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.
30 #include <linux/input.h>
34 #include "../shared/config-parser.h"
37 #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50
38 #define DEFAULT_MIN_ACCEL_FACTOR 0.16
39 #define DEFAULT_MAX_ACCEL_FACTOR 1.0
40 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
42 #define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
43 #define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
46 TOUCHPAD_MODEL_UNKNOWN = 0,
47 TOUCHPAD_MODEL_SYNAPTICS,
49 TOUCHPAD_MODEL_APPLETOUCH,
50 TOUCHPAD_MODEL_ELANTECH
54 TOUCHPAD_EVENT_NONE = 0,
55 TOUCHPAD_EVENT_ABSOLUTE_ANY = (1 << 0),
56 TOUCHPAD_EVENT_ABSOLUTE_X = (1 << 1),
57 TOUCHPAD_EVENT_ABSOLUTE_Y = (1 << 2),
58 TOUCHPAD_EVENT_REPORT = (1 << 3)
61 struct touchpad_model_spec {
64 enum touchpad_model model;
67 static struct touchpad_model_spec touchpad_spec_table[] = {
68 {0x0002, 0x0007, TOUCHPAD_MODEL_SYNAPTICS},
69 {0x0002, 0x0008, TOUCHPAD_MODEL_ALPS},
70 {0x05ac, 0x0000, TOUCHPAD_MODEL_APPLETOUCH},
71 {0x0002, 0x000e, TOUCHPAD_MODEL_ELANTECH},
72 {0x0000, 0x0000, TOUCHPAD_MODEL_UNKNOWN}
76 TOUCHPAD_STATE_NONE = 0,
77 TOUCHPAD_STATE_TOUCH = (1 << 0),
78 TOUCHPAD_STATE_MOVE = (1 << 1)
81 #define TOUCHPAD_HISTORY_LENGTH 4
83 struct touchpad_motion {
88 enum touchpad_fingers_state {
89 TOUCHPAD_FINGERS_ONE = (1 << 0),
90 TOUCHPAD_FINGERS_TWO = (1 << 1),
91 TOUCHPAD_FINGERS_THREE = (1 << 2)
109 struct touchpad_dispatch {
110 struct evdev_dispatch base;
111 struct evdev_device *device;
113 enum touchpad_model model;
116 int last_finger_state;
118 double constant_accel_factor;
119 double min_accel_factor;
120 double max_accel_factor;
122 unsigned int event_mask;
123 unsigned int event_mask_filter;
130 struct wl_array events;
131 enum fsm_state state;
132 struct wl_event_source *timer_source;
153 struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
155 unsigned int motion_count;
157 struct weston_motion_filter *filter;
160 static enum touchpad_model
161 get_touchpad_model(struct evdev_device *device)
166 if (ioctl(device->fd, EVIOCGID, &id) < 0)
167 return TOUCHPAD_MODEL_UNKNOWN;
169 for (i = 0; i < ARRAY_LENGTH(touchpad_spec_table); i++)
170 if (touchpad_spec_table[i].vendor == id.vendor &&
171 (!touchpad_spec_table[i].product ||
172 touchpad_spec_table[i].product == id.product))
173 return touchpad_spec_table[i].model;
175 return TOUCHPAD_MODEL_UNKNOWN;
179 configure_touchpad_pressure(struct touchpad_dispatch *touchpad,
180 int32_t pressure_min, int32_t pressure_max)
182 int32_t range = pressure_max - pressure_min + 1;
184 touchpad->has_pressure = 1;
186 /* Magic numbers from xf86-input-synaptics */
187 switch (touchpad->model) {
188 case TOUCHPAD_MODEL_ELANTECH:
189 touchpad->pressure.touch_low = pressure_min + 1;
190 touchpad->pressure.touch_high = pressure_min + 1;
193 touchpad->pressure.touch_low =
194 pressure_min + range * (25.0/256.0);
195 touchpad->pressure.touch_high =
196 pressure_min + range * (30.0/256.0);
201 touchpad_profile(struct weston_motion_filter *filter,
206 struct touchpad_dispatch *touchpad =
207 (struct touchpad_dispatch *) data;
211 accel_factor = velocity * touchpad->constant_accel_factor;
213 if (accel_factor > touchpad->max_accel_factor)
214 accel_factor = touchpad->max_accel_factor;
215 else if (accel_factor < touchpad->min_accel_factor)
216 accel_factor = touchpad->min_accel_factor;
221 static inline struct touchpad_motion *
222 motion_history_offset(struct touchpad_dispatch *touchpad, int offset)
225 (touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) %
226 TOUCHPAD_HISTORY_LENGTH;
228 return &touchpad->motion_history[offset_index];
232 estimate_delta(int x0, int x1, int x2, int x3)
234 return (x0 + x1 - x2 - x3) / 4;
238 hysteresis(int in, int center, int margin)
240 int diff = in - center;
241 if (abs(diff) <= margin)
245 return center + diff - margin;
246 else if (diff < -margin)
247 return center + diff + margin;
248 return center + diff;
252 touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy)
254 *dx = estimate_delta(motion_history_offset(touchpad, 0)->x,
255 motion_history_offset(touchpad, 1)->x,
256 motion_history_offset(touchpad, 2)->x,
257 motion_history_offset(touchpad, 3)->x);
258 *dy = estimate_delta(motion_history_offset(touchpad, 0)->y,
259 motion_history_offset(touchpad, 1)->y,
260 motion_history_offset(touchpad, 2)->y,
261 motion_history_offset(touchpad, 3)->y);
265 filter_motion(struct touchpad_dispatch *touchpad,
266 double *dx, double *dy, uint32_t time)
268 struct weston_motion_params motion;
273 weston_filter_dispatch(touchpad->filter, &motion, touchpad, time);
280 notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
282 notify_button(touchpad->device->seat, time,
283 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
284 WL_POINTER_BUTTON_STATE_PRESSED);
288 notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
290 notify_button(touchpad->device->seat, time,
291 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
292 WL_POINTER_BUTTON_STATE_RELEASED);
296 notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
298 notify_button_pressed(touchpad, time);
299 notify_button_released(touchpad, time);
303 process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
305 uint32_t timeout = UINT32_MAX;
306 enum fsm_event *pevent;
307 enum fsm_event event;
309 if (!touchpad->fsm.enable)
312 if (touchpad->fsm.events.size == 0)
315 wl_array_for_each(pevent, &touchpad->fsm.events) {
319 switch (touchpad->fsm.state) {
322 case FSM_EVENT_TOUCH:
323 touchpad->fsm.state = FSM_TOUCH;
331 case FSM_EVENT_RELEASE:
332 timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
333 touchpad->fsm.state = FSM_TAP;
336 touchpad->fsm.state = FSM_IDLE;
342 case FSM_EVENT_TIMEOUT:
343 notify_tap(touchpad, time);
344 touchpad->fsm.state = FSM_IDLE;
346 case FSM_EVENT_TOUCH:
347 notify_button_pressed(touchpad, time);
348 touchpad->fsm.state = FSM_TAP_2;
351 touchpad->fsm.state = FSM_IDLE;
357 case FSM_EVENT_MOTION:
358 touchpad->fsm.state = FSM_DRAG;
360 case FSM_EVENT_RELEASE:
361 notify_button_released(touchpad, time);
362 notify_tap(touchpad, time);
363 touchpad->fsm.state = FSM_IDLE;
366 touchpad->fsm.state = FSM_IDLE;
372 case FSM_EVENT_RELEASE:
373 notify_button_released(touchpad, time);
374 touchpad->fsm.state = FSM_IDLE;
377 touchpad->fsm.state = FSM_IDLE;
382 weston_log("evdev-touchpad: Unknown state %d",
383 touchpad->fsm.state);
384 touchpad->fsm.state = FSM_IDLE;
389 if (timeout != UINT32_MAX)
390 wl_event_source_timer_update(touchpad->fsm.timer_source,
393 wl_array_release(&touchpad->fsm.events);
394 wl_array_init(&touchpad->fsm.events);
398 push_fsm_event(struct touchpad_dispatch *touchpad,
399 enum fsm_event event)
401 enum fsm_event *pevent;
403 if (!touchpad->fsm.enable)
406 pevent = wl_array_add(&touchpad->fsm.events, sizeof event);
410 touchpad->fsm.state = FSM_IDLE;
414 fsm_timout_handler(void *data)
416 struct touchpad_dispatch *touchpad = data;
418 if (touchpad->fsm.events.size == 0) {
419 push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
420 process_fsm_events(touchpad, weston_compositor_get_time());
427 touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
430 int center_x, center_y;
431 double dx = 0.0, dy = 0.0;
433 if (touchpad->reset ||
434 touchpad->last_finger_state != touchpad->finger_state) {
436 touchpad->motion_count = 0;
437 touchpad->event_mask = TOUCHPAD_EVENT_NONE;
438 touchpad->event_mask_filter =
439 TOUCHPAD_EVENT_ABSOLUTE_X | TOUCHPAD_EVENT_ABSOLUTE_Y;
441 touchpad->last_finger_state = touchpad->finger_state;
443 process_fsm_events(touchpad, time);
447 touchpad->last_finger_state = touchpad->finger_state;
449 if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT))
452 touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT;
454 if ((touchpad->event_mask & touchpad->event_mask_filter) !=
455 touchpad->event_mask_filter)
458 touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY;
459 touchpad->event_mask = 0;
461 /* Avoid noice by moving center only when delta reaches a threshold
462 * distance from the old center. */
463 if (touchpad->motion_count > 0) {
464 center_x = hysteresis(touchpad->hw_abs.x,
465 touchpad->hysteresis.center_x,
466 touchpad->hysteresis.margin_x);
467 center_y = hysteresis(touchpad->hw_abs.y,
468 touchpad->hysteresis.center_y,
469 touchpad->hysteresis.margin_y);
471 center_x = touchpad->hw_abs.x;
472 center_y = touchpad->hw_abs.y;
474 touchpad->hysteresis.center_x = center_x;
475 touchpad->hysteresis.center_y = center_y;
476 touchpad->hw_abs.x = center_x;
477 touchpad->hw_abs.y = center_y;
479 /* Update motion history tracker */
480 motion_index = (touchpad->motion_index + 1) % TOUCHPAD_HISTORY_LENGTH;
481 touchpad->motion_index = motion_index;
482 touchpad->motion_history[motion_index].x = touchpad->hw_abs.x;
483 touchpad->motion_history[motion_index].y = touchpad->hw_abs.y;
484 if (touchpad->motion_count < 4)
485 touchpad->motion_count++;
487 if (touchpad->motion_count >= 4) {
488 touchpad_get_delta(touchpad, &dx, &dy);
490 filter_motion(touchpad, &dx, &dy, time);
492 if (touchpad->finger_state == TOUCHPAD_FINGERS_ONE) {
493 notify_motion(touchpad->device->seat, time,
494 wl_fixed_from_double(dx),
495 wl_fixed_from_double(dy));
496 } else if (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) {
498 notify_axis(touchpad->device->seat,
500 WL_POINTER_AXIS_HORIZONTAL_SCROLL,
501 wl_fixed_from_double(dx));
503 notify_axis(touchpad->device->seat,
505 WL_POINTER_AXIS_VERTICAL_SCROLL,
506 wl_fixed_from_double(dy));
510 if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
511 ((int)dx || (int)dy)) {
512 touchpad->state |= TOUCHPAD_STATE_MOVE;
513 push_fsm_event(touchpad, FSM_EVENT_MOTION);
516 process_fsm_events(touchpad, time);
520 on_touch(struct touchpad_dispatch *touchpad)
522 touchpad->state |= TOUCHPAD_STATE_TOUCH;
524 push_fsm_event(touchpad, FSM_EVENT_TOUCH);
528 on_release(struct touchpad_dispatch *touchpad)
532 touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
534 push_fsm_event(touchpad, FSM_EVENT_RELEASE);
538 process_absolute(struct touchpad_dispatch *touchpad,
539 struct evdev_device *device,
540 struct input_event *e)
544 if (e->value > touchpad->pressure.touch_high &&
545 !(touchpad->state & TOUCHPAD_STATE_TOUCH))
547 else if (e->value < touchpad->pressure.touch_low &&
548 touchpad->state & TOUCHPAD_STATE_TOUCH)
549 on_release(touchpad);
553 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
554 touchpad->hw_abs.x = e->value;
555 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
556 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X;
560 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
561 touchpad->hw_abs.y = e->value;
562 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
563 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y;
570 process_key(struct touchpad_dispatch *touchpad,
571 struct evdev_device *device,
572 struct input_event *e,
579 if (!touchpad->has_pressure) {
580 if (e->value && !(touchpad->state & TOUCHPAD_STATE_TOUCH))
583 on_release(touchpad);
594 if (!touchpad->fsm.enable && e->code == BTN_LEFT &&
595 touchpad->finger_state == TOUCHPAD_FINGERS_TWO)
599 notify_button(device->seat, time, code,
600 e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
601 WL_POINTER_BUTTON_STATE_RELEASED);
604 case BTN_TOOL_RUBBER:
606 case BTN_TOOL_PENCIL:
607 case BTN_TOOL_AIRBRUSH:
612 case BTN_TOOL_FINGER:
614 touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
616 touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
618 case BTN_TOOL_DOUBLETAP:
620 touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
622 touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
624 case BTN_TOOL_TRIPLETAP:
626 touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
628 touchpad->finger_state &= ~TOUCHPAD_FINGERS_THREE;
634 touchpad_process(struct evdev_dispatch *dispatch,
635 struct evdev_device *device,
636 struct input_event *e,
639 struct touchpad_dispatch *touchpad =
640 (struct touchpad_dispatch *) dispatch;
644 if (e->code == SYN_REPORT)
645 touchpad->event_mask |= TOUCHPAD_EVENT_REPORT;
648 process_absolute(touchpad, device, e);
651 process_key(touchpad, device, e, time);
655 touchpad_update_state(touchpad, time);
659 touchpad_destroy(struct evdev_dispatch *dispatch)
661 struct touchpad_dispatch *touchpad =
662 (struct touchpad_dispatch *) dispatch;
664 touchpad->filter->interface->destroy(touchpad->filter);
665 wl_event_source_remove(touchpad->fsm.timer_source);
669 struct evdev_dispatch_interface touchpad_interface = {
675 touchpad_parse_config(struct touchpad_dispatch *touchpad, double diagonal)
677 struct weston_compositor *compositor =
678 touchpad->device->seat->compositor;
679 struct weston_config_section *s;
680 double constant_accel_factor;
681 double min_accel_factor;
682 double max_accel_factor;
684 s = weston_config_get_section(compositor->config,
685 "touchpad", NULL, NULL);
686 weston_config_section_get_double(s, "constant_accel_factor",
687 &constant_accel_factor,
688 DEFAULT_CONSTANT_ACCEL_NUMERATOR);
689 weston_config_section_get_double(s, "min_accel_factor",
691 DEFAULT_MIN_ACCEL_FACTOR);
692 weston_config_section_get_double(s, "max_accel_factor",
694 DEFAULT_MAX_ACCEL_FACTOR);
696 touchpad->constant_accel_factor =
697 constant_accel_factor / diagonal;
698 touchpad->min_accel_factor = min_accel_factor;
699 touchpad->max_accel_factor = max_accel_factor;
703 touchpad_init(struct touchpad_dispatch *touchpad,
704 struct evdev_device *device)
706 struct weston_motion_filter *accel;
707 struct wl_event_loop *loop;
709 unsigned long prop_bits[INPUT_PROP_MAX];
710 struct input_absinfo absinfo;
711 unsigned long abs_bits[NBITS(ABS_MAX)];
719 touchpad->base.interface = &touchpad_interface;
720 touchpad->device = device;
723 touchpad->model = get_touchpad_model(device);
725 ioctl(device->fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits);
726 has_buttonpad = TEST_BIT(prop_bits, INPUT_PROP_BUTTONPAD);
728 /* Configure pressure */
729 ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
730 if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
731 ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo);
732 configure_touchpad_pressure(touchpad,
737 /* Configure acceleration factor */
738 width = abs(device->abs.max_x - device->abs.min_x);
739 height = abs(device->abs.max_y - device->abs.min_y);
740 diagonal = sqrt(width*width + height*height);
742 touchpad_parse_config(touchpad, diagonal);
744 touchpad->hysteresis.margin_x =
745 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
746 touchpad->hysteresis.margin_y =
747 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
748 touchpad->hysteresis.center_x = 0;
749 touchpad->hysteresis.center_y = 0;
751 /* Configure acceleration profile */
752 accel = create_pointer_accelator_filter(touchpad_profile);
755 touchpad->filter = accel;
757 /* Setup initial state */
760 memset(touchpad->motion_history, 0, sizeof touchpad->motion_history);
761 touchpad->motion_index = 0;
762 touchpad->motion_count = 0;
764 touchpad->state = TOUCHPAD_STATE_NONE;
765 touchpad->last_finger_state = 0;
766 touchpad->finger_state = 0;
768 wl_array_init(&touchpad->fsm.events);
769 touchpad->fsm.state = FSM_IDLE;
771 loop = wl_display_get_event_loop(device->seat->compositor->wl_display);
772 touchpad->fsm.timer_source =
773 wl_event_loop_add_timer(loop, fsm_timout_handler, touchpad);
774 if (touchpad->fsm.timer_source == NULL) {
775 accel->interface->destroy(accel);
780 touchpad->fsm.enable = !has_buttonpad;
785 struct evdev_dispatch *
786 evdev_touchpad_create(struct evdev_device *device)
788 struct touchpad_dispatch *touchpad;
790 touchpad = malloc(sizeof *touchpad);
791 if (touchpad == NULL)
794 if (touchpad_init(touchpad, device) != 0) {
799 return &touchpad->base;