touchpad: Only move the pointer when there's a single finger down
[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 (tp->scroll.state == SCROLL_STATE_NONE) {
314                 /* Require at least one px scrolling to start */
315                 if (dx <= -1.0 || dx >= 1.0) {
316                         tp->scroll.state = SCROLL_STATE_SCROLLING;
317                         tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL);
318                 }
319
320                 if (dy <= -1.0 || dy >= 1.0) {
321                         tp->scroll.state = SCROLL_STATE_SCROLLING;
322                         tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL);
323                 }
324
325                 if (tp->scroll.state == SCROLL_STATE_NONE)
326                         return;
327         }
328
329         if (dy != 0.0 &&
330             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL))) {
331                 pointer_notify_axis(&tp->device->base,
332                                     time,
333                                     LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL,
334                                     li_fixed_from_double(dy));
335         }
336
337         if (dx != 0.0 &&
338             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL))) {
339                 pointer_notify_axis(&tp->device->base,
340                                     time,
341                                     LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL,
342                                     li_fixed_from_double(dx));
343         }
344 }
345
346 static int
347 tp_post_scroll_events(struct tp_dispatch *tp, uint32_t time)
348 {
349         if (tp->nfingers_down != 2) {
350                 /* terminate scrolling with a zero scroll event to notify
351                  * caller that it really ended now */
352                 if (tp->scroll.state != SCROLL_STATE_NONE) {
353                         tp->scroll.state = SCROLL_STATE_NONE;
354                         tp->scroll.direction = 0;
355                         if (tp->scroll.direction & LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL)
356                                 pointer_notify_axis(&tp->device->base,
357                                                     time,
358                                                     LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL,
359                                                     0);
360                         if (tp->scroll.direction & LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL)
361                                 pointer_notify_axis(&tp->device->base,
362                                                     time,
363                                                     LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL,
364                                                     0);
365                 }
366         } else {
367                 tp_post_twofinger_scroll(tp, time);
368                 return 1;
369         }
370         return 0;
371 }
372
373 static void
374 tp_post_button_events(struct tp_dispatch *tp, uint32_t time)
375 {
376         uint32_t current, old, button;
377
378         if ((tp->queued &
379                 (TOUCHPAD_EVENT_BUTTON_PRESS|TOUCHPAD_EVENT_BUTTON_RELEASE)) == 0)
380                                 return;
381
382         current = tp->buttons.state;
383         old = tp->buttons.old_state;
384         button = BTN_LEFT;
385
386         while (current || old) {
387                 enum libinput_pointer_button_state state;
388
389                 if ((current & 0x1) ^ (old & 0x1)) {
390                         if (!!(current & 0x1))
391                                 state = LIBINPUT_POINTER_BUTTON_STATE_PRESSED;
392                         else
393                                 state = LIBINPUT_POINTER_BUTTON_STATE_RELEASED;
394
395                         pointer_notify_button(&tp->device->base,
396                                               time,
397                                               button,
398                                               state);
399                 }
400
401                 button++;
402                 current >>= 1;
403                 old >>= 1;
404         }
405 }
406
407 static void
408 tp_post_events(struct tp_dispatch *tp, uint32_t time)
409 {
410         struct tp_touch *t = tp_current_touch(tp);
411         double dx, dy;
412
413         if (tp_tap_handle_state(tp, time) != 0)
414                 return;
415
416         if (tp_post_scroll_events(tp, time) != 0)
417                 return;
418
419         if (t->history.count >= TOUCHPAD_MIN_SAMPLES &&
420             tp->nfingers_down == 1) {
421                 tp_get_delta(t, &dx, &dy);
422                 tp_filter_motion(tp, &dx, &dy, time);
423
424                 if (dx != 0 || dy != 0)
425                         pointer_notify_motion(
426                                 &tp->device->base,
427                                 time,
428                                 li_fixed_from_double(dx),
429                                 li_fixed_from_double(dy));
430         }
431
432         tp_post_button_events(tp, time);
433 }
434
435 static void
436 tp_process(struct evdev_dispatch *dispatch,
437            struct evdev_device *device,
438            struct input_event *e,
439            uint32_t time)
440 {
441         struct tp_dispatch *tp =
442                 (struct tp_dispatch *)dispatch;
443
444         switch (e->type) {
445         case EV_ABS:
446                 tp_process_absolute(tp, e, time);
447                 break;
448         case EV_KEY:
449                 tp_process_key(tp, e, time);
450                 break;
451         case EV_SYN:
452                 tp_process_state(tp, time);
453                 tp_post_events(tp, time);
454                 tp_post_process_state(tp, time);
455                 break;
456         }
457 }
458
459 static void
460 tp_destroy(struct evdev_dispatch *dispatch)
461 {
462         struct tp_dispatch *tp =
463                 (struct tp_dispatch*)dispatch;
464
465         if (tp->filter)
466                 tp->filter->interface->destroy(tp->filter);
467         free(tp->touches);
468         free(tp);
469 }
470
471 static struct evdev_dispatch_interface tp_interface = {
472         tp_process,
473         tp_destroy
474 };
475
476 static int
477 tp_init_slots(struct tp_dispatch *tp,
478               struct evdev_device *device)
479 {
480         struct input_absinfo absinfo = {0};
481
482         ioctl(device->fd, EVIOCGABS(ABS_MT_SLOT), &absinfo);
483
484         tp->ntouches = absinfo.maximum + 1;
485         tp->touches = calloc(tp->ntouches,
486                              sizeof(struct tp_touch));
487         tp->slot = absinfo.value;
488
489         return 0;
490 }
491
492 static int
493 tp_init_accel(struct tp_dispatch *touchpad, double diagonal)
494 {
495         struct motion_filter *accel;
496
497         touchpad->accel.constant_factor =
498                 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
499         touchpad->accel.min_factor = DEFAULT_MIN_ACCEL_FACTOR;
500         touchpad->accel.max_factor = DEFAULT_MAX_ACCEL_FACTOR;
501
502         accel = create_pointer_accelator_filter(tp_accel_profile);
503         if (accel == NULL)
504                 return -1;
505
506         touchpad->filter = accel;
507
508         return 0;
509 }
510
511 static int
512 tp_init_scroll(struct tp_dispatch *tp)
513 {
514         tp->scroll.direction = 0;
515         tp->scroll.state = SCROLL_STATE_NONE;
516
517         return 0;
518 }
519
520 static int
521 tp_init(struct tp_dispatch *tp,
522         struct evdev_device *device)
523 {
524         int width, height;
525         double diagonal;
526
527         tp->base.interface = &tp_interface;
528         tp->device = device;
529
530         if (tp_init_slots(tp, device) != 0)
531                 return -1;
532
533         width = abs(device->abs.max_x - device->abs.min_x);
534         height = abs(device->abs.max_y - device->abs.min_y);
535         diagonal = sqrt(width*width + height*height);
536
537         tp->hysteresis.margin_x =
538                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
539         tp->hysteresis.margin_y =
540                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
541
542         if (tp_init_scroll(tp) != 0)
543                 return -1;
544
545         if (tp_init_accel(tp, diagonal) != 0)
546                 return -1;
547
548         if (tp_init_tap(tp) != 0)
549                 return -1;
550
551         return 0;
552 }
553
554 struct evdev_dispatch *
555 evdev_mt_touchpad_create(struct evdev_device *device)
556 {
557         struct tp_dispatch *tp;
558
559         tp = zalloc(sizeof *tp);
560         if (!tp)
561                 return NULL;
562
563         if (tp_init(tp, device) != 0) {
564                 tp_destroy(&tp->base);
565                 return NULL;
566         }
567
568         return  &tp->base;
569 }