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.
29 #include <linux/input.h>
35 #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50
36 #define DEFAULT_MIN_ACCEL_FACTOR 0.16
37 #define DEFAULT_MAX_ACCEL_FACTOR 1.0
38 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
40 #define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
41 #define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
44 TOUCHPAD_MODEL_UNKNOWN = 0,
45 TOUCHPAD_MODEL_SYNAPTICS,
47 TOUCHPAD_MODEL_APPLETOUCH,
48 TOUCHPAD_MODEL_ELANTECH
52 TOUCHPAD_EVENT_NONE = 0,
53 TOUCHPAD_EVENT_ABSOLUTE_ANY = (1 << 0),
54 TOUCHPAD_EVENT_ABSOLUTE_X = (1 << 1),
55 TOUCHPAD_EVENT_ABSOLUTE_Y = (1 << 2),
56 TOUCHPAD_EVENT_REPORT = (1 << 3)
59 struct touchpad_model_spec {
62 enum touchpad_model model;
65 static struct touchpad_model_spec touchpad_spec_table[] = {
66 {0x0002, 0x0007, TOUCHPAD_MODEL_SYNAPTICS},
67 {0x0002, 0x0008, TOUCHPAD_MODEL_ALPS},
68 {0x05ac, 0x0000, TOUCHPAD_MODEL_APPLETOUCH},
69 {0x0002, 0x000e, TOUCHPAD_MODEL_ELANTECH},
70 {0x0000, 0x0000, TOUCHPAD_MODEL_UNKNOWN}
74 TOUCHPAD_STATE_NONE = 0,
75 TOUCHPAD_STATE_TOUCH = (1 << 0),
76 TOUCHPAD_STATE_MOVE = (1 << 1)
79 #define TOUCHPAD_HISTORY_LENGTH 4
81 struct touchpad_motion {
86 enum touchpad_fingers_state {
87 TOUCHPAD_FINGERS_ONE = (1 << 0),
88 TOUCHPAD_FINGERS_TWO = (1 << 1),
89 TOUCHPAD_FINGERS_THREE = (1 << 2)
107 struct touchpad_dispatch {
108 struct evdev_dispatch base;
109 struct evdev_device *device;
111 enum touchpad_model model;
114 int last_finger_state;
116 double constant_accel_factor;
117 double min_accel_factor;
118 double max_accel_factor;
120 unsigned int event_mask;
121 unsigned int event_mask_filter;
128 struct wl_array events;
129 enum fsm_state state;
130 struct wl_event_source *timer_source;
151 struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
153 unsigned int motion_count;
155 struct weston_motion_filter *filter;
158 static enum touchpad_model
159 get_touchpad_model(struct evdev_device *device)
164 if (ioctl(device->fd, EVIOCGID, &id) < 0)
165 return TOUCHPAD_MODEL_UNKNOWN;
167 for (i = 0; i < ARRAY_LENGTH(touchpad_spec_table); i++)
168 if (touchpad_spec_table[i].vendor == id.vendor &&
169 (!touchpad_spec_table[i].product ||
170 touchpad_spec_table[i].product == id.product))
171 return touchpad_spec_table[i].model;
173 return TOUCHPAD_MODEL_UNKNOWN;
177 configure_touchpad_pressure(struct touchpad_dispatch *touchpad,
178 int32_t pressure_min, int32_t pressure_max)
180 int32_t range = pressure_max - pressure_min + 1;
182 touchpad->has_pressure = 1;
184 /* Magic numbers from xf86-input-synaptics */
185 switch (touchpad->model) {
186 case TOUCHPAD_MODEL_ELANTECH:
187 touchpad->pressure.touch_low = pressure_min + 1;
188 touchpad->pressure.touch_high = pressure_min + 1;
191 touchpad->pressure.touch_low =
192 pressure_min + range * (25.0/256.0);
193 touchpad->pressure.touch_high =
194 pressure_min + range * (30.0/256.0);
199 touchpad_profile(struct weston_motion_filter *filter,
204 struct touchpad_dispatch *touchpad =
205 (struct touchpad_dispatch *) data;
209 accel_factor = velocity * touchpad->constant_accel_factor;
211 if (accel_factor > touchpad->max_accel_factor)
212 accel_factor = touchpad->max_accel_factor;
213 else if (accel_factor < touchpad->min_accel_factor)
214 accel_factor = touchpad->min_accel_factor;
219 static inline struct touchpad_motion *
220 motion_history_offset(struct touchpad_dispatch *touchpad, int offset)
223 (touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) %
224 TOUCHPAD_HISTORY_LENGTH;
226 return &touchpad->motion_history[offset_index];
230 estimate_delta(int x0, int x1, int x2, int x3)
232 return (x0 + x1 - x2 - x3) / 4;
236 hysteresis(int in, int center, int margin)
238 int diff = in - center;
239 if (abs(diff) <= margin)
243 return center + diff - margin;
244 else if (diff < -margin)
245 return center + diff + margin;
246 return center + diff;
250 touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy)
252 *dx = estimate_delta(motion_history_offset(touchpad, 0)->x,
253 motion_history_offset(touchpad, 1)->x,
254 motion_history_offset(touchpad, 2)->x,
255 motion_history_offset(touchpad, 3)->x);
256 *dy = estimate_delta(motion_history_offset(touchpad, 0)->y,
257 motion_history_offset(touchpad, 1)->y,
258 motion_history_offset(touchpad, 2)->y,
259 motion_history_offset(touchpad, 3)->y);
263 filter_motion(struct touchpad_dispatch *touchpad,
264 double *dx, double *dy, uint32_t time)
266 struct weston_motion_params motion;
271 weston_filter_dispatch(touchpad->filter, &motion, touchpad, time);
278 notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
280 notify_button(touchpad->device->seat, time,
281 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
282 WL_POINTER_BUTTON_STATE_PRESSED);
286 notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
288 notify_button(touchpad->device->seat, time,
289 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
290 WL_POINTER_BUTTON_STATE_RELEASED);
294 notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
296 notify_button_pressed(touchpad, time);
297 notify_button_released(touchpad, time);
301 process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
303 uint32_t timeout = UINT32_MAX;
304 enum fsm_event *pevent;
305 enum fsm_event event;
307 if (!touchpad->fsm.enable)
310 if (touchpad->fsm.events.size == 0)
313 wl_array_for_each(pevent, &touchpad->fsm.events) {
317 switch (touchpad->fsm.state) {
320 case FSM_EVENT_TOUCH:
321 touchpad->fsm.state = FSM_TOUCH;
329 case FSM_EVENT_RELEASE:
330 timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
331 touchpad->fsm.state = FSM_TAP;
334 touchpad->fsm.state = FSM_IDLE;
340 case FSM_EVENT_TIMEOUT:
341 notify_tap(touchpad, time);
342 touchpad->fsm.state = FSM_IDLE;
344 case FSM_EVENT_TOUCH:
345 notify_button_pressed(touchpad, time);
346 touchpad->fsm.state = FSM_TAP_2;
349 touchpad->fsm.state = FSM_IDLE;
355 case FSM_EVENT_MOTION:
356 touchpad->fsm.state = FSM_DRAG;
358 case FSM_EVENT_RELEASE:
359 notify_button_released(touchpad, time);
360 notify_tap(touchpad, time);
361 touchpad->fsm.state = FSM_IDLE;
364 touchpad->fsm.state = FSM_IDLE;
370 case FSM_EVENT_RELEASE:
371 notify_button_released(touchpad, time);
372 touchpad->fsm.state = FSM_IDLE;
375 touchpad->fsm.state = FSM_IDLE;
380 weston_log("evdev-touchpad: Unknown state %d",
381 touchpad->fsm.state);
382 touchpad->fsm.state = FSM_IDLE;
387 if (timeout != UINT32_MAX)
388 wl_event_source_timer_update(touchpad->fsm.timer_source,
391 wl_array_release(&touchpad->fsm.events);
392 wl_array_init(&touchpad->fsm.events);
396 push_fsm_event(struct touchpad_dispatch *touchpad,
397 enum fsm_event event)
399 enum fsm_event *pevent;
401 if (!touchpad->fsm.enable)
404 pevent = wl_array_add(&touchpad->fsm.events, sizeof event);
408 touchpad->fsm.state = FSM_IDLE;
412 fsm_timout_handler(void *data)
414 struct touchpad_dispatch *touchpad = data;
416 if (touchpad->fsm.events.size == 0) {
417 push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
418 process_fsm_events(touchpad, weston_compositor_get_time());
425 touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
428 int center_x, center_y;
429 double dx = 0.0, dy = 0.0;
431 if (touchpad->reset ||
432 touchpad->last_finger_state != touchpad->finger_state) {
434 touchpad->motion_count = 0;
435 touchpad->event_mask = TOUCHPAD_EVENT_NONE;
436 touchpad->event_mask_filter =
437 TOUCHPAD_EVENT_ABSOLUTE_X | TOUCHPAD_EVENT_ABSOLUTE_Y;
439 touchpad->last_finger_state = touchpad->finger_state;
441 process_fsm_events(touchpad, time);
445 touchpad->last_finger_state = touchpad->finger_state;
447 if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT))
450 touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT;
452 if ((touchpad->event_mask & touchpad->event_mask_filter) !=
453 touchpad->event_mask_filter)
456 touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY;
457 touchpad->event_mask = 0;
459 /* Avoid noice by moving center only when delta reaches a threshold
460 * distance from the old center. */
461 if (touchpad->motion_count > 0) {
462 center_x = hysteresis(touchpad->hw_abs.x,
463 touchpad->hysteresis.center_x,
464 touchpad->hysteresis.margin_x);
465 center_y = hysteresis(touchpad->hw_abs.y,
466 touchpad->hysteresis.center_y,
467 touchpad->hysteresis.margin_y);
469 center_x = touchpad->hw_abs.x;
470 center_y = touchpad->hw_abs.y;
472 touchpad->hysteresis.center_x = center_x;
473 touchpad->hysteresis.center_y = center_y;
474 touchpad->hw_abs.x = center_x;
475 touchpad->hw_abs.y = center_y;
477 /* Update motion history tracker */
478 motion_index = (touchpad->motion_index + 1) % TOUCHPAD_HISTORY_LENGTH;
479 touchpad->motion_index = motion_index;
480 touchpad->motion_history[motion_index].x = touchpad->hw_abs.x;
481 touchpad->motion_history[motion_index].y = touchpad->hw_abs.y;
482 if (touchpad->motion_count < 4)
483 touchpad->motion_count++;
485 if (touchpad->motion_count >= 4) {
486 touchpad_get_delta(touchpad, &dx, &dy);
488 filter_motion(touchpad, &dx, &dy, time);
490 if (touchpad->finger_state == TOUCHPAD_FINGERS_ONE) {
491 touchpad->device->rel.dx = wl_fixed_from_double(dx);
492 touchpad->device->rel.dy = wl_fixed_from_double(dy);
493 touchpad->device->pending_events |=
494 EVDEV_RELATIVE_MOTION | EVDEV_SYN;
495 } else if (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) {
497 notify_axis(touchpad->device->seat,
499 WL_POINTER_AXIS_HORIZONTAL_SCROLL,
500 wl_fixed_from_double(dx));
502 notify_axis(touchpad->device->seat,
504 WL_POINTER_AXIS_VERTICAL_SCROLL,
505 wl_fixed_from_double(dy));
509 if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
510 ((int)dx || (int)dy)) {
511 touchpad->state |= TOUCHPAD_STATE_MOVE;
512 push_fsm_event(touchpad, FSM_EVENT_MOTION);
515 process_fsm_events(touchpad, time);
519 on_touch(struct touchpad_dispatch *touchpad)
521 touchpad->state |= TOUCHPAD_STATE_TOUCH;
523 push_fsm_event(touchpad, FSM_EVENT_TOUCH);
527 on_release(struct touchpad_dispatch *touchpad)
531 touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
533 push_fsm_event(touchpad, FSM_EVENT_RELEASE);
537 process_absolute(struct touchpad_dispatch *touchpad,
538 struct evdev_device *device,
539 struct input_event *e)
543 if (e->value > touchpad->pressure.touch_high &&
544 !(touchpad->state & TOUCHPAD_STATE_TOUCH))
546 else if (e->value < touchpad->pressure.touch_low &&
547 touchpad->state & TOUCHPAD_STATE_TOUCH)
548 on_release(touchpad);
552 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
553 touchpad->hw_abs.x = e->value;
554 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
555 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X;
559 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
560 touchpad->hw_abs.y = e->value;
561 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
562 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y;
569 process_key(struct touchpad_dispatch *touchpad,
570 struct evdev_device *device,
571 struct input_event *e,
578 if (!touchpad->has_pressure) {
579 if (e->value && !(touchpad->state & TOUCHPAD_STATE_TOUCH))
582 on_release(touchpad);
593 if (!touchpad->fsm.enable && e->code == BTN_LEFT &&
594 touchpad->finger_state == TOUCHPAD_FINGERS_TWO)
598 notify_button(device->seat, time, code,
599 e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
600 WL_POINTER_BUTTON_STATE_RELEASED);
603 case BTN_TOOL_RUBBER:
605 case BTN_TOOL_PENCIL:
606 case BTN_TOOL_AIRBRUSH:
611 case BTN_TOOL_FINGER:
613 touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
615 touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
617 case BTN_TOOL_DOUBLETAP:
619 touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
621 touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
623 case BTN_TOOL_TRIPLETAP:
625 touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
627 touchpad->finger_state &= ~TOUCHPAD_FINGERS_THREE;
633 touchpad_process(struct evdev_dispatch *dispatch,
634 struct evdev_device *device,
635 struct input_event *e,
638 struct touchpad_dispatch *touchpad =
639 (struct touchpad_dispatch *) dispatch;
643 if (e->code == SYN_REPORT)
644 touchpad->event_mask |= TOUCHPAD_EVENT_REPORT;
647 process_absolute(touchpad, device, e);
650 process_key(touchpad, device, e, time);
654 touchpad_update_state(touchpad, time);
658 touchpad_destroy(struct evdev_dispatch *dispatch)
660 struct touchpad_dispatch *touchpad =
661 (struct touchpad_dispatch *) dispatch;
663 touchpad->filter->interface->destroy(touchpad->filter);
664 wl_event_source_remove(touchpad->fsm.timer_source);
668 struct evdev_dispatch_interface touchpad_interface = {
674 touchpad_init(struct touchpad_dispatch *touchpad,
675 struct evdev_device *device)
677 struct weston_motion_filter *accel;
678 struct wl_event_loop *loop;
680 unsigned long prop_bits[INPUT_PROP_MAX];
681 struct input_absinfo absinfo;
682 unsigned long abs_bits[NBITS(ABS_MAX)];
690 touchpad->base.interface = &touchpad_interface;
691 touchpad->device = device;
694 touchpad->model = get_touchpad_model(device);
696 ioctl(device->fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits);
697 has_buttonpad = TEST_BIT(prop_bits, INPUT_PROP_BUTTONPAD);
699 /* Configure pressure */
700 ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
701 if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
702 ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo);
703 configure_touchpad_pressure(touchpad,
708 /* Configure acceleration factor */
709 width = abs(device->abs.max_x - device->abs.min_x);
710 height = abs(device->abs.max_y - device->abs.min_y);
711 diagonal = sqrt(width*width + height*height);
713 touchpad->constant_accel_factor =
714 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
716 touchpad->min_accel_factor = DEFAULT_MIN_ACCEL_FACTOR;
717 touchpad->max_accel_factor = DEFAULT_MAX_ACCEL_FACTOR;
719 touchpad->hysteresis.margin_x =
720 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
721 touchpad->hysteresis.margin_y =
722 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
723 touchpad->hysteresis.center_x = 0;
724 touchpad->hysteresis.center_y = 0;
726 /* Configure acceleration profile */
727 accel = create_pointer_accelator_filter(touchpad_profile);
730 touchpad->filter = accel;
732 /* Setup initial state */
735 memset(touchpad->motion_history, 0, sizeof touchpad->motion_history);
736 touchpad->motion_index = 0;
737 touchpad->motion_count = 0;
739 touchpad->state = TOUCHPAD_STATE_NONE;
740 touchpad->last_finger_state = 0;
741 touchpad->finger_state = 0;
743 wl_array_init(&touchpad->fsm.events);
744 touchpad->fsm.state = FSM_IDLE;
746 loop = wl_display_get_event_loop(device->seat->compositor->wl_display);
747 touchpad->fsm.timer_source =
748 wl_event_loop_add_timer(loop, fsm_timout_handler, touchpad);
749 if (touchpad->fsm.timer_source == NULL) {
750 accel->interface->destroy(accel);
755 touchpad->fsm.enable = !has_buttonpad;
760 struct evdev_dispatch *
761 evdev_touchpad_create(struct evdev_device *device)
763 struct touchpad_dispatch *touchpad;
765 touchpad = malloc(sizeof *touchpad);
766 if (touchpad == NULL)
769 if (touchpad_init(touchpad, device) != 0) {
774 return &touchpad->base;