touchpad: add support for multi-finger tapping
[platform/upstream/libinput.git] / src / evdev-mt-touchpad.c
1 /*
2  * Copyright © 2014 Red Hat, Inc.
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
23 #include "config.h"
24
25 #include <assert.h>
26 #include <math.h>
27 #include <stdbool.h>
28
29 #include "evdev-mt-touchpad.h"
30
31 #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50
32 #define DEFAULT_MIN_ACCEL_FACTOR 0.16
33 #define DEFAULT_MAX_ACCEL_FACTOR 1.0
34 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
35
36 static inline int
37 tp_hysteresis(int in, int center, int margin)
38 {
39         int diff = in - center;
40         if (abs(diff) <= margin)
41                 return center;
42
43         if (diff > margin)
44                 return center + diff - margin;
45         else if (diff < -margin)
46                 return center + diff + margin;
47         return center + diff;
48 }
49
50 static double
51 tp_accel_profile(struct motion_filter *filter,
52                  void *data,
53                  double velocity,
54                  uint32_t time)
55 {
56         struct tp_dispatch *tp =
57                 (struct tp_dispatch *) data;
58
59         double accel_factor;
60
61         accel_factor = velocity * tp->accel.constant_factor;
62
63         if (accel_factor > tp->accel.max_factor)
64                 accel_factor = tp->accel.max_factor;
65         else if (accel_factor < tp->accel.min_factor)
66                 accel_factor = tp->accel.min_factor;
67
68         return accel_factor;
69 }
70
71 static inline struct tp_motion *
72 tp_motion_history_offset(struct tp_touch *t, int offset)
73 {
74         int offset_index =
75                 (t->history.index - offset + TOUCHPAD_HISTORY_LENGTH) %
76                 TOUCHPAD_HISTORY_LENGTH;
77
78         return &t->history.samples[offset_index];
79 }
80
81 static void
82 tp_filter_motion(struct tp_dispatch *tp,
83                  double *dx, double *dy, uint32_t time)
84 {
85         struct motion_params motion;
86
87         motion.dx = *dx;
88         motion.dy = *dy;
89
90         filter_dispatch(tp->filter, &motion, tp, time);
91
92         *dx = motion.dx;
93         *dy = motion.dy;
94 }
95
96 static inline void
97 tp_motion_history_push(struct tp_touch *t)
98 {
99         int motion_index = (t->history.index + 1) % TOUCHPAD_HISTORY_LENGTH;
100
101         if (t->history.count < TOUCHPAD_HISTORY_LENGTH)
102                 t->history.count++;
103
104         t->history.samples[motion_index].x = t->x;
105         t->history.samples[motion_index].y = t->y;
106         t->history.index = motion_index;
107 }
108
109 static inline void
110 tp_motion_hysteresis(struct tp_dispatch *tp,
111                      struct tp_touch *t)
112 {
113         int x = t->x,
114             y = t->y;
115
116         if (t->history.count == 0) {
117                 t->hysteresis.center_x = t->x;
118                 t->hysteresis.center_y = t->y;
119         } else {
120                 x = tp_hysteresis(x,
121                                   t->hysteresis.center_x,
122                                   tp->hysteresis.margin_x);
123                 y = tp_hysteresis(y,
124                                   t->hysteresis.center_y,
125                                   tp->hysteresis.margin_y);
126                 t->hysteresis.center_x = x;
127                 t->hysteresis.center_y = y;
128                 t->x = x;
129                 t->y = y;
130         }
131 }
132
133 static inline void
134 tp_motion_history_reset(struct tp_touch *t)
135 {
136         t->history.count = 0;
137 }
138
139 static inline struct tp_touch *
140 tp_current_touch(struct tp_dispatch *tp)
141 {
142         return &tp->touches[min(tp->slot, tp->ntouches)];
143 }
144
145 static inline void
146 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
147 {
148         if (t->state != TOUCH_UPDATE) {
149                 tp_motion_history_reset(t);
150                 t->dirty = true;
151                 t->state = TOUCH_BEGIN;
152                 tp->nfingers_down++;
153                 assert(tp->nfingers_down >= 1);
154                 tp->queued |= TOUCHPAD_EVENT_MOTION;
155         }
156 }
157
158 static inline void
159 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
160 {
161         if (t->state == TOUCH_NONE)
162                 return;
163
164         t->dirty = true;
165         t->state = TOUCH_END;
166         assert(tp->nfingers_down >= 1);
167         tp->nfingers_down--;
168         tp->queued |= TOUCHPAD_EVENT_MOTION;
169 }
170
171 static double
172 tp_estimate_delta(int x0, int x1, int x2, int x3)
173 {
174         return (x0 + x1 - x2 - x3) / 4;
175 }
176
177 void
178 tp_get_delta(struct tp_touch *t, double *dx, double *dy)
179 {
180         if (t->history.count < 4) {
181                 *dx = 0;
182                 *dy = 0;
183                 return;
184         }
185
186         *dx = tp_estimate_delta(tp_motion_history_offset(t, 0)->x,
187                                 tp_motion_history_offset(t, 1)->x,
188                                 tp_motion_history_offset(t, 2)->x,
189                                 tp_motion_history_offset(t, 3)->x);
190         *dy = tp_estimate_delta(tp_motion_history_offset(t, 0)->y,
191                                 tp_motion_history_offset(t, 1)->y,
192                                 tp_motion_history_offset(t, 2)->y,
193                                 tp_motion_history_offset(t, 3)->y);
194 }
195
196 static void
197 tp_process_absolute(struct tp_dispatch *tp,
198                     const struct input_event *e,
199                     uint32_t time)
200 {
201         struct tp_touch *t = tp_current_touch(tp);
202
203         switch(e->code) {
204         case ABS_MT_POSITION_X:
205                 t->x = e->value;
206                 t->millis = time;
207                 t->dirty = true;
208                 tp->queued |= TOUCHPAD_EVENT_MOTION;
209                 break;
210         case ABS_MT_POSITION_Y:
211                 t->y = e->value;
212                 t->millis = time;
213                 t->dirty = true;
214                 tp->queued |= TOUCHPAD_EVENT_MOTION;
215                 break;
216         case ABS_MT_SLOT:
217                 tp->slot = e->value;
218                 break;
219         case ABS_MT_TRACKING_ID:
220                 t->millis = time;
221                 if (e->value != -1)
222                         tp_begin_touch(tp, t);
223                 else
224                         tp_end_touch(tp, t);
225         }
226 }
227
228 static void
229 tp_process_key(struct tp_dispatch *tp,
230                const struct input_event *e,
231                uint32_t time)
232 {
233         uint32_t mask;
234
235         switch (e->code) {
236                 case BTN_LEFT:
237                 case BTN_MIDDLE:
238                 case BTN_RIGHT:
239                         mask = 1 << (e->code - BTN_LEFT);
240                         if (e->value) {
241                                 tp->buttons.state |= mask;
242                                 tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS;
243                         } else {
244                                 tp->buttons.state &= ~mask;
245                                 tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
246                         }
247                         break;
248         }
249 }
250
251 static void
252 tp_process_state(struct tp_dispatch *tp, uint32_t time)
253 {
254         struct tp_touch *t;
255
256         tp_for_each_touch(tp, t) {
257                 if (!t->dirty)
258                         continue;
259
260                 tp_motion_hysteresis(tp, t);
261                 tp_motion_history_push(t);
262         }
263 }
264
265 static void
266 tp_post_process_state(struct tp_dispatch *tp, uint32_t time)
267 {
268         struct tp_touch *t;
269
270         tp_for_each_touch(tp, t) {
271                 if (!t->dirty)
272                         continue;
273
274                 if (t->state == TOUCH_END)
275                         t->state = TOUCH_NONE;
276                 else if (t->state == TOUCH_BEGIN)
277                         t->state = TOUCH_UPDATE;
278
279                 t->dirty = false;
280         }
281
282         tp->buttons.old_state = tp->buttons.state;
283
284         tp->queued = TOUCHPAD_EVENT_NONE;
285 }
286
287 static void
288 tp_post_twofinger_scroll(struct tp_dispatch *tp, uint32_t time)
289 {
290         struct tp_touch *t;
291         int nchanged = 0;
292         double dx = 0, dy =0;
293         double tmpx, tmpy;
294
295         tp_for_each_touch(tp, t) {
296                 if (t->dirty) {
297                         nchanged++;
298                         tp_get_delta(t, &tmpx, &tmpy);
299
300                         dx += tmpx;
301                         dy += tmpy;
302                 }
303         }
304
305         if (nchanged == 0)
306                 return;
307
308         dx /= nchanged;
309         dy /= nchanged;
310
311         tp_filter_motion(tp, &dx, &dy, time);
312
313         if (dx != 0.0)
314                 pointer_notify_axis(&tp->device->base,
315                                     time,
316                                     LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL,
317                                     li_fixed_from_double(dx));
318         if (dy != 0.0)
319                 pointer_notify_axis(&tp->device->base,
320                                     time,
321                                     LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL,
322                                     li_fixed_from_double(dy));
323 }
324
325 static void
326 tp_post_button_events(struct tp_dispatch *tp, uint32_t time)
327 {
328         uint32_t current, old, button;
329
330         if ((tp->queued &
331                 (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0)
332                                 return;
333
334         current = tp->buttons.state;
335         old = tp->buttons.old_state;
336         button = BTN_LEFT;
337
338         while (current || old) {
339                 enum libinput_pointer_button_state state;
340
341                 if ((current & 0x1) ^ (old & 0x1)) {
342                         if (!!(current & 0x1))
343                                 state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED;
344                         else
345                                 state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED;
346
347                         pointer_notify_button(&tp->device->base,
348                                               time,
349                                               button,
350                                               state);
351                 }
352
353                 button++;
354                 current >>= 1;
355                 old >>= 1;
356         }
357 }
358
359 static void
360 tp_post_events(struct tp_dispatch *tp, uint32_t time)
361 {
362         struct tp_touch *t = tp_current_touch(tp);
363         double dx, dy;
364
365         if (tp->nfingers_down > 2) {
366                 return;
367         } else if (tp->nfingers_down == 2) {
368                 tp_post_twofinger_scroll(tp, time);
369                 return;
370         }
371
372         tp_tap_handle_state(tp, time);
373
374         if (t->history.count < 4)
375                 return;
376
377         tp_get_delta(t, &dx, &dy);
378         tp_filter_motion(tp, &dx, &dy, time);
379
380         if (dx != 0 || dy != 0)
381                 pointer_notify_motion(
382                         &tp->device->base,
383                         time,
384                         li_fixed_from_double(dx),
385                         li_fixed_from_double(dy));
386
387         tp_post_button_events(tp, time);
388 }
389
390 static void
391 tp_process(struct evdev_dispatch *dispatch,
392            struct evdev_device *device,
393            struct input_event *e,
394            uint32_t time)
395 {
396         struct tp_dispatch *tp =
397                 (struct tp_dispatch *)dispatch;
398
399         switch (e->type) {
400         case EV_ABS:
401                 tp_process_absolute(tp, e, time);
402                 break;
403         case EV_KEY:
404                 tp_process_key(tp, e, time);
405                 break;
406         case EV_SYN:
407                 tp_process_state(tp, time);
408                 tp_post_events(tp, time);
409                 tp_post_process_state(tp, time);
410                 break;
411         }
412 }
413
414 static void
415 tp_destroy(struct evdev_dispatch *dispatch)
416 {
417         struct tp_dispatch *tp =
418                 (struct tp_dispatch*)dispatch;
419
420         if (tp->filter)
421                 tp->filter->interface->destroy(tp->filter);
422         free(tp->touches);
423         free(tp);
424 }
425
426 static struct evdev_dispatch_interface tp_interface = {
427         tp_process,
428         tp_destroy
429 };
430
431 static int
432 tp_init_slots(struct tp_dispatch *tp,
433               struct evdev_device *device)
434 {
435         struct input_absinfo absinfo = {0};
436
437         ioctl(device->fd, EVIOCGABS(ABS_MT_SLOT), &absinfo);
438
439         tp->ntouches = absinfo.maximum + 1;
440         tp->touches = calloc(tp->ntouches,
441                              sizeof(struct tp_touch));
442         tp->slot = absinfo.value;
443
444         return 0;
445 }
446
447 static int
448 tp_init_accel(struct tp_dispatch *touchpad, double diagonal)
449 {
450         struct motion_filter *accel;
451
452         touchpad->accel.constant_factor =
453                 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
454         touchpad->accel.min_factor = DEFAULT_MIN_ACCEL_FACTOR;
455         touchpad->accel.max_factor = DEFAULT_MAX_ACCEL_FACTOR;
456
457         accel = create_pointer_accelator_filter(tp_accel_profile);
458         if (accel == NULL)
459                 return -1;
460
461         touchpad->filter = accel;
462
463         return 0;
464 }
465
466 static int
467 tp_init(struct tp_dispatch *tp,
468         struct evdev_device *device)
469 {
470         int width, height;
471         double diagonal;
472
473         tp->base.interface = &tp_interface;
474         tp->device = device;
475
476         if (tp_init_slots(tp, device) != 0)
477                 return -1;
478
479         width = abs(device->abs.max_x - device->abs.min_x);
480         height = abs(device->abs.max_y - device->abs.min_y);
481         diagonal = sqrt(width*width + height*height);
482
483         tp->hysteresis.margin_x =
484                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
485         tp->hysteresis.margin_y =
486                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
487
488         if (tp_init_accel(tp, diagonal) != 0)
489                 return -1;
490
491         if (tp_init_tap(tp) != 0)
492                 return -1;
493
494         return 0;
495 }
496
497 struct evdev_dispatch *
498 evdev_mt_touchpad_create(struct evdev_device *device)
499 {
500         struct tp_dispatch *tp;
501
502         tp = zalloc(sizeof *tp);
503         if (!tp)
504                 return NULL;
505
506         if (tp_init(tp, device) != 0) {
507                 tp_destroy(&tp->base);
508                 return NULL;
509         }
510
511         return  &tp->base;
512 }