blob: 69f913acf8b79cc3e63ae066f380b66e2bf71e47 [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
Daniel Stonec228e232013-05-22 18:03:19 +030023#include "config.h"
24
Jonas Ådahl1df17af2012-05-17 12:18:17 +020025#include <stdlib.h>
26#include <math.h>
27#include <string.h>
Jonas Ådahl87b07352012-09-27 18:40:40 +020028#include <stdbool.h>
Armin Kb502f902013-07-31 01:41:03 +020029#include <unistd.h>
Jonas Ådahl1df17af2012-05-17 12:18:17 +020030#include <linux/input.h>
31
32#include "filter.h"
Pekka Paalanencfa1f672012-08-03 14:38:59 +030033#include "evdev.h"
Armin Kb502f902013-07-31 01:41:03 +020034#include "../shared/config-parser.h"
Jonas Ådahl1df17af2012-05-17 12:18:17 +020035
36/* Default values */
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
41
Jonas Ådahl87b07352012-09-27 18:40:40 +020042#define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
43#define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
44
Jonas Ådahl1df17af2012-05-17 12:18:17 +020045enum touchpad_model {
46 TOUCHPAD_MODEL_UNKNOWN = 0,
47 TOUCHPAD_MODEL_SYNAPTICS,
48 TOUCHPAD_MODEL_ALPS,
49 TOUCHPAD_MODEL_APPLETOUCH,
50 TOUCHPAD_MODEL_ELANTECH
51};
52
Jonas Ådahlc6894932012-09-27 18:40:39 +020053enum touchpad_event {
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)
59};
Jonas Ådahl1df17af2012-05-17 12:18:17 +020060
61struct touchpad_model_spec {
62 short vendor;
63 short product;
64 enum touchpad_model model;
65};
66
67static 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}
73};
74
75enum touchpad_state {
Jonas Ådahlc6894932012-09-27 18:40:39 +020076 TOUCHPAD_STATE_NONE = 0,
77 TOUCHPAD_STATE_TOUCH = (1 << 0),
78 TOUCHPAD_STATE_MOVE = (1 << 1)
Jonas Ådahl1df17af2012-05-17 12:18:17 +020079};
80
81#define TOUCHPAD_HISTORY_LENGTH 4
82
83struct touchpad_motion {
84 int32_t x;
85 int32_t y;
86};
87
88enum touchpad_fingers_state {
89 TOUCHPAD_FINGERS_ONE = (1 << 0),
90 TOUCHPAD_FINGERS_TWO = (1 << 1),
91 TOUCHPAD_FINGERS_THREE = (1 << 2)
92};
93
Jonas Ådahl87b07352012-09-27 18:40:40 +020094enum fsm_event {
95 FSM_EVENT_TOUCH,
96 FSM_EVENT_RELEASE,
97 FSM_EVENT_MOTION,
98 FSM_EVENT_TIMEOUT
99};
100
101enum fsm_state {
102 FSM_IDLE,
103 FSM_TOUCH,
104 FSM_TAP,
105 FSM_TAP_2,
106 FSM_DRAG
107};
108
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200109struct touchpad_dispatch {
110 struct evdev_dispatch base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300111 struct evdev_device *device;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200112
113 enum touchpad_model model;
Jonas Ådahlc6894932012-09-27 18:40:39 +0200114 unsigned int state;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200115 int finger_state;
116 int last_finger_state;
117
118 double constant_accel_factor;
119 double min_accel_factor;
120 double max_accel_factor;
121
122 unsigned int event_mask;
123 unsigned int event_mask_filter;
124
125 int reset;
126
127 struct {
Jonas Ådahl848e2e62013-03-22 08:41:42 +0100128 bool enable;
129
Jonas Ådahl87b07352012-09-27 18:40:40 +0200130 struct wl_array events;
131 enum fsm_state state;
132 struct wl_event_source *timer_source;
133 } fsm;
134
135 struct {
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200136 int32_t x;
137 int32_t y;
138 } hw_abs;
139
140 int has_pressure;
141 struct {
142 int32_t touch_low;
143 int32_t touch_high;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200144 } pressure;
145
146 struct {
147 int32_t margin_x;
148 int32_t margin_y;
149 int32_t center_x;
150 int32_t center_y;
151 } hysteresis;
152
153 struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
154 int motion_index;
155 unsigned int motion_count;
156
Jonas Ådahlc6894932012-09-27 18:40:39 +0200157 struct weston_motion_filter *filter;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200158};
159
160static enum touchpad_model
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300161get_touchpad_model(struct evdev_device *device)
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200162{
163 struct input_id id;
164 unsigned int i;
165
166 if (ioctl(device->fd, EVIOCGID, &id) < 0)
167 return TOUCHPAD_MODEL_UNKNOWN;
168
Dima Ryazanovddf9bb32012-11-11 00:29:01 -0800169 for (i = 0; i < ARRAY_LENGTH(touchpad_spec_table); i++)
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200170 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;
174
175 return TOUCHPAD_MODEL_UNKNOWN;
176}
177
178static void
179configure_touchpad_pressure(struct touchpad_dispatch *touchpad,
180 int32_t pressure_min, int32_t pressure_max)
181{
182 int32_t range = pressure_max - pressure_min + 1;
183
184 touchpad->has_pressure = 1;
185
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;
191 break;
192 default:
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);
197 }
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200198}
199
200static double
201touchpad_profile(struct weston_motion_filter *filter,
202 void *data,
203 double velocity,
204 uint32_t time)
205{
206 struct touchpad_dispatch *touchpad =
207 (struct touchpad_dispatch *) data;
208
209 double accel_factor;
210
211 accel_factor = velocity * touchpad->constant_accel_factor;
212
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;
217
218 return accel_factor;
219}
220
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200221static inline struct touchpad_motion *
222motion_history_offset(struct touchpad_dispatch *touchpad, int offset)
223{
224 int offset_index =
225 (touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) %
226 TOUCHPAD_HISTORY_LENGTH;
227
228 return &touchpad->motion_history[offset_index];
229}
230
231static double
232estimate_delta(int x0, int x1, int x2, int x3)
233{
234 return (x0 + x1 - x2 - x3) / 4;
235}
236
237static int
238hysteresis(int in, int center, int margin)
239{
240 int diff = in - center;
241 if (abs(diff) <= margin)
242 return center;
243
244 if (diff > margin)
245 return center + diff - margin;
246 else if (diff < -margin)
247 return center + diff + margin;
248 return center + diff;
249}
250
251static void
252touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy)
253{
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);
262}
263
264static void
265filter_motion(struct touchpad_dispatch *touchpad,
266 double *dx, double *dy, uint32_t time)
267{
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200268 struct weston_motion_params motion;
269
270 motion.dx = *dx;
271 motion.dy = *dy;
272
Jonas Ådahlc6894932012-09-27 18:40:39 +0200273 weston_filter_dispatch(touchpad->filter, &motion, touchpad, time);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200274
275 *dx = motion.dx;
276 *dy = motion.dy;
277}
278
279static void
Jonas Ådahl87b07352012-09-27 18:40:40 +0200280notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
281{
282 notify_button(touchpad->device->seat, time,
283 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
284 WL_POINTER_BUTTON_STATE_PRESSED);
285}
286
287static void
288notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
289{
290 notify_button(touchpad->device->seat, time,
291 DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
292 WL_POINTER_BUTTON_STATE_RELEASED);
293}
294
295static void
296notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
297{
298 notify_button_pressed(touchpad, time);
299 notify_button_released(touchpad, time);
300}
301
302static void
303process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
304{
305 uint32_t timeout = UINT32_MAX;
306 enum fsm_event *pevent;
307 enum fsm_event event;
308
Jonas Ådahl848e2e62013-03-22 08:41:42 +0100309 if (!touchpad->fsm.enable)
310 return;
311
Jonas Ådahl87b07352012-09-27 18:40:40 +0200312 if (touchpad->fsm.events.size == 0)
313 return;
314
315 wl_array_for_each(pevent, &touchpad->fsm.events) {
316 event = *pevent;
317 timeout = 0;
318
319 switch (touchpad->fsm.state) {
320 case FSM_IDLE:
321 switch (event) {
322 case FSM_EVENT_TOUCH:
323 touchpad->fsm.state = FSM_TOUCH;
324 break;
325 default:
326 break;
327 }
328 break;
329 case FSM_TOUCH:
330 switch (event) {
331 case FSM_EVENT_RELEASE:
332 timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
333 touchpad->fsm.state = FSM_TAP;
334 break;
335 default:
336 touchpad->fsm.state = FSM_IDLE;
337 break;
338 }
339 break;
340 case FSM_TAP:
341 switch (event) {
342 case FSM_EVENT_TIMEOUT:
343 notify_tap(touchpad, time);
344 touchpad->fsm.state = FSM_IDLE;
345 break;
346 case FSM_EVENT_TOUCH:
347 notify_button_pressed(touchpad, time);
348 touchpad->fsm.state = FSM_TAP_2;
349 break;
350 default:
351 touchpad->fsm.state = FSM_IDLE;
352 break;
353 }
354 break;
355 case FSM_TAP_2:
356 switch (event) {
357 case FSM_EVENT_MOTION:
358 touchpad->fsm.state = FSM_DRAG;
359 break;
360 case FSM_EVENT_RELEASE:
361 notify_button_released(touchpad, time);
362 notify_tap(touchpad, time);
363 touchpad->fsm.state = FSM_IDLE;
364 break;
365 default:
366 touchpad->fsm.state = FSM_IDLE;
367 break;
368 }
369 break;
370 case FSM_DRAG:
371 switch (event) {
372 case FSM_EVENT_RELEASE:
373 notify_button_released(touchpad, time);
374 touchpad->fsm.state = FSM_IDLE;
375 break;
376 default:
377 touchpad->fsm.state = FSM_IDLE;
378 break;
379 }
380 break;
381 default:
382 weston_log("evdev-touchpad: Unknown state %d",
383 touchpad->fsm.state);
384 touchpad->fsm.state = FSM_IDLE;
385 break;
386 }
387 }
388
389 if (timeout != UINT32_MAX)
390 wl_event_source_timer_update(touchpad->fsm.timer_source,
391 timeout);
392
393 wl_array_release(&touchpad->fsm.events);
394 wl_array_init(&touchpad->fsm.events);
395}
396
397static void
398push_fsm_event(struct touchpad_dispatch *touchpad,
399 enum fsm_event event)
400{
401 enum fsm_event *pevent;
402
Jonas Ådahl848e2e62013-03-22 08:41:42 +0100403 if (!touchpad->fsm.enable)
404 return;
405
Jonas Ådahl87b07352012-09-27 18:40:40 +0200406 pevent = wl_array_add(&touchpad->fsm.events, sizeof event);
407 if (pevent)
408 *pevent = event;
409 else
410 touchpad->fsm.state = FSM_IDLE;
411}
412
413static int
414fsm_timout_handler(void *data)
415{
416 struct touchpad_dispatch *touchpad = data;
417
418 if (touchpad->fsm.events.size == 0) {
419 push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
420 process_fsm_events(touchpad, weston_compositor_get_time());
421 }
422
423 return 1;
424}
425
426static void
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200427touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
428{
429 int motion_index;
430 int center_x, center_y;
Jonas Ådahlc6894932012-09-27 18:40:39 +0200431 double dx = 0.0, dy = 0.0;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200432
433 if (touchpad->reset ||
434 touchpad->last_finger_state != touchpad->finger_state) {
435 touchpad->reset = 0;
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;
440
441 touchpad->last_finger_state = touchpad->finger_state;
442
Jonas Ådahl87b07352012-09-27 18:40:40 +0200443 process_fsm_events(touchpad, time);
444
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200445 return;
446 }
447 touchpad->last_finger_state = touchpad->finger_state;
448
449 if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT))
450 return;
451 else
452 touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT;
453
454 if ((touchpad->event_mask & touchpad->event_mask_filter) !=
455 touchpad->event_mask_filter)
456 return;
457
458 touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY;
459 touchpad->event_mask = 0;
460
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);
Jonas Ådahlc6894932012-09-27 18:40:39 +0200470 } else {
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200471 center_x = touchpad->hw_abs.x;
472 center_y = touchpad->hw_abs.y;
473 }
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;
478
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++;
486
487 if (touchpad->motion_count >= 4) {
488 touchpad_get_delta(touchpad, &dx, &dy);
489
490 filter_motion(touchpad, &dx, &dy, time);
491
Jonas Ådahld9f58192012-09-27 18:40:43 +0200492 if (touchpad->finger_state == TOUCHPAD_FINGERS_ONE) {
Neil Robertsdaf7d472013-09-24 12:09:03 +0100493 notify_motion(touchpad->device->seat, time,
494 wl_fixed_from_double(dx),
495 wl_fixed_from_double(dy));
Jonas Ådahld9f58192012-09-27 18:40:43 +0200496 } else if (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) {
497 if (dx != 0.0)
498 notify_axis(touchpad->device->seat,
499 time,
500 WL_POINTER_AXIS_HORIZONTAL_SCROLL,
501 wl_fixed_from_double(dx));
502 if (dy != 0.0)
503 notify_axis(touchpad->device->seat,
504 time,
505 WL_POINTER_AXIS_VERTICAL_SCROLL,
506 wl_fixed_from_double(dy));
507 }
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200508 }
Jonas Ådahlc6894932012-09-27 18:40:39 +0200509
510 if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
511 ((int)dx || (int)dy)) {
512 touchpad->state |= TOUCHPAD_STATE_MOVE;
Jonas Ådahl87b07352012-09-27 18:40:40 +0200513 push_fsm_event(touchpad, FSM_EVENT_MOTION);
Jonas Ådahlc6894932012-09-27 18:40:39 +0200514 }
Jonas Ådahl87b07352012-09-27 18:40:40 +0200515
516 process_fsm_events(touchpad, time);
Jonas Ådahlc6894932012-09-27 18:40:39 +0200517}
518
519static void
520on_touch(struct touchpad_dispatch *touchpad)
521{
522 touchpad->state |= TOUCHPAD_STATE_TOUCH;
Jonas Ådahl87b07352012-09-27 18:40:40 +0200523
524 push_fsm_event(touchpad, FSM_EVENT_TOUCH);
Jonas Ådahlc6894932012-09-27 18:40:39 +0200525}
526
527static void
528on_release(struct touchpad_dispatch *touchpad)
529{
530
531 touchpad->reset = 1;
532 touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
Jonas Ådahl87b07352012-09-27 18:40:40 +0200533
534 push_fsm_event(touchpad, FSM_EVENT_RELEASE);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200535}
536
537static inline void
538process_absolute(struct touchpad_dispatch *touchpad,
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300539 struct evdev_device *device,
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200540 struct input_event *e)
541{
542 switch (e->code) {
543 case ABS_PRESSURE:
Jonas Ådahlc6894932012-09-27 18:40:39 +0200544 if (e->value > touchpad->pressure.touch_high &&
545 !(touchpad->state & TOUCHPAD_STATE_TOUCH))
546 on_touch(touchpad);
547 else if (e->value < touchpad->pressure.touch_low &&
548 touchpad->state & TOUCHPAD_STATE_TOUCH)
549 on_release(touchpad);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200550
551 break;
552 case ABS_X:
Jonas Ådahlc6894932012-09-27 18:40:39 +0200553 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200554 touchpad->hw_abs.x = e->value;
555 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
556 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X;
557 }
558 break;
559 case ABS_Y:
Jonas Ådahlc6894932012-09-27 18:40:39 +0200560 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200561 touchpad->hw_abs.y = e->value;
562 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
563 touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y;
564 }
565 break;
566 }
567}
568
569static inline void
570process_key(struct touchpad_dispatch *touchpad,
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300571 struct evdev_device *device,
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200572 struct input_event *e,
573 uint32_t time)
574{
Kristian Høgsberg3bdaa3e2013-07-01 12:48:55 -0400575 uint32_t code;
576
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200577 switch (e->code) {
578 case BTN_TOUCH:
579 if (!touchpad->has_pressure) {
Jonas Ådahlc6894932012-09-27 18:40:39 +0200580 if (e->value && !(touchpad->state & TOUCHPAD_STATE_TOUCH))
581 on_touch(touchpad);
582 else if (!e->value)
583 on_release(touchpad);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200584 }
585 break;
586 case BTN_LEFT:
587 case BTN_RIGHT:
588 case BTN_MIDDLE:
589 case BTN_SIDE:
590 case BTN_EXTRA:
591 case BTN_FORWARD:
592 case BTN_BACK:
593 case BTN_TASK:
Kristian Høgsberg3bdaa3e2013-07-01 12:48:55 -0400594 if (!touchpad->fsm.enable && e->code == BTN_LEFT &&
595 touchpad->finger_state == TOUCHPAD_FINGERS_TWO)
596 code = BTN_RIGHT;
597 else
598 code = e->code;
599 notify_button(device->seat, time, code,
Daniel Stone4dbadb12012-05-30 16:31:51 +0100600 e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
601 WL_POINTER_BUTTON_STATE_RELEASED);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200602 break;
603 case BTN_TOOL_PEN:
604 case BTN_TOOL_RUBBER:
605 case BTN_TOOL_BRUSH:
606 case BTN_TOOL_PENCIL:
607 case BTN_TOOL_AIRBRUSH:
608 case BTN_TOOL_MOUSE:
609 case BTN_TOOL_LENS:
610 touchpad->reset = 1;
611 break;
612 case BTN_TOOL_FINGER:
Rob Bradford3de191e2012-10-09 18:44:29 +0100613 if (e->value)
614 touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
Jonas Ådahld9f58192012-09-27 18:40:43 +0200615 else
616 touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200617 break;
618 case BTN_TOOL_DOUBLETAP:
Rob Bradford3de191e2012-10-09 18:44:29 +0100619 if (e->value)
620 touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
Jonas Ådahld9f58192012-09-27 18:40:43 +0200621 else
622 touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200623 break;
624 case BTN_TOOL_TRIPLETAP:
Rob Bradford3de191e2012-10-09 18:44:29 +0100625 if (e->value)
626 touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
Jonas Ådahld9f58192012-09-27 18:40:43 +0200627 else
628 touchpad->finger_state &= ~TOUCHPAD_FINGERS_THREE;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200629 break;
630 }
631}
632
633static void
634touchpad_process(struct evdev_dispatch *dispatch,
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300635 struct evdev_device *device,
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200636 struct input_event *e,
637 uint32_t time)
638{
639 struct touchpad_dispatch *touchpad =
640 (struct touchpad_dispatch *) dispatch;
641
642 switch (e->type) {
643 case EV_SYN:
644 if (e->code == SYN_REPORT)
645 touchpad->event_mask |= TOUCHPAD_EVENT_REPORT;
646 break;
647 case EV_ABS:
648 process_absolute(touchpad, device, e);
649 break;
650 case EV_KEY:
651 process_key(touchpad, device, e, time);
652 break;
653 }
654
655 touchpad_update_state(touchpad, time);
656}
657
658static void
659touchpad_destroy(struct evdev_dispatch *dispatch)
660{
661 struct touchpad_dispatch *touchpad =
662 (struct touchpad_dispatch *) dispatch;
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200663
Jonas Ådahlc6894932012-09-27 18:40:39 +0200664 touchpad->filter->interface->destroy(touchpad->filter);
Jonas Ådahl87b07352012-09-27 18:40:40 +0200665 wl_event_source_remove(touchpad->fsm.timer_source);
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200666 free(dispatch);
667}
668
669struct evdev_dispatch_interface touchpad_interface = {
670 touchpad_process,
671 touchpad_destroy
672};
673
Armin Kb502f902013-07-31 01:41:03 +0200674static void
675touchpad_parse_config(struct touchpad_dispatch *touchpad, double diagonal)
676{
Kristian Høgsberg037bdc42013-08-29 13:49:35 -0700677 struct weston_compositor *compositor =
678 touchpad->device->seat->compositor;
Armin Kb502f902013-07-31 01:41:03 +0200679 struct weston_config_section *s;
Armin Kb502f902013-07-31 01:41:03 +0200680 double constant_accel_factor;
681 double min_accel_factor;
682 double max_accel_factor;
683
Kristian Høgsberg037bdc42013-08-29 13:49:35 -0700684 s = weston_config_get_section(compositor->config,
685 "touchpad", NULL, NULL);
Armin Kb502f902013-07-31 01:41:03 +0200686 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",
690 &min_accel_factor,
691 DEFAULT_MIN_ACCEL_FACTOR);
692 weston_config_section_get_double(s, "max_accel_factor",
693 &max_accel_factor,
694 DEFAULT_MAX_ACCEL_FACTOR);
695
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;
700}
701
Jonas Ådahlc6894932012-09-27 18:40:39 +0200702static int
703touchpad_init(struct touchpad_dispatch *touchpad,
704 struct evdev_device *device)
705{
706 struct weston_motion_filter *accel;
Jonas Ådahl87b07352012-09-27 18:40:40 +0200707 struct wl_event_loop *loop;
Jonas Ådahlc6894932012-09-27 18:40:39 +0200708
Jonas Ådahl848e2e62013-03-22 08:41:42 +0100709 unsigned long prop_bits[INPUT_PROP_MAX];
Jonas Ådahlc6894932012-09-27 18:40:39 +0200710 struct input_absinfo absinfo;
711 unsigned long abs_bits[NBITS(ABS_MAX)];
712
Jonas Ådahl848e2e62013-03-22 08:41:42 +0100713 bool has_buttonpad;
714
Jonas Ådahlc6894932012-09-27 18:40:39 +0200715 double width;
716 double height;
717 double diagonal;
718
719 touchpad->base.interface = &touchpad_interface;
720 touchpad->device = device;
721
722 /* Detect model */
723 touchpad->model = get_touchpad_model(device);
724
Jonas Ådahl848e2e62013-03-22 08:41:42 +0100725 ioctl(device->fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits);
726 has_buttonpad = TEST_BIT(prop_bits, INPUT_PROP_BUTTONPAD);
727
Jonas Ådahlc6894932012-09-27 18:40:39 +0200728 /* 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,
733 absinfo.minimum,
734 absinfo.maximum);
735 }
736
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);
741
Armin Kb502f902013-07-31 01:41:03 +0200742 touchpad_parse_config(touchpad, diagonal);
Jonas Ådahlc6894932012-09-27 18:40:39 +0200743
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;
750
751 /* Configure acceleration profile */
752 accel = create_pointer_accelator_filter(touchpad_profile);
753 if (accel == NULL)
754 return -1;
755 touchpad->filter = accel;
756
757 /* Setup initial state */
758 touchpad->reset = 1;
759
760 memset(touchpad->motion_history, 0, sizeof touchpad->motion_history);
761 touchpad->motion_index = 0;
762 touchpad->motion_count = 0;
763
764 touchpad->state = TOUCHPAD_STATE_NONE;
765 touchpad->last_finger_state = 0;
766 touchpad->finger_state = 0;
767
Jonas Ådahl87b07352012-09-27 18:40:40 +0200768 wl_array_init(&touchpad->fsm.events);
769 touchpad->fsm.state = FSM_IDLE;
770
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);
776 return -1;
777 }
778
Jonas Ådahl848e2e62013-03-22 08:41:42 +0100779 /* Configure */
780 touchpad->fsm.enable = !has_buttonpad;
781
Jonas Ådahlc6894932012-09-27 18:40:39 +0200782 return 0;
783}
784
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200785struct evdev_dispatch *
Pekka Paalanen3eb47612012-08-06 14:57:08 +0300786evdev_touchpad_create(struct evdev_device *device)
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200787{
788 struct touchpad_dispatch *touchpad;
789
790 touchpad = malloc(sizeof *touchpad);
791 if (touchpad == NULL)
792 return NULL;
793
Jonas Ådahlc6894932012-09-27 18:40:39 +0200794 if (touchpad_init(touchpad, device) != 0) {
795 free(touchpad);
796 return NULL;
797 }
Jonas Ådahl1df17af2012-05-17 12:18:17 +0200798
799 return &touchpad->base;
800}