Merge branch 'master' of git+ssh://git.freedesktop.org/git/wayland/libinput
[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                 /* Stop spurious MOTION events at the end of scrolling */
457                 t->is_pointer = false;
458         }
459
460         if (nchanged == 0)
461                 return;
462
463         dx /= nchanged;
464         dy /= nchanged;
465
466         tp_filter_motion(tp, &dx, &dy, time);
467
468         /* Require at least three px scrolling to start */
469         if (dy <= -3.0 || dy >= 3.0)
470                 tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
471
472         if (dx <= -3.0 || dx >= 3.0)
473                 tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
474
475         if (dy != 0.0 &&
476             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))) {
477                 pointer_notify_axis(&tp->device->base,
478                                     time,
479                                     LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
480                                     dy);
481         }
482
483         if (dx != 0.0 &&
484             (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))) {
485                 pointer_notify_axis(&tp->device->base,
486                                     time,
487                                     LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
488                                     dx);
489         }
490 }
491
492 static void
493 tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time)
494 {
495         /* terminate scrolling with a zero scroll event */
496         if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
497                 pointer_notify_axis(&tp->device->base,
498                                     time,
499                                     LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
500                                     0);
501         if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
502                 pointer_notify_axis(&tp->device->base,
503                                     time,
504                                     LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
505                                     0);
506
507         tp->scroll.direction = 0;
508 }
509
510 static int
511 tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
512 {
513         struct tp_touch *t;
514         int nfingers_down = 0;
515
516         /* Only count active touches for 2 finger scrolling */
517         tp_for_each_touch(tp, t) {
518                 if (tp_touch_active(tp, t))
519                         nfingers_down++;
520         }
521
522         if (nfingers_down != 2) {
523                 tp_stop_scroll_events(tp, time);
524                 return 0;
525         }
526
527         tp_post_twofinger_scroll(tp, time);
528         return 1;
529 }
530
531 static void
532 tp_post_events(struct tp_dispatch *tp, uint64_t time)
533 {
534         struct tp_touch *t = tp_current_touch(tp);
535         double dx, dy;
536         int consumed = 0;
537
538         consumed |= tp_tap_handle_state(tp, time);
539         consumed |= tp_post_button_events(tp, time);
540
541         if (consumed) {
542                 tp_stop_scroll_events(tp, time);
543                 return;
544         }
545
546         if (tp_post_scroll_events(tp, time) != 0)
547                 return;
548
549         if (t->history.count >= TOUCHPAD_MIN_SAMPLES) {
550                 if (!t->is_pointer) {
551                         tp_for_each_touch(tp, t) {
552                                 if (t->is_pointer)
553                                         break;
554                         }
555                 }
556
557                 if (!t->is_pointer)
558                         return;
559
560                 tp_get_delta(t, &dx, &dy);
561                 tp_filter_motion(tp, &dx, &dy, time);
562
563                 if (dx != 0.0 || dy != 0.0)
564                         pointer_notify_motion(&tp->device->base, time, dx, dy);
565         }
566 }
567
568 static void
569 tp_process(struct evdev_dispatch *dispatch,
570            struct evdev_device *device,
571            struct input_event *e,
572            uint64_t time)
573 {
574         struct tp_dispatch *tp =
575                 (struct tp_dispatch *)dispatch;
576
577         switch (e->type) {
578         case EV_ABS:
579                 if (tp->has_mt)
580                         tp_process_absolute(tp, e, time);
581                 else
582                         tp_process_absolute_st(tp, e, time);
583                 break;
584         case EV_KEY:
585                 tp_process_key(tp, e, time);
586                 break;
587         case EV_SYN:
588                 tp_process_state(tp, time);
589                 tp_post_events(tp, time);
590                 tp_post_process_state(tp, time);
591                 break;
592         }
593 }
594
595 static void
596 tp_destroy(struct evdev_dispatch *dispatch)
597 {
598         struct tp_dispatch *tp =
599                 (struct tp_dispatch*)dispatch;
600
601         tp_destroy_tap(tp);
602         tp_destroy_buttons(tp);
603
604         motion_filter_destroy(tp->filter);
605         free(tp->touches);
606         free(tp);
607 }
608
609 static struct evdev_dispatch_interface tp_interface = {
610         tp_process,
611         tp_destroy
612 };
613
614 static void
615 tp_init_touch(struct tp_dispatch *tp,
616               struct tp_touch *t)
617 {
618         t->tp = tp;
619 }
620
621 static int
622 tp_init_slots(struct tp_dispatch *tp,
623               struct evdev_device *device)
624 {
625         size_t i;
626         const struct input_absinfo *absinfo;
627
628         absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
629         if (absinfo) {
630                 tp->ntouches = absinfo->maximum + 1;
631                 tp->slot = absinfo->value;
632                 tp->has_mt = true;
633         } else {
634                 struct map {
635                         unsigned int code;
636                         int ntouches;
637                 } max_touches[] = {
638                         { BTN_TOOL_QUINTTAP, 5 },
639                         { BTN_TOOL_QUADTAP, 4 },
640                         { BTN_TOOL_TRIPLETAP, 3 },
641                         { BTN_TOOL_DOUBLETAP, 2 },
642                 };
643                 struct map *m;
644
645                 tp->slot = 0;
646                 tp->has_mt = false;
647                 tp->ntouches = 1;
648
649                 ARRAY_FOR_EACH(max_touches, m) {
650                         if (libevdev_has_event_code(device->evdev,
651                                                     EV_KEY,
652                                                     m->code)) {
653                                 tp->ntouches = m->ntouches;
654                                 break;
655                         }
656                 }
657         }
658         tp->touches = calloc(tp->ntouches,
659                              sizeof(struct tp_touch));
660         if (!tp->touches)
661                 return -1;
662
663         for (i = 0; i < tp->ntouches; i++)
664                 tp_init_touch(tp, &tp->touches[i]);
665
666         return 0;
667 }
668
669 static void
670 calculate_scale_coefficients(struct tp_dispatch *tp)
671 {
672         int res_x, res_y;
673
674         if (tp->has_mt) {
675                 res_x = libevdev_get_abs_resolution(tp->device->evdev,
676                                                     ABS_MT_POSITION_X);
677                 res_y = libevdev_get_abs_resolution(tp->device->evdev,
678                                                     ABS_MT_POSITION_Y);
679         } else {
680                 res_x = libevdev_get_abs_resolution(tp->device->evdev,
681                                                     ABS_X);
682                 res_y = libevdev_get_abs_resolution(tp->device->evdev,
683                                                     ABS_Y);
684         }
685
686         if (res_x <= 0 || res_y <= 0) {
687                 tp->accel.x_scale_coeff = 1.0;
688                 tp->accel.y_scale_coeff = 1.0;
689         } else if (res_x > res_y) {
690                 tp->accel.x_scale_coeff = res_y / (double) res_x;
691                 tp->accel.y_scale_coeff = 1.0f;
692         } else {
693                 tp->accel.y_scale_coeff = res_x / (double) res_y;
694                 tp->accel.x_scale_coeff = 1.0f;
695         }
696 }
697
698 static int
699 tp_init_accel(struct tp_dispatch *touchpad, double diagonal)
700 {
701         struct motion_filter *accel;
702
703         calculate_scale_coefficients(touchpad);
704
705         touchpad->accel.constant_factor =
706                 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
707         touchpad->accel.min_factor = DEFAULT_MIN_ACCEL_FACTOR;
708         touchpad->accel.max_factor = DEFAULT_MAX_ACCEL_FACTOR;
709
710         accel = create_pointer_accelator_filter(tp_accel_profile);
711         if (accel == NULL)
712                 return -1;
713
714         touchpad->filter = accel;
715
716         return 0;
717 }
718
719 static int
720 tp_init_scroll(struct tp_dispatch *tp)
721 {
722         tp->scroll.direction = 0;
723
724         return 0;
725 }
726
727 static int
728 tp_init(struct tp_dispatch *tp,
729         struct evdev_device *device)
730 {
731         int width, height;
732         double diagonal;
733
734         tp->base.interface = &tp_interface;
735         tp->device = device;
736
737         if (tp_init_slots(tp, device) != 0)
738                 return -1;
739
740         width = abs(device->abs.absinfo_x->maximum -
741                     device->abs.absinfo_x->minimum);
742         height = abs(device->abs.absinfo_y->maximum -
743                      device->abs.absinfo_y->minimum);
744         diagonal = sqrt(width*width + height*height);
745
746         tp->hysteresis.margin_x =
747                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
748         tp->hysteresis.margin_y =
749                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
750
751         if (tp_init_scroll(tp) != 0)
752                 return -1;
753
754         if (tp_init_accel(tp, diagonal) != 0)
755                 return -1;
756
757         if (tp_init_tap(tp) != 0)
758                 return -1;
759
760         if (tp_init_buttons(tp, device) != 0)
761                 return -1;
762
763         return 0;
764 }
765
766 struct evdev_dispatch *
767 evdev_mt_touchpad_create(struct evdev_device *device)
768 {
769         struct tp_dispatch *tp;
770
771         tp = zalloc(sizeof *tp);
772         if (!tp)
773                 return NULL;
774
775         if (tp_init(tp, device) != 0) {
776                 tp_destroy(&tp->base);
777                 return NULL;
778         }
779
780         return  &tp->base;
781 }