blob: 6a3217bdedf443a74d2d7c63bef7dbf1ab7cc46f [file] [log] [blame]
Jonas Ådahl1df17af2012-05-17 12:18:17 +02001/*
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 Ådahl1df17af2012-05-17 12:18:17 +020023#include <stdlib.h>
24#include <math.h>
25#include <string.h>
Jonas Ådahl87b07352012-09-27 18:40:40 +020026#include <stdbool.h>
Jonas Ådahl1df17af2012-05-17 12:18:17 +020027#include <linux/input.h>
28
29#include "filter.h"
Pekka Paalanencfa1f672012-08-03 14:38:59 +030030#include "evdev.h"
Jonas Ådahl1df17af2012-05-17 12:18:17 +020031
32/* Default values */
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
37
Jonas Ådahl87b07352012-09-27 18:40:40 +020038#define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
39#define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
40
Jonas Ådahl1df17af2012-05-17 12:18:17 +020041enum touchpad_model {
42 TOUCHPAD_MODEL_UNKNOWN = 0,
43 TOUCHPAD_MODEL_SYNAPTICS,
44 TOUCHPAD_MODEL_ALPS,
45 TOUCHPAD_MODEL_APPLETOUCH,
46 TOUCHPAD_MODEL_ELANTECH
47};
48
Jonas Ådahlc6894932012-09-27 18:40:39 +020049enum touchpad_event {
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)
55};
Jonas Ådahl1df17af2012-05-17 12:18:17 +020056
57struct touchpad_model_spec {
58 short vendor;
59 short product;
60 enum touchpad_model model;
61};
62
63static 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}
69};
70
71enum touchpad_state {
Jonas Ådahlc6894932012-09-27 18:40:39 +020072 TOUCHPAD_STATE_NONE = 0,
73 TOUCHPAD_STATE_TOUCH = (1 << 0),
74 TOUCHPAD_STATE_MOVE = (1 << 1)
Jonas Ådahl1df17af2012-05-17 12:18:17 +020075};
76
77#define TOUCHPAD_HISTORY_LENGTH 4
78
79struct touchpad_motion {
80 int32_t x;
81 int32_t y;
82};
83
84enum touchpad_fingers_state {
85 TOUCHPAD_FINGERS_ONE = (1 << 0),
86 TOUCHPAD_FINGERS_TWO = (1 << 1),
87 TOUCHPAD_FINGERS_THREE = (1 << 2)
88};
89
Jonas Ådahl87b07352012-09-27 18:40:40 +020090enum fsm_event {
91 FSM_EVENT_TOUCH,
92 FSM_EVENT_RELEASE,
93 FSM_EVENT_MOTION,
94 FSM_EVENT_TIMEOUT
95};
96
97enum fsm_state {
98 FSM_IDLE,
99 FSM_TOUCH,
100 FSM_TAP,
101 FSM_TAP_2,
102 FSM_DRAG
103};
104
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200105struct touchpad_dispatch {
106 struct evdev_dispatch base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300107 struct evdev_device *device;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200108
109 enum touchpad_model model;
Jonas Ådahlc6894932012-09-27 18:40:39 +0200110 unsigned int state;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200111 int finger_state;
112 int last_finger_state;
113
114 double constant_accel_factor;
115 double min_accel_factor;
116 double max_accel_factor;
117
118 unsigned int event_mask;
119 unsigned int event_mask_filter;
120
121 int reset;
122
123 struct {
Jonas Ådahl87b07352012-09-27 18:40:40 +0200124 struct wl_array events;
125 enum fsm_state state;
126 struct wl_event_source *timer_source;
127 } fsm;
128
129 struct {
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200130 int32_t x;
131 int32_t y;
132 } hw_abs;
133
134 int has_pressure;
135 struct {
136 int32_t touch_low;
137 int32_t touch_high;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200138 } pressure;
139
140 struct {
141 int32_t margin_x;
142 int32_t margin_y;
143 int32_t center_x;
144 int32_t center_y;
145 } hysteresis;
146
147 struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
148 int motion_index;
149 unsigned int motion_count;
150
Jonas Ådahlc6894932012-09-27 18:40:39 +0200151 struct weston_motion_filter *filter;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200152};
153
154static enum touchpad_model
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300155get_touchpad_model(struct evdev_device *device)
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200156{
157 struct input_id id;
158 unsigned int i;
159
160 if (ioctl(device->fd, EVIOCGID, &id) < 0)
161 return TOUCHPAD_MODEL_UNKNOWN;
162
Rob Bradfordec913fd2012-10-09 18:44:32 +0100163 for (i = 0; ARRAY_LENGTH(touchpad_spec_table); i++)
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200164 if (touchpad_spec_table[i].vendor == id.vendor &&
165 (!touchpad_spec_table[i].product ||
166 touchpad_spec_table[i].product == id.product))
167 return touchpad_spec_table[i].model;
168
169 return TOUCHPAD_MODEL_UNKNOWN;
170}
171
172static void
173configure_touchpad_pressure(struct touchpad_dispatch *touchpad,
174 int32_t pressure_min, int32_t pressure_max)
175{
176 int32_t range = pressure_max - pressure_min + 1;
177
178 touchpad->has_pressure = 1;
179
180 /* Magic numbers from xf86-input-synaptics */
181 switch (touchpad->model) {
182 case TOUCHPAD_MODEL_ELANTECH:
183 touchpad->pressure.touch_low = pressure_min + 1;
184 touchpad->pressure.touch_high = pressure_min + 1;
185 break;
186 default:
187 touchpad->pressure.touch_low =
188 pressure_min + range * (25.0/256.0);
189 touchpad->pressure.touch_high =
190 pressure_min + range * (30.0/256.0);
191 }
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200192}
193
194static double
195touchpad_profile(struct weston_motion_filter *filter,
196 void *data,
197 double velocity,
198 uint32_t time)
199{
200 struct touchpad_dispatch *touchpad =
201 (struct touchpad_dispatch *) data;
202
203 double accel_factor;
204
205 accel_factor = velocity * touchpad->constant_accel_factor;
206
207 if (accel_factor > touchpad->max_accel_factor)
208 accel_factor = touchpad->max_accel_factor;
209 else if (accel_factor < touchpad->min_accel_factor)
210 accel_factor = touchpad->min_accel_factor;
211
212 return accel_factor;
213}
214
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200215static inline struct touchpad_motion *
216motion_history_offset(struct touchpad_dispatch *touchpad, int offset)
217{
218 int offset_index =
219 (touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) %
220 TOUCHPAD_HISTORY_LENGTH;
221
222 return &touchpad->motion_history[offset_index];
223}
224
225static double
226estimate_delta(int x0, int x1, int x2, int x3)
227{
228 return (x0 + x1 - x2 - x3) / 4;
229}
230
231static int
232hysteresis(int in, int center, int margin)
233{
234 int diff = in - center;
235 if (abs(diff) <= margin)
236 return center;
237
238 if (diff > margin)
239 return center + diff - margin;
240 else if (diff < -margin)
241 return center + diff + margin;
242 return center + diff;
243}
244
245static void
246touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy)
247{
248 *dx = estimate_delta(motion_history_offset(touchpad, 0)->x,
249 motion_history_offset(touchpad, 1)->x,
250 motion_history_offset(touchpad, 2)->x,
251 motion_history_offset(touchpad, 3)->x);
252 *dy = estimate_delta(motion_history_offset(touchpad, 0)->y,
253 motion_history_offset(touchpad, 1)->y,
254 motion_history_offset(touchpad, 2)->y,
255 motion_history_offset(touchpad, 3)->y);
256}
257
258static void
259filter_motion(struct touchpad_dispatch *touchpad,
260 double *dx, double *dy, uint32_t time)
261{
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200262 struct weston_motion_params motion;
263
264 motion.dx = *dx;
265 motion.dy = *dy;
266
Jonas Ådahlc6894932012-09-27 18:40:39 +0200267 weston_filter_dispatch(touchpad->filter, &motion, touchpad, time);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200268
269 *dx = motion.dx;
270 *dy = motion.dy;
271}
272
273static void
Jonas Ådahl87b07352012-09-27 18:40:40 +0200274notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
275{
276 notify_button(touchpad->device->seat, time,
277 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
278 WL_POINTER_BUTTON_STATE_PRESSED);
279}
280
281static void
282notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
283{
284 notify_button(touchpad->device->seat, time,
285 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
286 WL_POINTER_BUTTON_STATE_RELEASED);
287}
288
289static void
290notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
291{
292 notify_button_pressed(touchpad, time);
293 notify_button_released(touchpad, time);
294}
295
296static void
297process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
298{
299 uint32_t timeout = UINT32_MAX;
300 enum fsm_event *pevent;
301 enum fsm_event event;
302
303 if (touchpad->fsm.events.size == 0)
304 return;
305
306 wl_array_for_each(pevent, &touchpad->fsm.events) {
307 event = *pevent;
308 timeout = 0;
309
310 switch (touchpad->fsm.state) {
311 case FSM_IDLE:
312 switch (event) {
313 case FSM_EVENT_TOUCH:
314 touchpad->fsm.state = FSM_TOUCH;
315 break;
316 default:
317 break;
318 }
319 break;
320 case FSM_TOUCH:
321 switch (event) {
322 case FSM_EVENT_RELEASE:
323 timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
324 touchpad->fsm.state = FSM_TAP;
325 break;
326 default:
327 touchpad->fsm.state = FSM_IDLE;
328 break;
329 }
330 break;
331 case FSM_TAP:
332 switch (event) {
333 case FSM_EVENT_TIMEOUT:
334 notify_tap(touchpad, time);
335 touchpad->fsm.state = FSM_IDLE;
336 break;
337 case FSM_EVENT_TOUCH:
338 notify_button_pressed(touchpad, time);
339 touchpad->fsm.state = FSM_TAP_2;
340 break;
341 default:
342 touchpad->fsm.state = FSM_IDLE;
343 break;
344 }
345 break;
346 case FSM_TAP_2:
347 switch (event) {
348 case FSM_EVENT_MOTION:
349 touchpad->fsm.state = FSM_DRAG;
350 break;
351 case FSM_EVENT_RELEASE:
352 notify_button_released(touchpad, time);
353 notify_tap(touchpad, time);
354 touchpad->fsm.state = FSM_IDLE;
355 break;
356 default:
357 touchpad->fsm.state = FSM_IDLE;
358 break;
359 }
360 break;
361 case FSM_DRAG:
362 switch (event) {
363 case FSM_EVENT_RELEASE:
364 notify_button_released(touchpad, time);
365 touchpad->fsm.state = FSM_IDLE;
366 break;
367 default:
368 touchpad->fsm.state = FSM_IDLE;
369 break;
370 }
371 break;
372 default:
373 weston_log("evdev-touchpad: Unknown state %d",
374 touchpad->fsm.state);
375 touchpad->fsm.state = FSM_IDLE;
376 break;
377 }
378 }
379
380 if (timeout != UINT32_MAX)
381 wl_event_source_timer_update(touchpad->fsm.timer_source,
382 timeout);
383
384 wl_array_release(&touchpad->fsm.events);
385 wl_array_init(&touchpad->fsm.events);
386}
387
388static void
389push_fsm_event(struct touchpad_dispatch *touchpad,
390 enum fsm_event event)
391{
392 enum fsm_event *pevent;
393
394 pevent = wl_array_add(&touchpad->fsm.events, sizeof event);
395 if (pevent)
396 *pevent = event;
397 else
398 touchpad->fsm.state = FSM_IDLE;
399}
400
401static int
402fsm_timout_handler(void *data)
403{
404 struct touchpad_dispatch *touchpad = data;
405
406 if (touchpad->fsm.events.size == 0) {
407 push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
408 process_fsm_events(touchpad, weston_compositor_get_time());
409 }
410
411 return 1;
412}
413
414static void
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200415touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
416{
417 int motion_index;
418 int center_x, center_y;
Jonas Ådahlc6894932012-09-27 18:40:39 +0200419 double dx = 0.0, dy = 0.0;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200420
421 if (touchpad->reset ||
422 touchpad->last_finger_state != touchpad->finger_state) {
423 touchpad->reset = 0;
424 touchpad->motion_count = 0;
425 touchpad->event_mask = TOUCHPAD_EVENT_NONE;
426 touchpad->event_mask_filter =
427 TOUCHPAD_EVENT_ABSOLUTE_X | TOUCHPAD_EVENT_ABSOLUTE_Y;
428
429 touchpad->last_finger_state = touchpad->finger_state;
430
Jonas Ådahl87b07352012-09-27 18:40:40 +0200431 process_fsm_events(touchpad, time);
432
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200433 return;
434 }
435 touchpad->last_finger_state = touchpad->finger_state;
436
437 if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT))
438 return;
439 else
440 touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT;
441
442 if ((touchpad->event_mask & touchpad->event_mask_filter) !=
443 touchpad->event_mask_filter)
444 return;
445
446 touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY;
447 touchpad->event_mask = 0;
448
449 /* Avoid noice by moving center only when delta reaches a threshold
450 * distance from the old center. */
451 if (touchpad->motion_count > 0) {
452 center_x = hysteresis(touchpad->hw_abs.x,
453 touchpad->hysteresis.center_x,
454 touchpad->hysteresis.margin_x);
455 center_y = hysteresis(touchpad->hw_abs.y,
456 touchpad->hysteresis.center_y,
457 touchpad->hysteresis.margin_y);
Jonas Ådahlc6894932012-09-27 18:40:39 +0200458 } else {
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200459 center_x = touchpad->hw_abs.x;
460 center_y = touchpad->hw_abs.y;
461 }
462 touchpad->hysteresis.center_x = center_x;
463 touchpad->hysteresis.center_y = center_y;
464 touchpad->hw_abs.x = center_x;
465 touchpad->hw_abs.y = center_y;
466
467 /* Update motion history tracker */
468 motion_index = (touchpad->motion_index + 1) % TOUCHPAD_HISTORY_LENGTH;
469 touchpad->motion_index = motion_index;
470 touchpad->motion_history[motion_index].x = touchpad->hw_abs.x;
471 touchpad->motion_history[motion_index].y = touchpad->hw_abs.y;
472 if (touchpad->motion_count < 4)
473 touchpad->motion_count++;
474
475 if (touchpad->motion_count >= 4) {
476 touchpad_get_delta(touchpad, &dx, &dy);
477
478 filter_motion(touchpad, &dx, &dy, time);
479
Jonas Ådahld9f58192012-09-27 18:40:43 +0200480 if (touchpad->finger_state == TOUCHPAD_FINGERS_ONE) {
481 touchpad->device->rel.dx = wl_fixed_from_double(dx);
482 touchpad->device->rel.dy = wl_fixed_from_double(dy);
483 touchpad->device->pending_events |=
484 EVDEV_RELATIVE_MOTION;
485 } else if (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) {
486 if (dx != 0.0)
487 notify_axis(touchpad->device->seat,
488 time,
489 WL_POINTER_AXIS_HORIZONTAL_SCROLL,
490 wl_fixed_from_double(dx));
491 if (dy != 0.0)
492 notify_axis(touchpad->device->seat,
493 time,
494 WL_POINTER_AXIS_VERTICAL_SCROLL,
495 wl_fixed_from_double(dy));
496 }
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200497 }
Jonas Ådahlc6894932012-09-27 18:40:39 +0200498
499 if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
500 ((int)dx || (int)dy)) {
501 touchpad->state |= TOUCHPAD_STATE_MOVE;
Jonas Ådahl87b07352012-09-27 18:40:40 +0200502 push_fsm_event(touchpad, FSM_EVENT_MOTION);
Jonas Ådahlc6894932012-09-27 18:40:39 +0200503 }
Jonas Ådahl87b07352012-09-27 18:40:40 +0200504
505 process_fsm_events(touchpad, time);
Jonas Ådahlc6894932012-09-27 18:40:39 +0200506}
507
508static void
509on_touch(struct touchpad_dispatch *touchpad)
510{
511 touchpad->state |= TOUCHPAD_STATE_TOUCH;
Jonas Ådahl87b07352012-09-27 18:40:40 +0200512
513 push_fsm_event(touchpad, FSM_EVENT_TOUCH);
Jonas Ådahlc6894932012-09-27 18:40:39 +0200514}
515
516static void
517on_release(struct touchpad_dispatch *touchpad)
518{
519
520 touchpad->reset = 1;
521 touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
Jonas Ådahl87b07352012-09-27 18:40:40 +0200522
523 push_fsm_event(touchpad, FSM_EVENT_RELEASE);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200524}
525
526static inline void
527process_absolute(struct touchpad_dispatch *touchpad,
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300528 struct evdev_device *device,
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200529 struct input_event *e)
530{
531 switch (e->code) {
532 case ABS_PRESSURE:
Jonas Ådahlc6894932012-09-27 18:40:39 +0200533 if (e->value > touchpad->pressure.touch_high &&
534 !(touchpad->state & TOUCHPAD_STATE_TOUCH))
535 on_touch(touchpad);
536 else if (e->value < touchpad->pressure.touch_low &&
537 touchpad->state & TOUCHPAD_STATE_TOUCH)
538 on_release(touchpad);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200539
540 break;
541 case ABS_X:
Jonas Ådahlc6894932012-09-27 18:40:39 +0200542 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200543 touchpad->hw_abs.x = e->value;
544 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
545 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X;
546 }
547 break;
548 case ABS_Y:
Jonas Ådahlc6894932012-09-27 18:40:39 +0200549 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200550 touchpad->hw_abs.y = e->value;
551 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
552 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y;
553 }
554 break;
555 }
556}
557
558static inline void
559process_key(struct touchpad_dispatch *touchpad,
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300560 struct evdev_device *device,
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200561 struct input_event *e,
562 uint32_t time)
563{
564 switch (e->code) {
565 case BTN_TOUCH:
566 if (!touchpad->has_pressure) {
Jonas Ådahlc6894932012-09-27 18:40:39 +0200567 if (e->value && !(touchpad->state & TOUCHPAD_STATE_TOUCH))
568 on_touch(touchpad);
569 else if (!e->value)
570 on_release(touchpad);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200571 }
572 break;
573 case BTN_LEFT:
574 case BTN_RIGHT:
575 case BTN_MIDDLE:
576 case BTN_SIDE:
577 case BTN_EXTRA:
578 case BTN_FORWARD:
579 case BTN_BACK:
580 case BTN_TASK:
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -0400581 notify_button(device->seat,
Daniel Stone4dbadb12012-05-30 16:31:51 +0100582 time, e->code,
583 e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
584 WL_POINTER_BUTTON_STATE_RELEASED);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200585 break;
586 case BTN_TOOL_PEN:
587 case BTN_TOOL_RUBBER:
588 case BTN_TOOL_BRUSH:
589 case BTN_TOOL_PENCIL:
590 case BTN_TOOL_AIRBRUSH:
591 case BTN_TOOL_MOUSE:
592 case BTN_TOOL_LENS:
593 touchpad->reset = 1;
594 break;
595 case BTN_TOOL_FINGER:
Rob Bradford3de191e2012-10-09 18:44:29 +0100596 if (e->value)
597 touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
Jonas Ådahld9f58192012-09-27 18:40:43 +0200598 else
599 touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200600 break;
601 case BTN_TOOL_DOUBLETAP:
Rob Bradford3de191e2012-10-09 18:44:29 +0100602 if (e->value)
603 touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
Jonas Ådahld9f58192012-09-27 18:40:43 +0200604 else
605 touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200606 break;
607 case BTN_TOOL_TRIPLETAP:
Rob Bradford3de191e2012-10-09 18:44:29 +0100608 if (e->value)
609 touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
Jonas Ådahld9f58192012-09-27 18:40:43 +0200610 else
611 touchpad->finger_state &= ~TOUCHPAD_FINGERS_THREE;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200612 break;
613 }
614}
615
616static void
617touchpad_process(struct evdev_dispatch *dispatch,
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300618 struct evdev_device *device,
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200619 struct input_event *e,
620 uint32_t time)
621{
622 struct touchpad_dispatch *touchpad =
623 (struct touchpad_dispatch *) dispatch;
624
625 switch (e->type) {
626 case EV_SYN:
627 if (e->code == SYN_REPORT)
628 touchpad->event_mask |= TOUCHPAD_EVENT_REPORT;
629 break;
630 case EV_ABS:
631 process_absolute(touchpad, device, e);
632 break;
633 case EV_KEY:
634 process_key(touchpad, device, e, time);
635 break;
636 }
637
638 touchpad_update_state(touchpad, time);
639}
640
641static void
642touchpad_destroy(struct evdev_dispatch *dispatch)
643{
644 struct touchpad_dispatch *touchpad =
645 (struct touchpad_dispatch *) dispatch;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200646
Jonas Ådahlc6894932012-09-27 18:40:39 +0200647 touchpad->filter->interface->destroy(touchpad->filter);
Jonas Ådahl87b07352012-09-27 18:40:40 +0200648 wl_event_source_remove(touchpad->fsm.timer_source);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200649 free(dispatch);
650}
651
652struct evdev_dispatch_interface touchpad_interface = {
653 touchpad_process,
654 touchpad_destroy
655};
656
Jonas Ådahlc6894932012-09-27 18:40:39 +0200657static int
658touchpad_init(struct touchpad_dispatch *touchpad,
659 struct evdev_device *device)
660{
661 struct weston_motion_filter *accel;
Jonas Ådahl87b07352012-09-27 18:40:40 +0200662 struct wl_event_loop *loop;
Jonas Ådahlc6894932012-09-27 18:40:39 +0200663
664 struct input_absinfo absinfo;
665 unsigned long abs_bits[NBITS(ABS_MAX)];
666
667 double width;
668 double height;
669 double diagonal;
670
671 touchpad->base.interface = &touchpad_interface;
672 touchpad->device = device;
673
674 /* Detect model */
675 touchpad->model = get_touchpad_model(device);
676
677 /* Configure pressure */
678 ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
679 if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
680 ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo);
681 configure_touchpad_pressure(touchpad,
682 absinfo.minimum,
683 absinfo.maximum);
684 }
685
686 /* Configure acceleration factor */
687 width = abs(device->abs.max_x - device->abs.min_x);
688 height = abs(device->abs.max_y - device->abs.min_y);
689 diagonal = sqrt(width*width + height*height);
690
691 touchpad->constant_accel_factor =
692 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
693
694 touchpad->min_accel_factor = DEFAULT_MIN_ACCEL_FACTOR;
695 touchpad->max_accel_factor = DEFAULT_MAX_ACCEL_FACTOR;
696
697 touchpad->hysteresis.margin_x =
698 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
699 touchpad->hysteresis.margin_y =
700 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
701 touchpad->hysteresis.center_x = 0;
702 touchpad->hysteresis.center_y = 0;
703
704 /* Configure acceleration profile */
705 accel = create_pointer_accelator_filter(touchpad_profile);
706 if (accel == NULL)
707 return -1;
708 touchpad->filter = accel;
709
710 /* Setup initial state */
711 touchpad->reset = 1;
712
713 memset(touchpad->motion_history, 0, sizeof touchpad->motion_history);
714 touchpad->motion_index = 0;
715 touchpad->motion_count = 0;
716
717 touchpad->state = TOUCHPAD_STATE_NONE;
718 touchpad->last_finger_state = 0;
719 touchpad->finger_state = 0;
720
Jonas Ådahl87b07352012-09-27 18:40:40 +0200721 wl_array_init(&touchpad->fsm.events);
722 touchpad->fsm.state = FSM_IDLE;
723
724 loop = wl_display_get_event_loop(device->seat->compositor->wl_display);
725 touchpad->fsm.timer_source =
726 wl_event_loop_add_timer(loop, fsm_timout_handler, touchpad);
727 if (touchpad->fsm.timer_source == NULL) {
728 accel->interface->destroy(accel);
729 return -1;
730 }
731
Jonas Ådahlc6894932012-09-27 18:40:39 +0200732 return 0;
733}
734
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200735struct evdev_dispatch *
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300736evdev_touchpad_create(struct evdev_device *device)
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200737{
738 struct touchpad_dispatch *touchpad;
739
740 touchpad = malloc(sizeof *touchpad);
741 if (touchpad == NULL)
742 return NULL;
743
Jonas Ådahlc6894932012-09-27 18:40:39 +0200744 if (touchpad_init(touchpad, device) != 0) {
745 free(touchpad);
746 return NULL;
747 }
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200748
749 return &touchpad->base;
750}