2 * Copyright © 2012 Jonas Ådahl
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.
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.
27 #include <linux/input.h>
33 #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50
34 #define DEFAULT_MIN_ACCEL_FACTOR 0.16
35 #define DEFAULT_MAX_ACCEL_FACTOR 1.0
36 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
38 #define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
39 #define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
42 TOUCHPAD_MODEL_UNKNOWN = 0,
43 TOUCHPAD_MODEL_SYNAPTICS,
45 TOUCHPAD_MODEL_APPLETOUCH,
46 TOUCHPAD_MODEL_ELANTECH
50 TOUCHPAD_EVENT_NONE = 0,
51 TOUCHPAD_EVENT_ABSOLUTE_ANY = (1 << 0),
52 TOUCHPAD_EVENT_ABSOLUTE_X = (1 << 1),
53 TOUCHPAD_EVENT_ABSOLUTE_Y = (1 << 2),
54 TOUCHPAD_EVENT_REPORT = (1 << 3)
57 struct touchpad_model_spec {
60 enum touchpad_model model;
63 static struct touchpad_model_spec touchpad_spec_table[] = {
64 {0x0002, 0x0007, TOUCHPAD_MODEL_SYNAPTICS},
65 {0x0002, 0x0008, TOUCHPAD_MODEL_ALPS},
66 {0x05ac, 0x0000, TOUCHPAD_MODEL_APPLETOUCH},
67 {0x0002, 0x000e, TOUCHPAD_MODEL_ELANTECH},
68 {0x0000, 0x0000, TOUCHPAD_MODEL_UNKNOWN}
72 TOUCHPAD_STATE_NONE = 0,
73 TOUCHPAD_STATE_TOUCH = (1 << 0),
74 TOUCHPAD_STATE_MOVE = (1 << 1)
77 #define TOUCHPAD_HISTORY_LENGTH 4
79 struct touchpad_motion {
84 enum touchpad_fingers_state {
85 TOUCHPAD_FINGERS_ONE = (1 << 0),
86 TOUCHPAD_FINGERS_TWO = (1 << 1),
87 TOUCHPAD_FINGERS_THREE = (1 << 2)
105 struct touchpad_dispatch {
106 struct evdev_dispatch base;
107 struct evdev_device *device;
109 enum touchpad_model model;
112 int last_finger_state;
114 double constant_accel_factor;
115 double min_accel_factor;
116 double max_accel_factor;
118 unsigned int event_mask;
119 unsigned int event_mask_filter;
126 struct wl_array events;
127 enum fsm_state state;
128 struct wl_event_source *timer_source;
149 struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
151 unsigned int motion_count;
153 struct weston_motion_filter *filter;
156 static enum touchpad_model
157 get_touchpad_model(struct evdev_device *device)
162 if (ioctl(device->fd, EVIOCGID, &id) < 0)
163 return TOUCHPAD_MODEL_UNKNOWN;
165 for (i = 0; i < ARRAY_LENGTH(touchpad_spec_table); i++)
166 if (touchpad_spec_table[i].vendor == id.vendor &&
167 (!touchpad_spec_table[i].product ||
168 touchpad_spec_table[i].product == id.product))
169 return touchpad_spec_table[i].model;
171 return TOUCHPAD_MODEL_UNKNOWN;
175 configure_touchpad_pressure(struct touchpad_dispatch *touchpad,
176 int32_t pressure_min, int32_t pressure_max)
178 int32_t range = pressure_max - pressure_min + 1;
180 touchpad->has_pressure = 1;
182 /* Magic numbers from xf86-input-synaptics */
183 switch (touchpad->model) {
184 case TOUCHPAD_MODEL_ELANTECH:
185 touchpad->pressure.touch_low = pressure_min + 1;
186 touchpad->pressure.touch_high = pressure_min + 1;
189 touchpad->pressure.touch_low =
190 pressure_min + range * (25.0/256.0);
191 touchpad->pressure.touch_high =
192 pressure_min + range * (30.0/256.0);
197 touchpad_profile(struct weston_motion_filter *filter,
202 struct touchpad_dispatch *touchpad =
203 (struct touchpad_dispatch *) data;
207 accel_factor = velocity * touchpad->constant_accel_factor;
209 if (accel_factor > touchpad->max_accel_factor)
210 accel_factor = touchpad->max_accel_factor;
211 else if (accel_factor < touchpad->min_accel_factor)
212 accel_factor = touchpad->min_accel_factor;
217 static inline struct touchpad_motion *
218 motion_history_offset(struct touchpad_dispatch *touchpad, int offset)
221 (touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) %
222 TOUCHPAD_HISTORY_LENGTH;
224 return &touchpad->motion_history[offset_index];
228 estimate_delta(int x0, int x1, int x2, int x3)
230 return (x0 + x1 - x2 - x3) / 4;
234 hysteresis(int in, int center, int margin)
236 int diff = in - center;
237 if (abs(diff) <= margin)
241 return center + diff - margin;
242 else if (diff < -margin)
243 return center + diff + margin;
244 return center + diff;
248 touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy)
250 *dx = estimate_delta(motion_history_offset(touchpad, 0)->x,
251 motion_history_offset(touchpad, 1)->x,
252 motion_history_offset(touchpad, 2)->x,
253 motion_history_offset(touchpad, 3)->x);
254 *dy = estimate_delta(motion_history_offset(touchpad, 0)->y,
255 motion_history_offset(touchpad, 1)->y,
256 motion_history_offset(touchpad, 2)->y,
257 motion_history_offset(touchpad, 3)->y);
261 filter_motion(struct touchpad_dispatch *touchpad,
262 double *dx, double *dy, uint32_t time)
264 struct weston_motion_params motion;
269 weston_filter_dispatch(touchpad->filter, &motion, touchpad, time);
276 notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
278 notify_button(touchpad->device->seat, time,
279 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
280 WL_POINTER_BUTTON_STATE_PRESSED);
284 notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
286 notify_button(touchpad->device->seat, time,
287 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
288 WL_POINTER_BUTTON_STATE_RELEASED);
292 notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
294 notify_button_pressed(touchpad, time);
295 notify_button_released(touchpad, time);
299 process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
301 uint32_t timeout = UINT32_MAX;
302 enum fsm_event *pevent;
303 enum fsm_event event;
305 if (!touchpad->fsm.enable)
308 if (touchpad->fsm.events.size == 0)
311 wl_array_for_each(pevent, &touchpad->fsm.events) {
315 switch (touchpad->fsm.state) {
318 case FSM_EVENT_TOUCH:
319 touchpad->fsm.state = FSM_TOUCH;
327 case FSM_EVENT_RELEASE:
328 timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
329 touchpad->fsm.state = FSM_TAP;
332 touchpad->fsm.state = FSM_IDLE;
338 case FSM_EVENT_TIMEOUT:
339 notify_tap(touchpad, time);
340 touchpad->fsm.state = FSM_IDLE;
342 case FSM_EVENT_TOUCH:
343 notify_button_pressed(touchpad, time);
344 touchpad->fsm.state = FSM_TAP_2;
347 touchpad->fsm.state = FSM_IDLE;
353 case FSM_EVENT_MOTION:
354 touchpad->fsm.state = FSM_DRAG;
356 case FSM_EVENT_RELEASE:
357 notify_button_released(touchpad, time);
358 notify_tap(touchpad, time);
359 touchpad->fsm.state = FSM_IDLE;
362 touchpad->fsm.state = FSM_IDLE;
368 case FSM_EVENT_RELEASE:
369 notify_button_released(touchpad, time);
370 touchpad->fsm.state = FSM_IDLE;
373 touchpad->fsm.state = FSM_IDLE;
378 weston_log("evdev-touchpad: Unknown state %d",
379 touchpad->fsm.state);
380 touchpad->fsm.state = FSM_IDLE;
385 if (timeout != UINT32_MAX)
386 wl_event_source_timer_update(touchpad->fsm.timer_source,
389 wl_array_release(&touchpad->fsm.events);
390 wl_array_init(&touchpad->fsm.events);
394 push_fsm_event(struct touchpad_dispatch *touchpad,
395 enum fsm_event event)
397 enum fsm_event *pevent;
399 if (!touchpad->fsm.enable)
402 pevent = wl_array_add(&touchpad->fsm.events, sizeof event);
406 touchpad->fsm.state = FSM_IDLE;
410 fsm_timout_handler(void *data)
412 struct touchpad_dispatch *touchpad = data;
414 if (touchpad->fsm.events.size == 0) {
415 push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
416 process_fsm_events(touchpad, weston_compositor_get_time());
423 touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
426 int center_x, center_y;
427 double dx = 0.0, dy = 0.0;
429 if (touchpad->reset ||
430 touchpad->last_finger_state != touchpad->finger_state) {
432 touchpad->motion_count = 0;
433 touchpad->event_mask = TOUCHPAD_EVENT_NONE;
434 touchpad->event_mask_filter =
435 TOUCHPAD_EVENT_ABSOLUTE_X | TOUCHPAD_EVENT_ABSOLUTE_Y;
437 touchpad->last_finger_state = touchpad->finger_state;
439 process_fsm_events(touchpad, time);
443 touchpad->last_finger_state = touchpad->finger_state;
445 if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT))
448 touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT;
450 if ((touchpad->event_mask & touchpad->event_mask_filter) !=
451 touchpad->event_mask_filter)
454 touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY;
455 touchpad->event_mask = 0;
457 /* Avoid noice by moving center only when delta reaches a threshold
458 * distance from the old center. */
459 if (touchpad->motion_count > 0) {
460 center_x = hysteresis(touchpad->hw_abs.x,
461 touchpad->hysteresis.center_x,
462 touchpad->hysteresis.margin_x);
463 center_y = hysteresis(touchpad->hw_abs.y,
464 touchpad->hysteresis.center_y,
465 touchpad->hysteresis.margin_y);
467 center_x = touchpad->hw_abs.x;
468 center_y = touchpad->hw_abs.y;
470 touchpad->hysteresis.center_x = center_x;
471 touchpad->hysteresis.center_y = center_y;
472 touchpad->hw_abs.x = center_x;
473 touchpad->hw_abs.y = center_y;
475 /* Update motion history tracker */
476 motion_index = (touchpad->motion_index + 1) % TOUCHPAD_HISTORY_LENGTH;
477 touchpad->motion_index = motion_index;
478 touchpad->motion_history[motion_index].x = touchpad->hw_abs.x;
479 touchpad->motion_history[motion_index].y = touchpad->hw_abs.y;
480 if (touchpad->motion_count < 4)
481 touchpad->motion_count++;
483 if (touchpad->motion_count >= 4) {
484 touchpad_get_delta(touchpad, &dx, &dy);
486 filter_motion(touchpad, &dx, &dy, time);
488 if (touchpad->finger_state == TOUCHPAD_FINGERS_ONE) {
489 touchpad->device->rel.dx = wl_fixed_from_double(dx);
490 touchpad->device->rel.dy = wl_fixed_from_double(dy);
491 touchpad->device->pending_events |=
492 EVDEV_RELATIVE_MOTION | EVDEV_SYN;
493 } else if (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) {
495 notify_axis(touchpad->device->seat,
497 WL_POINTER_AXIS_HORIZONTAL_SCROLL,
498 wl_fixed_from_double(dx));
500 notify_axis(touchpad->device->seat,
502 WL_POINTER_AXIS_VERTICAL_SCROLL,
503 wl_fixed_from_double(dy));
507 if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
508 ((int)dx || (int)dy)) {
509 touchpad->state |= TOUCHPAD_STATE_MOVE;
510 push_fsm_event(touchpad, FSM_EVENT_MOTION);
513 process_fsm_events(touchpad, time);
517 on_touch(struct touchpad_dispatch *touchpad)
519 touchpad->state |= TOUCHPAD_STATE_TOUCH;
521 push_fsm_event(touchpad, FSM_EVENT_TOUCH);
525 on_release(struct touchpad_dispatch *touchpad)
529 touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
531 push_fsm_event(touchpad, FSM_EVENT_RELEASE);
535 process_absolute(struct touchpad_dispatch *touchpad,
536 struct evdev_device *device,
537 struct input_event *e)
541 if (e->value > touchpad->pressure.touch_high &&
542 !(touchpad->state & TOUCHPAD_STATE_TOUCH))
544 else if (e->value < touchpad->pressure.touch_low &&
545 touchpad->state & TOUCHPAD_STATE_TOUCH)
546 on_release(touchpad);
550 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
551 touchpad->hw_abs.x = e->value;
552 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
553 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X;
557 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
558 touchpad->hw_abs.y = e->value;
559 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
560 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y;
567 process_key(struct touchpad_dispatch *touchpad,
568 struct evdev_device *device,
569 struct input_event *e,
574 if (!touchpad->has_pressure) {
575 if (e->value && !(touchpad->state & TOUCHPAD_STATE_TOUCH))
578 on_release(touchpad);
589 notify_button(device->seat,
591 e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
592 WL_POINTER_BUTTON_STATE_RELEASED);
595 case BTN_TOOL_RUBBER:
597 case BTN_TOOL_PENCIL:
598 case BTN_TOOL_AIRBRUSH:
603 case BTN_TOOL_FINGER:
605 touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
607 touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
609 case BTN_TOOL_DOUBLETAP:
611 touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
613 touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
615 case BTN_TOOL_TRIPLETAP:
617 touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
619 touchpad->finger_state &= ~TOUCHPAD_FINGERS_THREE;
625 touchpad_process(struct evdev_dispatch *dispatch,
626 struct evdev_device *device,
627 struct input_event *e,
630 struct touchpad_dispatch *touchpad =
631 (struct touchpad_dispatch *) dispatch;
635 if (e->code == SYN_REPORT)
636 touchpad->event_mask |= TOUCHPAD_EVENT_REPORT;
639 process_absolute(touchpad, device, e);
642 process_key(touchpad, device, e, time);
646 touchpad_update_state(touchpad, time);
650 touchpad_destroy(struct evdev_dispatch *dispatch)
652 struct touchpad_dispatch *touchpad =
653 (struct touchpad_dispatch *) dispatch;
655 touchpad->filter->interface->destroy(touchpad->filter);
656 wl_event_source_remove(touchpad->fsm.timer_source);
660 struct evdev_dispatch_interface touchpad_interface = {
666 touchpad_init(struct touchpad_dispatch *touchpad,
667 struct evdev_device *device)
669 struct weston_motion_filter *accel;
670 struct wl_event_loop *loop;
672 unsigned long prop_bits[INPUT_PROP_MAX];
673 struct input_absinfo absinfo;
674 unsigned long abs_bits[NBITS(ABS_MAX)];
682 touchpad->base.interface = &touchpad_interface;
683 touchpad->device = device;
686 touchpad->model = get_touchpad_model(device);
688 ioctl(device->fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits);
689 has_buttonpad = TEST_BIT(prop_bits, INPUT_PROP_BUTTONPAD);
691 /* Configure pressure */
692 ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
693 if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
694 ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo);
695 configure_touchpad_pressure(touchpad,
700 /* Configure acceleration factor */
701 width = abs(device->abs.max_x - device->abs.min_x);
702 height = abs(device->abs.max_y - device->abs.min_y);
703 diagonal = sqrt(width*width + height*height);
705 touchpad->constant_accel_factor =
706 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
708 touchpad->min_accel_factor = DEFAULT_MIN_ACCEL_FACTOR;
709 touchpad->max_accel_factor = DEFAULT_MAX_ACCEL_FACTOR;
711 touchpad->hysteresis.margin_x =
712 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
713 touchpad->hysteresis.margin_y =
714 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
715 touchpad->hysteresis.center_x = 0;
716 touchpad->hysteresis.center_y = 0;
718 /* Configure acceleration profile */
719 accel = create_pointer_accelator_filter(touchpad_profile);
722 touchpad->filter = accel;
724 /* Setup initial state */
727 memset(touchpad->motion_history, 0, sizeof touchpad->motion_history);
728 touchpad->motion_index = 0;
729 touchpad->motion_count = 0;
731 touchpad->state = TOUCHPAD_STATE_NONE;
732 touchpad->last_finger_state = 0;
733 touchpad->finger_state = 0;
735 wl_array_init(&touchpad->fsm.events);
736 touchpad->fsm.state = FSM_IDLE;
738 loop = wl_display_get_event_loop(device->seat->compositor->wl_display);
739 touchpad->fsm.timer_source =
740 wl_event_loop_add_timer(loop, fsm_timout_handler, touchpad);
741 if (touchpad->fsm.timer_source == NULL) {
742 accel->interface->destroy(accel);
747 touchpad->fsm.enable = !has_buttonpad;
752 struct evdev_dispatch *
753 evdev_touchpad_create(struct evdev_device *device)
755 struct touchpad_dispatch *touchpad;
757 touchpad = malloc(sizeof *touchpad);
758 if (touchpad == NULL)
761 if (touchpad_init(touchpad, device) != 0) {
766 return &touchpad->base;