Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright © 2012 Jonas Ådahl |
| 3 | * |
| 4 | * Permission to use, copy, modify, distribute, and sell this software and |
| 5 | * its documentation for any purpose is hereby granted without fee, provided |
| 6 | * that the above copyright notice appear in all copies and that both that |
| 7 | * copyright notice and this permission notice appear in supporting |
| 8 | * documentation, and that the name of the copyright holders not be used in |
| 9 | * advertising or publicity pertaining to distribution of the software |
| 10 | * without specific, written prior permission. The copyright holders make |
| 11 | * no representations about the suitability of this software for any |
| 12 | * purpose. It is provided "as is" without express or implied warranty. |
| 13 | * |
| 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
| 15 | * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| 16 | * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| 17 | * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER |
| 18 | * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF |
| 19 | * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 20 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 21 | */ |
| 22 | |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 23 | #include <stdlib.h> |
| 24 | #include <math.h> |
| 25 | #include <string.h> |
| 26 | #include <linux/input.h> |
| 27 | |
| 28 | #include "filter.h" |
Pekka Paalanen | cfa1f67 | 2012-08-03 14:38:59 +0300 | [diff] [blame] | 29 | #include "evdev.h" |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 30 | |
| 31 | /* Default values */ |
| 32 | #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50 |
| 33 | #define DEFAULT_MIN_ACCEL_FACTOR 0.16 |
| 34 | #define DEFAULT_MAX_ACCEL_FACTOR 1.0 |
| 35 | #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0 |
| 36 | |
| 37 | enum touchpad_model { |
| 38 | TOUCHPAD_MODEL_UNKNOWN = 0, |
| 39 | TOUCHPAD_MODEL_SYNAPTICS, |
| 40 | TOUCHPAD_MODEL_ALPS, |
| 41 | TOUCHPAD_MODEL_APPLETOUCH, |
| 42 | TOUCHPAD_MODEL_ELANTECH |
| 43 | }; |
| 44 | |
| 45 | #define TOUCHPAD_EVENT_NONE 0 |
| 46 | #define TOUCHPAD_EVENT_ABSOLUTE_ANY (1 << 0) |
| 47 | #define TOUCHPAD_EVENT_ABSOLUTE_X (1 << 1) |
| 48 | #define TOUCHPAD_EVENT_ABSOLUTE_Y (1 << 2) |
| 49 | #define TOUCHPAD_EVENT_REPORT (1 << 3) |
| 50 | |
| 51 | struct touchpad_model_spec { |
| 52 | short vendor; |
| 53 | short product; |
| 54 | enum touchpad_model model; |
| 55 | }; |
| 56 | |
| 57 | static struct touchpad_model_spec touchpad_spec_table[] = { |
| 58 | {0x0002, 0x0007, TOUCHPAD_MODEL_SYNAPTICS}, |
| 59 | {0x0002, 0x0008, TOUCHPAD_MODEL_ALPS}, |
| 60 | {0x05ac, 0x0000, TOUCHPAD_MODEL_APPLETOUCH}, |
| 61 | {0x0002, 0x000e, TOUCHPAD_MODEL_ELANTECH}, |
| 62 | {0x0000, 0x0000, TOUCHPAD_MODEL_UNKNOWN} |
| 63 | }; |
| 64 | |
| 65 | enum touchpad_state { |
| 66 | TOUCHPAD_STATE_NONE = 0, |
| 67 | TOUCHPAD_STATE_TOUCH, |
| 68 | TOUCHPAD_STATE_PRESS |
| 69 | }; |
| 70 | |
| 71 | #define TOUCHPAD_HISTORY_LENGTH 4 |
| 72 | |
| 73 | struct touchpad_motion { |
| 74 | int32_t x; |
| 75 | int32_t y; |
| 76 | }; |
| 77 | |
| 78 | enum touchpad_fingers_state { |
| 79 | TOUCHPAD_FINGERS_ONE = (1 << 0), |
| 80 | TOUCHPAD_FINGERS_TWO = (1 << 1), |
| 81 | TOUCHPAD_FINGERS_THREE = (1 << 2) |
| 82 | }; |
| 83 | |
| 84 | struct touchpad_dispatch { |
| 85 | struct evdev_dispatch base; |
Pekka Paalanen | 3eb4761 | 2012-08-06 14:57:08 +0300 | [diff] [blame] | 86 | struct evdev_device *device; |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 87 | |
| 88 | enum touchpad_model model; |
| 89 | enum touchpad_state state; |
| 90 | int finger_state; |
| 91 | int last_finger_state; |
| 92 | |
| 93 | double constant_accel_factor; |
| 94 | double min_accel_factor; |
| 95 | double max_accel_factor; |
| 96 | |
| 97 | unsigned int event_mask; |
| 98 | unsigned int event_mask_filter; |
| 99 | |
| 100 | int reset; |
| 101 | |
| 102 | struct { |
| 103 | int32_t x; |
| 104 | int32_t y; |
| 105 | } hw_abs; |
| 106 | |
| 107 | int has_pressure; |
| 108 | struct { |
| 109 | int32_t touch_low; |
| 110 | int32_t touch_high; |
| 111 | int32_t press; |
| 112 | } pressure; |
| 113 | |
| 114 | struct { |
| 115 | int32_t margin_x; |
| 116 | int32_t margin_y; |
| 117 | int32_t center_x; |
| 118 | int32_t center_y; |
| 119 | } hysteresis; |
| 120 | |
| 121 | struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH]; |
| 122 | int motion_index; |
| 123 | unsigned int motion_count; |
| 124 | |
| 125 | struct wl_list motion_filters; |
| 126 | }; |
| 127 | |
| 128 | static enum touchpad_model |
Pekka Paalanen | 3eb4761 | 2012-08-06 14:57:08 +0300 | [diff] [blame] | 129 | get_touchpad_model(struct evdev_device *device) |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 130 | { |
| 131 | struct input_id id; |
| 132 | unsigned int i; |
| 133 | |
| 134 | if (ioctl(device->fd, EVIOCGID, &id) < 0) |
| 135 | return TOUCHPAD_MODEL_UNKNOWN; |
| 136 | |
| 137 | for (i = 0; i < sizeof touchpad_spec_table; i++) |
| 138 | if (touchpad_spec_table[i].vendor == id.vendor && |
| 139 | (!touchpad_spec_table[i].product || |
| 140 | touchpad_spec_table[i].product == id.product)) |
| 141 | return touchpad_spec_table[i].model; |
| 142 | |
| 143 | return TOUCHPAD_MODEL_UNKNOWN; |
| 144 | } |
| 145 | |
| 146 | static void |
| 147 | configure_touchpad_pressure(struct touchpad_dispatch *touchpad, |
| 148 | int32_t pressure_min, int32_t pressure_max) |
| 149 | { |
| 150 | int32_t range = pressure_max - pressure_min + 1; |
| 151 | |
| 152 | touchpad->has_pressure = 1; |
| 153 | |
| 154 | /* Magic numbers from xf86-input-synaptics */ |
| 155 | switch (touchpad->model) { |
| 156 | case TOUCHPAD_MODEL_ELANTECH: |
| 157 | touchpad->pressure.touch_low = pressure_min + 1; |
| 158 | touchpad->pressure.touch_high = pressure_min + 1; |
| 159 | break; |
| 160 | default: |
| 161 | touchpad->pressure.touch_low = |
| 162 | pressure_min + range * (25.0/256.0); |
| 163 | touchpad->pressure.touch_high = |
| 164 | pressure_min + range * (30.0/256.0); |
| 165 | } |
| 166 | |
| 167 | touchpad->pressure.press = pressure_min + range; |
| 168 | } |
| 169 | |
| 170 | static double |
| 171 | touchpad_profile(struct weston_motion_filter *filter, |
| 172 | void *data, |
| 173 | double velocity, |
| 174 | uint32_t time) |
| 175 | { |
| 176 | struct touchpad_dispatch *touchpad = |
| 177 | (struct touchpad_dispatch *) data; |
| 178 | |
| 179 | double accel_factor; |
| 180 | |
| 181 | accel_factor = velocity * touchpad->constant_accel_factor; |
| 182 | |
| 183 | if (accel_factor > touchpad->max_accel_factor) |
| 184 | accel_factor = touchpad->max_accel_factor; |
| 185 | else if (accel_factor < touchpad->min_accel_factor) |
| 186 | accel_factor = touchpad->min_accel_factor; |
| 187 | |
| 188 | return accel_factor; |
| 189 | } |
| 190 | |
| 191 | static void |
| 192 | configure_touchpad(struct touchpad_dispatch *touchpad, |
Pekka Paalanen | 3eb4761 | 2012-08-06 14:57:08 +0300 | [diff] [blame] | 193 | struct evdev_device *device) |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 194 | { |
| 195 | struct weston_motion_filter *accel; |
| 196 | |
| 197 | struct input_absinfo absinfo; |
| 198 | unsigned long abs_bits[NBITS(ABS_MAX)]; |
| 199 | |
| 200 | double width; |
| 201 | double height; |
| 202 | double diagonal; |
| 203 | |
| 204 | /* Detect model */ |
| 205 | touchpad->model = get_touchpad_model(device); |
| 206 | |
| 207 | /* Configure pressure */ |
| 208 | ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits); |
| 209 | if (TEST_BIT(abs_bits, ABS_PRESSURE)) { |
| 210 | ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo); |
| 211 | configure_touchpad_pressure(touchpad, |
| 212 | absinfo.minimum, |
| 213 | absinfo.maximum); |
| 214 | } |
| 215 | |
| 216 | /* Configure acceleration factor */ |
| 217 | width = abs(device->abs.max_x - device->abs.min_x); |
| 218 | height = abs(device->abs.max_y - device->abs.min_y); |
| 219 | diagonal = sqrt(width*width + height*height); |
| 220 | |
| 221 | touchpad->constant_accel_factor = |
| 222 | DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal; |
| 223 | |
| 224 | touchpad->min_accel_factor = DEFAULT_MIN_ACCEL_FACTOR; |
| 225 | touchpad->max_accel_factor = DEFAULT_MAX_ACCEL_FACTOR; |
| 226 | |
| 227 | touchpad->hysteresis.margin_x = |
| 228 | diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; |
| 229 | touchpad->hysteresis.margin_y = |
| 230 | diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR; |
| 231 | touchpad->hysteresis.center_x = 0; |
| 232 | touchpad->hysteresis.center_y = 0; |
| 233 | |
| 234 | /* Configure acceleration profile */ |
| 235 | accel = create_pointer_accelator_filter(touchpad_profile); |
| 236 | wl_list_insert(&touchpad->motion_filters, &accel->link); |
| 237 | |
| 238 | /* Setup initial state */ |
| 239 | touchpad->reset = 1; |
| 240 | |
| 241 | memset(touchpad->motion_history, 0, sizeof touchpad->motion_history); |
| 242 | touchpad->motion_index = 0; |
| 243 | touchpad->motion_count = 0; |
| 244 | |
| 245 | touchpad->state = TOUCHPAD_STATE_NONE; |
| 246 | touchpad->last_finger_state = 0; |
| 247 | touchpad->finger_state = 0; |
| 248 | } |
| 249 | |
| 250 | static inline struct touchpad_motion * |
| 251 | motion_history_offset(struct touchpad_dispatch *touchpad, int offset) |
| 252 | { |
| 253 | int offset_index = |
| 254 | (touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) % |
| 255 | TOUCHPAD_HISTORY_LENGTH; |
| 256 | |
| 257 | return &touchpad->motion_history[offset_index]; |
| 258 | } |
| 259 | |
| 260 | static double |
| 261 | estimate_delta(int x0, int x1, int x2, int x3) |
| 262 | { |
| 263 | return (x0 + x1 - x2 - x3) / 4; |
| 264 | } |
| 265 | |
| 266 | static int |
| 267 | hysteresis(int in, int center, int margin) |
| 268 | { |
| 269 | int diff = in - center; |
| 270 | if (abs(diff) <= margin) |
| 271 | return center; |
| 272 | |
| 273 | if (diff > margin) |
| 274 | return center + diff - margin; |
| 275 | else if (diff < -margin) |
| 276 | return center + diff + margin; |
| 277 | return center + diff; |
| 278 | } |
| 279 | |
| 280 | static void |
| 281 | touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy) |
| 282 | { |
| 283 | *dx = estimate_delta(motion_history_offset(touchpad, 0)->x, |
| 284 | motion_history_offset(touchpad, 1)->x, |
| 285 | motion_history_offset(touchpad, 2)->x, |
| 286 | motion_history_offset(touchpad, 3)->x); |
| 287 | *dy = estimate_delta(motion_history_offset(touchpad, 0)->y, |
| 288 | motion_history_offset(touchpad, 1)->y, |
| 289 | motion_history_offset(touchpad, 2)->y, |
| 290 | motion_history_offset(touchpad, 3)->y); |
| 291 | } |
| 292 | |
| 293 | static void |
| 294 | filter_motion(struct touchpad_dispatch *touchpad, |
| 295 | double *dx, double *dy, uint32_t time) |
| 296 | { |
| 297 | struct weston_motion_filter *filter; |
| 298 | struct weston_motion_params motion; |
| 299 | |
| 300 | motion.dx = *dx; |
| 301 | motion.dy = *dy; |
| 302 | |
| 303 | wl_list_for_each(filter, &touchpad->motion_filters, link) |
| 304 | weston_filter_dispatch(filter, &motion, touchpad, time); |
| 305 | |
| 306 | *dx = motion.dx; |
| 307 | *dy = motion.dy; |
| 308 | } |
| 309 | |
| 310 | static void |
| 311 | touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time) |
| 312 | { |
| 313 | int motion_index; |
| 314 | int center_x, center_y; |
| 315 | double dx, dy; |
| 316 | |
| 317 | if (touchpad->reset || |
| 318 | touchpad->last_finger_state != touchpad->finger_state) { |
| 319 | touchpad->reset = 0; |
| 320 | touchpad->motion_count = 0; |
| 321 | touchpad->event_mask = TOUCHPAD_EVENT_NONE; |
| 322 | touchpad->event_mask_filter = |
| 323 | TOUCHPAD_EVENT_ABSOLUTE_X | TOUCHPAD_EVENT_ABSOLUTE_Y; |
| 324 | |
| 325 | touchpad->last_finger_state = touchpad->finger_state; |
| 326 | |
| 327 | return; |
| 328 | } |
| 329 | touchpad->last_finger_state = touchpad->finger_state; |
| 330 | |
| 331 | if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT)) |
| 332 | return; |
| 333 | else |
| 334 | touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT; |
| 335 | |
| 336 | if ((touchpad->event_mask & touchpad->event_mask_filter) != |
| 337 | touchpad->event_mask_filter) |
| 338 | return; |
| 339 | |
| 340 | touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY; |
| 341 | touchpad->event_mask = 0; |
| 342 | |
| 343 | /* Avoid noice by moving center only when delta reaches a threshold |
| 344 | * distance from the old center. */ |
| 345 | if (touchpad->motion_count > 0) { |
| 346 | center_x = hysteresis(touchpad->hw_abs.x, |
| 347 | touchpad->hysteresis.center_x, |
| 348 | touchpad->hysteresis.margin_x); |
| 349 | center_y = hysteresis(touchpad->hw_abs.y, |
| 350 | touchpad->hysteresis.center_y, |
| 351 | touchpad->hysteresis.margin_y); |
| 352 | } |
| 353 | else { |
| 354 | center_x = touchpad->hw_abs.x; |
| 355 | center_y = touchpad->hw_abs.y; |
| 356 | } |
| 357 | touchpad->hysteresis.center_x = center_x; |
| 358 | touchpad->hysteresis.center_y = center_y; |
| 359 | touchpad->hw_abs.x = center_x; |
| 360 | touchpad->hw_abs.y = center_y; |
| 361 | |
| 362 | /* Update motion history tracker */ |
| 363 | motion_index = (touchpad->motion_index + 1) % TOUCHPAD_HISTORY_LENGTH; |
| 364 | touchpad->motion_index = motion_index; |
| 365 | touchpad->motion_history[motion_index].x = touchpad->hw_abs.x; |
| 366 | touchpad->motion_history[motion_index].y = touchpad->hw_abs.y; |
| 367 | if (touchpad->motion_count < 4) |
| 368 | touchpad->motion_count++; |
| 369 | |
| 370 | if (touchpad->motion_count >= 4) { |
| 371 | touchpad_get_delta(touchpad, &dx, &dy); |
| 372 | |
| 373 | filter_motion(touchpad, &dx, &dy, time); |
| 374 | |
| 375 | touchpad->device->rel.dx = wl_fixed_from_double(dx); |
| 376 | touchpad->device->rel.dy = wl_fixed_from_double(dy); |
Daniel Stone | 1d63777 | 2012-05-30 16:31:47 +0100 | [diff] [blame] | 377 | touchpad->device->pending_events |= EVDEV_RELATIVE_MOTION; |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 378 | } |
| 379 | } |
| 380 | |
| 381 | static inline void |
| 382 | process_absolute(struct touchpad_dispatch *touchpad, |
Pekka Paalanen | 3eb4761 | 2012-08-06 14:57:08 +0300 | [diff] [blame] | 383 | struct evdev_device *device, |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 384 | struct input_event *e) |
| 385 | { |
| 386 | switch (e->code) { |
| 387 | case ABS_PRESSURE: |
| 388 | if (e->value > touchpad->pressure.press) |
| 389 | touchpad->state = TOUCHPAD_STATE_PRESS; |
| 390 | else if (e->value > touchpad->pressure.touch_high) |
| 391 | touchpad->state = TOUCHPAD_STATE_TOUCH; |
| 392 | else if (e->value < touchpad->pressure.touch_low) { |
| 393 | if (touchpad->state > TOUCHPAD_STATE_NONE) |
| 394 | touchpad->reset = 1; |
| 395 | |
| 396 | touchpad->state = TOUCHPAD_STATE_NONE; |
| 397 | } |
| 398 | |
| 399 | break; |
| 400 | case ABS_X: |
| 401 | if (touchpad->state >= TOUCHPAD_STATE_TOUCH) { |
| 402 | touchpad->hw_abs.x = e->value; |
| 403 | touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY; |
| 404 | touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X; |
| 405 | } |
| 406 | break; |
| 407 | case ABS_Y: |
| 408 | if (touchpad->state >= TOUCHPAD_STATE_TOUCH) { |
| 409 | touchpad->hw_abs.y = e->value; |
| 410 | touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY; |
| 411 | touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y; |
| 412 | } |
| 413 | break; |
| 414 | } |
| 415 | } |
| 416 | |
| 417 | static inline void |
| 418 | process_key(struct touchpad_dispatch *touchpad, |
Pekka Paalanen | 3eb4761 | 2012-08-06 14:57:08 +0300 | [diff] [blame] | 419 | struct evdev_device *device, |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 420 | struct input_event *e, |
| 421 | uint32_t time) |
| 422 | { |
| 423 | switch (e->code) { |
| 424 | case BTN_TOUCH: |
| 425 | if (!touchpad->has_pressure) { |
| 426 | if (!e->value) { |
| 427 | touchpad->state = TOUCHPAD_STATE_NONE; |
| 428 | touchpad->reset = 1; |
| 429 | } else { |
| 430 | touchpad->state = |
| 431 | e->value ? |
| 432 | TOUCHPAD_STATE_TOUCH : |
| 433 | TOUCHPAD_STATE_NONE; |
| 434 | } |
| 435 | } |
| 436 | break; |
| 437 | case BTN_LEFT: |
| 438 | case BTN_RIGHT: |
| 439 | case BTN_MIDDLE: |
| 440 | case BTN_SIDE: |
| 441 | case BTN_EXTRA: |
| 442 | case BTN_FORWARD: |
| 443 | case BTN_BACK: |
| 444 | case BTN_TASK: |
Kristian Høgsberg | cb3eaae | 2012-08-10 09:50:11 -0400 | [diff] [blame^] | 445 | notify_button(device->seat, |
Daniel Stone | 4dbadb1 | 2012-05-30 16:31:51 +0100 | [diff] [blame] | 446 | time, e->code, |
| 447 | e->value ? WL_POINTER_BUTTON_STATE_PRESSED : |
| 448 | WL_POINTER_BUTTON_STATE_RELEASED); |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 449 | break; |
| 450 | case BTN_TOOL_PEN: |
| 451 | case BTN_TOOL_RUBBER: |
| 452 | case BTN_TOOL_BRUSH: |
| 453 | case BTN_TOOL_PENCIL: |
| 454 | case BTN_TOOL_AIRBRUSH: |
| 455 | case BTN_TOOL_MOUSE: |
| 456 | case BTN_TOOL_LENS: |
| 457 | touchpad->reset = 1; |
| 458 | break; |
| 459 | case BTN_TOOL_FINGER: |
| 460 | touchpad->finger_state = |
| 461 | ~TOUCHPAD_FINGERS_ONE | e->value ? |
| 462 | TOUCHPAD_FINGERS_ONE : 0; |
| 463 | break; |
| 464 | case BTN_TOOL_DOUBLETAP: |
| 465 | touchpad->finger_state = |
| 466 | ~TOUCHPAD_FINGERS_TWO | e->value ? |
| 467 | TOUCHPAD_FINGERS_TWO : 0; |
| 468 | break; |
| 469 | case BTN_TOOL_TRIPLETAP: |
| 470 | touchpad->finger_state = |
| 471 | ~TOUCHPAD_FINGERS_THREE | e->value ? |
| 472 | TOUCHPAD_FINGERS_THREE : 0; |
| 473 | break; |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | static void |
| 478 | touchpad_process(struct evdev_dispatch *dispatch, |
Pekka Paalanen | 3eb4761 | 2012-08-06 14:57:08 +0300 | [diff] [blame] | 479 | struct evdev_device *device, |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 480 | struct input_event *e, |
| 481 | uint32_t time) |
| 482 | { |
| 483 | struct touchpad_dispatch *touchpad = |
| 484 | (struct touchpad_dispatch *) dispatch; |
| 485 | |
| 486 | switch (e->type) { |
| 487 | case EV_SYN: |
| 488 | if (e->code == SYN_REPORT) |
| 489 | touchpad->event_mask |= TOUCHPAD_EVENT_REPORT; |
| 490 | break; |
| 491 | case EV_ABS: |
| 492 | process_absolute(touchpad, device, e); |
| 493 | break; |
| 494 | case EV_KEY: |
| 495 | process_key(touchpad, device, e, time); |
| 496 | break; |
| 497 | } |
| 498 | |
| 499 | touchpad_update_state(touchpad, time); |
| 500 | } |
| 501 | |
| 502 | static void |
| 503 | touchpad_destroy(struct evdev_dispatch *dispatch) |
| 504 | { |
| 505 | struct touchpad_dispatch *touchpad = |
| 506 | (struct touchpad_dispatch *) dispatch; |
| 507 | struct weston_motion_filter *filter; |
| 508 | struct weston_motion_filter *next; |
| 509 | |
| 510 | wl_list_for_each_safe(filter, next, &touchpad->motion_filters, link) |
| 511 | filter->interface->destroy(filter); |
| 512 | |
| 513 | free(dispatch); |
| 514 | } |
| 515 | |
| 516 | struct evdev_dispatch_interface touchpad_interface = { |
| 517 | touchpad_process, |
| 518 | touchpad_destroy |
| 519 | }; |
| 520 | |
| 521 | struct evdev_dispatch * |
Pekka Paalanen | 3eb4761 | 2012-08-06 14:57:08 +0300 | [diff] [blame] | 522 | evdev_touchpad_create(struct evdev_device *device) |
Jonas Ådahl | 1df17af | 2012-05-17 12:18:17 +0200 | [diff] [blame] | 523 | { |
| 524 | struct touchpad_dispatch *touchpad; |
| 525 | |
| 526 | touchpad = malloc(sizeof *touchpad); |
| 527 | if (touchpad == NULL) |
| 528 | return NULL; |
| 529 | |
| 530 | touchpad->base.interface = &touchpad_interface; |
| 531 | |
| 532 | touchpad->device = device; |
| 533 | wl_list_init(&touchpad->motion_filters); |
| 534 | |
| 535 | configure_touchpad(touchpad, device); |
| 536 | |
| 537 | return &touchpad->base; |
| 538 | } |