touchpad: Avoid spurious motion event for scroll movement below threshold
[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 100
32 #define DEFAULT_MIN_ACCEL_FACTOR 0.20
33 #define DEFAULT_MAX_ACCEL_FACTOR 0.40
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                  uint64_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, uint64_t time)
84 {
85         struct motion_params motion;
86
87         motion.dx = *dx * tp->accel.x_scale_coeff;
88         motion.dy = *dy * tp->accel.y_scale_coeff;
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 - 1)];
143 }
144
145 static inline struct tp_touch *
146 tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
147 {
148         assert(slot < tp->ntouches);
149         return &tp->touches[slot];
150 }
151
152 static inline void
153 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
154 {
155         if (t->state != TOUCH_UPDATE) {
156                 tp_motion_history_reset(t);
157                 t->dirty = true;
158                 t->state = TOUCH_BEGIN;
159                 t->pinned.is_pinned = false;
160                 tp->nfingers_down++;
161                 assert(tp->nfingers_down >= 1);
162                 tp->queued |= TOUCHPAD_EVENT_MOTION;
163         }
164 }
165
166 static inline void
167 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
168 {
169         if (t->state == TOUCH_NONE)
170                 return;
171
172         t->dirty = true;
173         t->is_pointer = false;
174         t->state = TOUCH_END;
175         t->pinned.is_pinned = false;
176         assert(tp->nfingers_down >= 1);
177         tp->nfingers_down--;
178         tp->queued |= TOUCHPAD_EVENT_MOTION;
179 }
180
181 static double
182 tp_estimate_delta(int x0, int x1, int x2, int x3)
183 {
184         return (x0 + x1 - x2 - x3) / 4;
185 }
186
187 void
188 tp_get_delta(struct tp_touch *t, double *dx, double *dy)
189 {
190         if (t->history.count < 4) {
191                 *dx = 0;
192                 *dy = 0;
193                 return;
194         }
195
196         *dx = tp_estimate_delta(tp_motion_history_offset(t, 0)->x,
197                                 tp_motion_history_offset(t, 1)->x,
198                                 tp_motion_history_offset(t, 2)->x,
199                                 tp_motion_history_offset(t, 3)->x);
200         *dy = tp_estimate_delta(tp_motion_history_offset(t, 0)->y,
201                                 tp_motion_history_offset(t, 1)->y,
202                                 tp_motion_history_offset(t, 2)->y,
203                                 tp_motion_history_offset(t, 3)->y);
204 }
205
206 static void
207 tp_process_absolute(struct tp_dispatch *tp,
208                     const struct input_event *e,
209                     uint64_t time)
210 {
211         struct tp_touch *t = tp_current_touch(tp);
212
213         switch(e->code) {
214         case ABS_MT_POSITION_X:
215                 t->x = e->value;
216                 t->millis = time;
217                 t->dirty = true;
218                 tp->queued |= TOUCHPAD_EVENT_MOTION;
219                 break;
220         case ABS_MT_POSITION_Y:
221                 t->y = e->value;
222                 t->millis = time;
223                 t->dirty = true;
224                 tp->queued |= TOUCHPAD_EVENT_MOTION;
225                 break;
226         case ABS_MT_SLOT:
227                 tp->slot = e->value;
228                 break;
229         case ABS_MT_TRACKING_ID:
230                 t->millis = time;
231                 if (e->value != -1)
232                         tp_begin_touch(tp, t);
233                 else
234                         tp_end_touch(tp, t);
235         }
236 }
237
238 static void
239 tp_process_absolute_st(struct tp_dispatch *tp,
240                        const struct input_event *e,
241                        uint64_t time)
242 {
243         struct tp_touch *t = tp_current_touch(tp);
244
245         switch(e->code) {
246         case ABS_X:
247                 t->x = e->value;
248                 t->millis = time;
249                 t->dirty = true;
250                 tp->queued |= TOUCHPAD_EVENT_MOTION;
251                 break;
252         case ABS_Y:
253                 t->y = e->value;
254                 t->millis = time;
255                 t->dirty = true;
256                 tp->queued |= TOUCHPAD_EVENT_MOTION;
257                 break;
258         }
259 }
260
261 static void
262 tp_process_fake_touch(struct tp_dispatch *tp,
263                       const struct input_event *e,
264                       uint64_t time)
265 {
266         struct tp_touch *t;
267         unsigned int fake_touches;
268         unsigned int nfake_touches;
269         unsigned int i;
270         unsigned int shift;
271
272         if (e->code != BTN_TOUCH &&
273             (e->code < BTN_TOOL_DOUBLETAP || e->code > BTN_TOOL_QUADTAP))
274                 return;
275
276         shift = e->code == BTN_TOUCH ? 0 : (e->code - BTN_TOOL_DOUBLETAP + 1);
277
278         if (e->value)
279                 tp->fake_touches |= 1 << shift;
280         else
281                 tp->fake_touches &= ~(0x1 << shift);
282
283         fake_touches = tp->fake_touches;
284         nfake_touches = 0;
285         while (fake_touches) {
286                 nfake_touches++;
287                 fake_touches >>= 1;
288         }
289
290         for (i = 0; i < tp->ntouches; i++) {
291                 t = tp_get_touch(tp, i);
292                 if (i >= nfake_touches) {
293                         if (t->state != TOUCH_NONE) {
294                                 tp_end_touch(tp, t);
295                                 t->millis = time;
296                         }
297                 } else if (t->state != TOUCH_UPDATE &&
298                            t->state != TOUCH_BEGIN) {
299                         t->state = TOUCH_NONE;
300                         tp_begin_touch(tp, t);
301                         t->millis = time;
302                         t->fake =true;
303                 }
304         }
305
306         assert(tp->nfingers_down == nfake_touches);
307 }
308
309 static void
310 tp_process_key(struct tp_dispatch *tp,
311                const struct input_event *e,
312                uint64_t time)
313 {
314         switch (e->code) {
315                 case BTN_LEFT:
316                 case BTN_MIDDLE:
317                 case BTN_RIGHT:
318                         tp_process_button(tp, e, time);
319                         break;
320                 case BTN_TOUCH:
321                 case BTN_TOOL_DOUBLETAP:
322                 case BTN_TOOL_TRIPLETAP:
323                 case BTN_TOOL_QUADTAP:
324                         if (!tp->has_mt)
325                                 tp_process_fake_touch(tp, e, time);
326                         break;
327         }
328 }
329
330 static void
331 tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
332 {
333         unsigned int xdist, ydist;
334
335         if (!t->pinned.is_pinned)
336                 return;
337
338         xdist = abs(t->x - t->pinned.center_x);
339         ydist = abs(t->y - t->pinned.center_y);
340
341         if (xdist * xdist + ydist * ydist >=
342                         tp->buttons.motion_dist * tp->buttons.motion_dist) {
343                 t->pinned.is_pinned = false;
344                 tp_set_pointer(tp, t);
345         }
346 }
347
348 static void
349 tp_pin_fingers(struct tp_dispatch *tp)
350 {
351         struct tp_touch *t;
352
353         tp_for_each_touch(tp, t) {
354                 t->is_pointer = false;
355                 t->pinned.is_pinned = true;
356                 t->pinned.center_x = t->x;
357                 t->pinned.center_y = t->y;
358         }
359 }
360
361 static int
362 tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
363 {
364         return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
365                 !t->pinned.is_pinned && tp_button_touch_active(tp, t);
366 }
367
368 void
369 tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t)
370 {
371         struct tp_touch *tmp = NULL;
372
373         /* Only set the touch as pointer if we don't have one yet */
374         tp_for_each_touch(tp, tmp) {
375                 if (tmp->is_pointer)
376                         return;
377         }
378
379         if (tp_touch_active(tp, t))
380                 t->is_pointer = true;
381 }
382
383 static void
384 tp_process_state(struct tp_dispatch *tp, uint64_t time)
385 {
386         struct tp_touch *t;
387         struct tp_touch *first = tp_get_touch(tp, 0);
388
389         tp_for_each_touch(tp, t) {
390                 if (!tp->has_mt && t != first && first->fake) {
391                         t->x = first->x;
392                         t->y = first->y;
393                         if (!t->dirty)
394                                 t->dirty = first->dirty;
395                 } else if (!t->dirty)
396                         continue;
397
398                 tp_motion_hysteresis(tp, t);
399                 tp_motion_history_push(t);
400
401                 tp_unpin_finger(tp, t);
402         }
403
404         tp_button_handle_state(tp, time);
405
406         /*
407          * We have a physical button down event on a clickpad. To avoid
408          * spurious pointer moves by the clicking finger we pin all fingers.
409          * We unpin fingers when they move more then a certain threshold to
410          * to allow drag and drop.
411          */
412         if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
413             tp->buttons.is_clickpad)
414                 tp_pin_fingers(tp);
415 }
416
417 static void
418 tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
419 {
420         struct tp_touch *t;
421
422         tp_for_each_touch(tp, t) {
423                 if (!t->dirty)
424                         continue;
425
426                 if (t->state == TOUCH_END) {
427                         t->state = TOUCH_NONE;
428                         t->fake = false;
429                 } else if (t->state == TOUCH_BEGIN)
430                         t->state = TOUCH_UPDATE;
431
432                 t->dirty = false;
433         }
434
435         tp->buttons.old_state = tp->buttons.state;
436
437         tp->queued = TOUCHPAD_EVENT_NONE;
438 }
439
440 static void
441 tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
442 {
443         struct tp_touch *t;
444         int nchanged = 0;
445         double dx = 0, dy =0;
446         double tmpx, tmpy;
447
448         tp_for_each_touch(tp, t) {
449                 if (tp_touch_active(tp, t) && t->dirty) {
450                         nchanged++;
451                         tp_get_delta(t, &tmpx, &tmpy);
452
453                         dx += tmpx;
454                         dy += tmpy;
455                 }
456         }
457
458         if (nchanged == 0)
459                 return;
460
461         dx /= nchanged;
462         dy /= nchanged;
463
464         tp_filter_motion(tp, &dx, &dy, time);
465
466         /* Require at least three px scrolling to start */
467         if (dy <= -3.0 || dy >= 3.0)
468                 tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
469
470         if (dx <= -3.0 || dx >= 3.0)
471                 tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
472
473         /* Stop spurious MOTION events at the end of scrolling */
474         tp_for_each_touch(tp, t)
475                 t->is_pointer = false;
476
477         if (dy != 0.0 &&
478             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))) {
479                 pointer_notify_axis(&tp->device->base,
480                                     time,
481                                     LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
482                                     dy);
483         }
484
485         if (dx != 0.0 &&
486             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))) {
487                 pointer_notify_axis(&tp->device->base,
488                                     time,
489                                     LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
490                                     dx);
491         }
492 }
493
494 static void
495 tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time)
496 {
497         /* terminate scrolling with a zero scroll event */
498         if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
499                 pointer_notify_axis(&tp->device->base,
500                                     time,
501                                     LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
502                                     0);
503         if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
504                 pointer_notify_axis(&tp->device->base,
505                                     time,
506                                     LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
507                                     0);
508
509         tp->scroll.direction = 0;
510 }
511
512 static int
513 tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
514 {
515         struct tp_touch *t;
516         int nfingers_down = 0;
517
518         /* Only count active touches for 2 finger scrolling */
519         tp_for_each_touch(tp, t) {
520                 if (tp_touch_active(tp, t))
521                         nfingers_down++;
522         }
523
524         if (nfingers_down != 2) {
525                 tp_stop_scroll_events(tp, time);
526                 return 0;
527         }
528
529         tp_post_twofinger_scroll(tp, time);
530         return 1;
531 }
532
533 static void
534 tp_post_events(struct tp_dispatch *tp, uint64_t time)
535 {
536         struct tp_touch *t = tp_current_touch(tp);
537         double dx, dy;
538         int consumed = 0;
539
540         consumed |= tp_tap_handle_state(tp, time);
541         consumed |= tp_post_button_events(tp, time);
542
543         if (consumed) {
544                 tp_stop_scroll_events(tp, time);
545                 return;
546         }
547
548         if (tp_post_scroll_events(tp, time) != 0)
549                 return;
550
551         if (t->history.count >= TOUCHPAD_MIN_SAMPLES) {
552                 if (!t->is_pointer) {
553                         tp_for_each_touch(tp, t) {
554                                 if (t->is_pointer)
555                                         break;
556                         }
557                 }
558
559                 if (!t->is_pointer)
560                         return;
561
562                 tp_get_delta(t, &dx, &dy);
563                 tp_filter_motion(tp, &dx, &dy, time);
564
565                 if (dx != 0.0 || dy != 0.0)
566                         pointer_notify_motion(&tp->device->base, time, dx, dy);
567         }
568 }
569
570 static void
571 tp_process(struct evdev_dispatch *dispatch,
572            struct evdev_device *device,
573            struct input_event *e,
574            uint64_t time)
575 {
576         struct tp_dispatch *tp =
577                 (struct tp_dispatch *)dispatch;
578
579         switch (e->type) {
580         case EV_ABS:
581                 if (tp->has_mt)
582                         tp_process_absolute(tp, e, time);
583                 else
584                         tp_process_absolute_st(tp, e, time);
585                 break;
586         case EV_KEY:
587                 tp_process_key(tp, e, time);
588                 break;
589         case EV_SYN:
590                 tp_process_state(tp, time);
591                 tp_post_events(tp, time);
592                 tp_post_process_state(tp, time);
593                 break;
594         }
595 }
596
597 static void
598 tp_destroy(struct evdev_dispatch *dispatch)
599 {
600         struct tp_dispatch *tp =
601                 (struct tp_dispatch*)dispatch;
602
603         tp_destroy_tap(tp);
604         tp_destroy_buttons(tp);
605
606         motion_filter_destroy(tp->filter);
607         free(tp->touches);
608         free(tp);
609 }
610
611 static struct evdev_dispatch_interface tp_interface = {
612         tp_process,
613         tp_destroy
614 };
615
616 static void
617 tp_init_touch(struct tp_dispatch *tp,
618               struct tp_touch *t)
619 {
620         t->tp = tp;
621 }
622
623 static int
624 tp_init_slots(struct tp_dispatch *tp,
625               struct evdev_device *device)
626 {
627         size_t i;
628         const struct input_absinfo *absinfo;
629
630         absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
631         if (absinfo) {
632                 tp->ntouches = absinfo->maximum + 1;
633                 tp->slot = absinfo->value;
634                 tp->has_mt = true;
635         } else {
636                 struct map {
637                         unsigned int code;
638                         int ntouches;
639                 } max_touches[] = {
640                         { BTN_TOOL_QUINTTAP, 5 },
641                         { BTN_TOOL_QUADTAP, 4 },
642                         { BTN_TOOL_TRIPLETAP, 3 },
643                         { BTN_TOOL_DOUBLETAP, 2 },
644                 };
645                 struct map *m;
646
647                 tp->slot = 0;
648                 tp->has_mt = false;
649                 tp->ntouches = 1;
650
651                 ARRAY_FOR_EACH(max_touches, m) {
652                         if (libevdev_has_event_code(device->evdev,
653                                                     EV_KEY,
654                                                     m->code)) {
655                                 tp->ntouches = m->ntouches;
656                                 break;
657                         }
658                 }
659         }
660         tp->touches = calloc(tp->ntouches,
661                              sizeof(struct tp_touch));
662         if (!tp->touches)
663                 return -1;
664
665         for (i = 0; i < tp->ntouches; i++)
666                 tp_init_touch(tp, &tp->touches[i]);
667
668         return 0;
669 }
670
671 static void
672 calculate_scale_coefficients(struct tp_dispatch *tp)
673 {
674         int res_x, res_y;
675
676         if (tp->has_mt) {
677                 res_x = libevdev_get_abs_resolution(tp->device->evdev,
678                                                     ABS_MT_POSITION_X);
679                 res_y = libevdev_get_abs_resolution(tp->device->evdev,
680                                                     ABS_MT_POSITION_Y);
681         } else {
682                 res_x = libevdev_get_abs_resolution(tp->device->evdev,
683                                                     ABS_X);
684                 res_y = libevdev_get_abs_resolution(tp->device->evdev,
685                                                     ABS_Y);
686         }
687
688         if (res_x <= 0 || res_y <= 0) {
689                 tp->accel.x_scale_coeff = 1.0;
690                 tp->accel.y_scale_coeff = 1.0;
691         } else if (res_x > res_y) {
692                 tp->accel.x_scale_coeff = res_y / (double) res_x;
693                 tp->accel.y_scale_coeff = 1.0f;
694         } else {
695                 tp->accel.y_scale_coeff = res_x / (double) res_y;
696                 tp->accel.x_scale_coeff = 1.0f;
697         }
698 }
699
700 static int
701 tp_init_accel(struct tp_dispatch *touchpad, double diagonal)
702 {
703         struct motion_filter *accel;
704
705         calculate_scale_coefficients(touchpad);
706
707         touchpad->accel.constant_factor =
708                 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
709         touchpad->accel.min_factor = DEFAULT_MIN_ACCEL_FACTOR;
710         touchpad->accel.max_factor = DEFAULT_MAX_ACCEL_FACTOR;
711
712         accel = create_pointer_accelator_filter(tp_accel_profile);
713         if (accel == NULL)
714                 return -1;
715
716         touchpad->filter = accel;
717
718         return 0;
719 }
720
721 static int
722 tp_init_scroll(struct tp_dispatch *tp)
723 {
724         tp->scroll.direction = 0;
725
726         return 0;
727 }
728
729 static int
730 tp_init(struct tp_dispatch *tp,
731         struct evdev_device *device)
732 {
733         int width, height;
734         double diagonal;
735
736         tp->base.interface = &tp_interface;
737         tp->device = device;
738
739         if (tp_init_slots(tp, device) != 0)
740                 return -1;
741
742         width = abs(device->abs.absinfo_x->maximum -
743                     device->abs.absinfo_x->minimum);
744         height = abs(device->abs.absinfo_y->maximum -
745                      device->abs.absinfo_y->minimum);
746         diagonal = sqrt(width*width + height*height);
747
748         tp->hysteresis.margin_x =
749                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
750         tp->hysteresis.margin_y =
751                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
752
753         if (tp_init_scroll(tp) != 0)
754                 return -1;
755
756         if (tp_init_accel(tp, diagonal) != 0)
757                 return -1;
758
759         if (tp_init_tap(tp) != 0)
760                 return -1;
761
762         if (tp_init_buttons(tp, device) != 0)
763                 return -1;
764
765         return 0;
766 }
767
768 struct evdev_dispatch *
769 evdev_mt_touchpad_create(struct evdev_device *device)
770 {
771         struct tp_dispatch *tp;
772
773         tp = zalloc(sizeof *tp);
774         if (!tp)
775                 return NULL;
776
777         if (tp_init(tp, device) != 0) {
778                 tp_destroy(&tp->base);
779                 return NULL;
780         }
781
782         return  &tp->base;
783 }