evdev: Update axis notifications to follow protocol
[profile/ivi/weston.git] / src / evdev-touchpad.c
1 /*
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
23 #include <stdlib.h>
24 #include <math.h>
25 #include <string.h>
26 #include <stdbool.h>
27 #include <linux/input.h>
28
29 #include "filter.h"
30 #include "evdev.h"
31
32 /* Default values */
33 #define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50
34 #define DEFAULT_MIN_ACCEL_FACTOR 0.16
35 #define DEFAULT_MAX_ACCEL_FACTOR 1.0
36 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
37
38 #define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
39 #define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
40
41 enum touchpad_model {
42         TOUCHPAD_MODEL_UNKNOWN = 0,
43         TOUCHPAD_MODEL_SYNAPTICS,
44         TOUCHPAD_MODEL_ALPS,
45         TOUCHPAD_MODEL_APPLETOUCH,
46         TOUCHPAD_MODEL_ELANTECH
47 };
48
49 enum touchpad_event {
50         TOUCHPAD_EVENT_NONE         = 0,
51         TOUCHPAD_EVENT_ABSOLUTE_ANY = (1 << 0),
52         TOUCHPAD_EVENT_ABSOLUTE_X   = (1 << 1),
53         TOUCHPAD_EVENT_ABSOLUTE_Y   = (1 << 2),
54         TOUCHPAD_EVENT_REPORT       = (1 << 3)
55 };
56
57 struct touchpad_model_spec {
58         short vendor;
59         short product;
60         enum touchpad_model model;
61 };
62
63 static struct touchpad_model_spec touchpad_spec_table[] = {
64         {0x0002, 0x0007, TOUCHPAD_MODEL_SYNAPTICS},
65         {0x0002, 0x0008, TOUCHPAD_MODEL_ALPS},
66         {0x05ac, 0x0000, TOUCHPAD_MODEL_APPLETOUCH},
67         {0x0002, 0x000e, TOUCHPAD_MODEL_ELANTECH},
68         {0x0000, 0x0000, TOUCHPAD_MODEL_UNKNOWN}
69 };
70
71 enum touchpad_state {
72         TOUCHPAD_STATE_NONE  = 0,
73         TOUCHPAD_STATE_TOUCH = (1 << 0),
74         TOUCHPAD_STATE_MOVE  = (1 << 1)
75 };
76
77 #define TOUCHPAD_HISTORY_LENGTH 4
78
79 struct touchpad_motion {
80         int32_t x;
81         int32_t y;
82 };
83
84 enum touchpad_fingers_state {
85         TOUCHPAD_FINGERS_ONE   = (1 << 0),
86         TOUCHPAD_FINGERS_TWO   = (1 << 1),
87         TOUCHPAD_FINGERS_THREE = (1 << 2)
88 };
89
90 enum fsm_event {
91         FSM_EVENT_TOUCH,
92         FSM_EVENT_RELEASE,
93         FSM_EVENT_MOTION,
94         FSM_EVENT_TIMEOUT
95 };
96
97 enum fsm_state {
98         FSM_IDLE,
99         FSM_TOUCH,
100         FSM_TAP,
101         FSM_TAP_2,
102         FSM_DRAG
103 };
104
105 struct touchpad_dispatch {
106         struct evdev_dispatch base;
107         struct evdev_device *device;
108
109         enum touchpad_model model;
110         unsigned int state;
111         int finger_state;
112         int last_finger_state;
113
114         double constant_accel_factor;
115         double min_accel_factor;
116         double max_accel_factor;
117
118         unsigned int event_mask;
119         unsigned int event_mask_filter;
120
121         int reset;
122
123         struct {
124                 struct wl_array events;
125                 enum fsm_state state;
126                 struct wl_event_source *timer_source;
127         } fsm;
128
129         struct {
130                 int32_t x;
131                 int32_t y;
132         } hw_abs;
133
134         int has_pressure;
135         struct {
136                 int32_t touch_low;
137                 int32_t touch_high;
138         } pressure;
139
140         struct {
141                 int32_t margin_x;
142                 int32_t margin_y;
143                 int32_t center_x;
144                 int32_t center_y;
145         } hysteresis;
146
147         struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
148         int motion_index;
149         unsigned int motion_count;
150
151         struct weston_motion_filter *filter;
152 };
153
154 static enum touchpad_model
155 get_touchpad_model(struct evdev_device *device)
156 {
157         struct input_id id;
158         unsigned int i;
159
160         if (ioctl(device->fd, EVIOCGID, &id) < 0)
161                 return TOUCHPAD_MODEL_UNKNOWN;
162
163         for (i = 0; ARRAY_LENGTH(touchpad_spec_table); i++)
164                 if (touchpad_spec_table[i].vendor == id.vendor &&
165                     (!touchpad_spec_table[i].product ||
166                      touchpad_spec_table[i].product == id.product))
167                         return touchpad_spec_table[i].model;
168
169         return TOUCHPAD_MODEL_UNKNOWN;
170 }
171
172 static void
173 configure_touchpad_pressure(struct touchpad_dispatch *touchpad,
174                             int32_t pressure_min, int32_t pressure_max)
175 {
176         int32_t range = pressure_max - pressure_min + 1;
177
178         touchpad->has_pressure = 1;
179
180         /* Magic numbers from xf86-input-synaptics */
181         switch (touchpad->model) {
182         case TOUCHPAD_MODEL_ELANTECH:
183                 touchpad->pressure.touch_low = pressure_min + 1;
184                 touchpad->pressure.touch_high = pressure_min + 1;
185                 break;
186         default:
187                 touchpad->pressure.touch_low =
188                         pressure_min + range * (25.0/256.0);
189                 touchpad->pressure.touch_high =
190                         pressure_min + range * (30.0/256.0);
191         }
192 }
193
194 static double
195 touchpad_profile(struct weston_motion_filter *filter,
196                  void *data,
197                  double velocity,
198                  uint32_t time)
199 {
200         struct touchpad_dispatch *touchpad =
201                 (struct touchpad_dispatch *) data;
202
203         double accel_factor;
204
205         accel_factor = velocity * touchpad->constant_accel_factor;
206
207         if (accel_factor > touchpad->max_accel_factor)
208                 accel_factor = touchpad->max_accel_factor;
209         else if (accel_factor < touchpad->min_accel_factor)
210                 accel_factor = touchpad->min_accel_factor;
211
212         return accel_factor;
213 }
214
215 static inline struct touchpad_motion *
216 motion_history_offset(struct touchpad_dispatch *touchpad, int offset)
217 {
218         int offset_index =
219                 (touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) %
220                 TOUCHPAD_HISTORY_LENGTH;
221
222         return &touchpad->motion_history[offset_index];
223 }
224
225 static double
226 estimate_delta(int x0, int x1, int x2, int x3)
227 {
228         return (x0 + x1 - x2 - x3) / 4;
229 }
230
231 static int
232 hysteresis(int in, int center, int margin)
233 {
234         int diff = in - center;
235         if (abs(diff) <= margin)
236                 return center;
237
238         if (diff > margin)
239                 return center + diff - margin;
240         else if (diff < -margin)
241                 return center + diff + margin;
242         return center + diff;
243 }
244
245 static void
246 touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy)
247 {
248         *dx = estimate_delta(motion_history_offset(touchpad, 0)->x,
249                              motion_history_offset(touchpad, 1)->x,
250                              motion_history_offset(touchpad, 2)->x,
251                              motion_history_offset(touchpad, 3)->x);
252         *dy = estimate_delta(motion_history_offset(touchpad, 0)->y,
253                              motion_history_offset(touchpad, 1)->y,
254                              motion_history_offset(touchpad, 2)->y,
255                              motion_history_offset(touchpad, 3)->y);
256 }
257
258 static void
259 filter_motion(struct touchpad_dispatch *touchpad,
260               double *dx, double *dy, uint32_t time)
261 {
262         struct weston_motion_params motion;
263
264         motion.dx = *dx;
265         motion.dy = *dy;
266
267         weston_filter_dispatch(touchpad->filter, &motion, touchpad, time);
268
269         *dx = motion.dx;
270         *dy = motion.dy;
271 }
272
273 static void
274 notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
275 {
276         notify_button(touchpad->device->seat, time,
277                       DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
278                       WL_POINTER_BUTTON_STATE_PRESSED);
279 }
280
281 static void
282 notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
283 {
284         notify_button(touchpad->device->seat, time,
285                       DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
286                       WL_POINTER_BUTTON_STATE_RELEASED);
287 }
288
289 static void
290 notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
291 {
292         notify_button_pressed(touchpad, time);
293         notify_button_released(touchpad, time);
294 }
295
296 static void
297 process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
298 {
299         uint32_t timeout = UINT32_MAX;
300         enum fsm_event *pevent;
301         enum fsm_event event;
302
303         if (touchpad->fsm.events.size == 0)
304                 return;
305
306         wl_array_for_each(pevent, &touchpad->fsm.events) {
307                 event = *pevent;
308                 timeout = 0;
309
310                 switch (touchpad->fsm.state) {
311                 case FSM_IDLE:
312                         switch (event) {
313                         case FSM_EVENT_TOUCH:
314                                 touchpad->fsm.state = FSM_TOUCH;
315                                 break;
316                         default:
317                                 break;
318                         }
319                         break;
320                 case FSM_TOUCH:
321                         switch (event) {
322                         case FSM_EVENT_RELEASE:
323                                 timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
324                                 touchpad->fsm.state = FSM_TAP;
325                                 break;
326                         default:
327                                 touchpad->fsm.state = FSM_IDLE;
328                                 break;
329                         }
330                         break;
331                 case FSM_TAP:
332                         switch (event) {
333                         case FSM_EVENT_TIMEOUT:
334                                 notify_tap(touchpad, time);
335                                 touchpad->fsm.state = FSM_IDLE;
336                                 break;
337                         case FSM_EVENT_TOUCH:
338                                 notify_button_pressed(touchpad, time);
339                                 touchpad->fsm.state = FSM_TAP_2;
340                                 break;
341                         default:
342                                 touchpad->fsm.state = FSM_IDLE;
343                                 break;
344                         }
345                         break;
346                 case FSM_TAP_2:
347                         switch (event) {
348                         case FSM_EVENT_MOTION:
349                                 touchpad->fsm.state = FSM_DRAG;
350                                 break;
351                         case FSM_EVENT_RELEASE:
352                                 notify_button_released(touchpad, time);
353                                 notify_tap(touchpad, time);
354                                 touchpad->fsm.state = FSM_IDLE;
355                                 break;
356                         default:
357                                 touchpad->fsm.state = FSM_IDLE;
358                                 break;
359                         }
360                         break;
361                 case FSM_DRAG:
362                         switch (event) {
363                         case FSM_EVENT_RELEASE:
364                                 notify_button_released(touchpad, time);
365                                 touchpad->fsm.state = FSM_IDLE;
366                                 break;
367                         default:
368                                 touchpad->fsm.state = FSM_IDLE;
369                                 break;
370                         }
371                         break;
372                 default:
373                         weston_log("evdev-touchpad: Unknown state %d",
374                                    touchpad->fsm.state);
375                         touchpad->fsm.state = FSM_IDLE;
376                         break;
377                 }
378         }
379
380         if (timeout != UINT32_MAX)
381                 wl_event_source_timer_update(touchpad->fsm.timer_source,
382                                              timeout);
383
384         wl_array_release(&touchpad->fsm.events);
385         wl_array_init(&touchpad->fsm.events);
386 }
387
388 static void
389 push_fsm_event(struct touchpad_dispatch *touchpad,
390                enum fsm_event event)
391 {
392         enum fsm_event *pevent;
393
394         pevent = wl_array_add(&touchpad->fsm.events, sizeof event);
395         if (pevent)
396                 *pevent = event;
397         else
398                 touchpad->fsm.state = FSM_IDLE;
399 }
400
401 static int
402 fsm_timout_handler(void *data)
403 {
404         struct touchpad_dispatch *touchpad = data;
405
406         if (touchpad->fsm.events.size == 0) {
407                 push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
408                 process_fsm_events(touchpad, weston_compositor_get_time());
409         }
410
411         return 1;
412 }
413
414 static void
415 touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
416 {
417         int motion_index;
418         int center_x, center_y;
419         double dx = 0.0, dy = 0.0;
420
421         if (touchpad->reset ||
422             touchpad->last_finger_state != touchpad->finger_state) {
423                 touchpad->reset = 0;
424                 touchpad->motion_count = 0;
425                 touchpad->event_mask = TOUCHPAD_EVENT_NONE;
426                 touchpad->event_mask_filter =
427                         TOUCHPAD_EVENT_ABSOLUTE_X | TOUCHPAD_EVENT_ABSOLUTE_Y;
428
429                 touchpad->last_finger_state = touchpad->finger_state;
430
431                 process_fsm_events(touchpad, time);
432
433                 return;
434         }
435         touchpad->last_finger_state = touchpad->finger_state;
436
437         if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT))
438                 return;
439         else
440                 touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT;
441
442         if ((touchpad->event_mask & touchpad->event_mask_filter) !=
443             touchpad->event_mask_filter)
444                 return;
445
446         touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY;
447         touchpad->event_mask = 0;
448
449         /* Avoid noice by moving center only when delta reaches a threshold
450          * distance from the old center. */
451         if (touchpad->motion_count > 0) {
452                 center_x = hysteresis(touchpad->hw_abs.x,
453                                       touchpad->hysteresis.center_x,
454                                       touchpad->hysteresis.margin_x);
455                 center_y = hysteresis(touchpad->hw_abs.y,
456                                       touchpad->hysteresis.center_y,
457                                       touchpad->hysteresis.margin_y);
458         } else {
459                 center_x = touchpad->hw_abs.x;
460                 center_y = touchpad->hw_abs.y;
461         }
462         touchpad->hysteresis.center_x = center_x;
463         touchpad->hysteresis.center_y = center_y;
464         touchpad->hw_abs.x = center_x;
465         touchpad->hw_abs.y = center_y;
466
467         /* Update motion history tracker */
468         motion_index = (touchpad->motion_index + 1) % TOUCHPAD_HISTORY_LENGTH;
469         touchpad->motion_index = motion_index;
470         touchpad->motion_history[motion_index].x = touchpad->hw_abs.x;
471         touchpad->motion_history[motion_index].y = touchpad->hw_abs.y;
472         if (touchpad->motion_count < 4)
473                 touchpad->motion_count++;
474
475         if (touchpad->motion_count >= 4) {
476                 touchpad_get_delta(touchpad, &dx, &dy);
477
478                 filter_motion(touchpad, &dx, &dy, time);
479
480                 if (touchpad->finger_state == TOUCHPAD_FINGERS_ONE) {
481                         touchpad->device->rel.dx = wl_fixed_from_double(dx);
482                         touchpad->device->rel.dy = wl_fixed_from_double(dy);
483                         touchpad->device->pending_events |=
484                                 EVDEV_RELATIVE_MOTION;
485                 } else if (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) {
486                         if (dx != 0.0)
487                                 notify_axis(touchpad->device->seat,
488                                             time,
489                                             WL_POINTER_AXIS_HORIZONTAL_SCROLL,
490                                             wl_fixed_from_double(dx));
491                         if (dy != 0.0)
492                                 notify_axis(touchpad->device->seat,
493                                             time,
494                                             WL_POINTER_AXIS_VERTICAL_SCROLL,
495                                             wl_fixed_from_double(dy));
496                 }
497         }
498
499         if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
500             ((int)dx || (int)dy)) {
501                 touchpad->state |= TOUCHPAD_STATE_MOVE;
502                 push_fsm_event(touchpad, FSM_EVENT_MOTION);
503         }
504
505         process_fsm_events(touchpad, time);
506 }
507
508 static void
509 on_touch(struct touchpad_dispatch *touchpad)
510 {
511         touchpad->state |= TOUCHPAD_STATE_TOUCH;
512
513         push_fsm_event(touchpad, FSM_EVENT_TOUCH);
514 }
515
516 static void
517 on_release(struct touchpad_dispatch *touchpad)
518 {
519
520         touchpad->reset = 1;
521         touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
522
523         push_fsm_event(touchpad, FSM_EVENT_RELEASE);
524 }
525
526 static inline void
527 process_absolute(struct touchpad_dispatch *touchpad,
528                  struct evdev_device *device,
529                  struct input_event *e)
530 {
531         switch (e->code) {
532         case ABS_PRESSURE:
533                 if (e->value > touchpad->pressure.touch_high &&
534                     !(touchpad->state & TOUCHPAD_STATE_TOUCH))
535                         on_touch(touchpad);
536                 else if (e->value < touchpad->pressure.touch_low &&
537                          touchpad->state & TOUCHPAD_STATE_TOUCH)
538                         on_release(touchpad);
539
540                 break;
541         case ABS_X:
542                 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
543                         touchpad->hw_abs.x = e->value;
544                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
545                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X;
546                 }
547                 break;
548         case ABS_Y:
549                 if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
550                         touchpad->hw_abs.y = e->value;
551                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
552                         touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y;
553                 }
554                 break;
555         }
556 }
557
558 static inline void
559 process_key(struct touchpad_dispatch *touchpad,
560             struct evdev_device *device,
561             struct input_event *e,
562             uint32_t time)
563 {
564         switch (e->code) {
565         case BTN_TOUCH:
566                 if (!touchpad->has_pressure) {
567                         if (e->value && !(touchpad->state & TOUCHPAD_STATE_TOUCH))
568                                 on_touch(touchpad);
569                         else if (!e->value)
570                                 on_release(touchpad);
571                 }
572                 break;
573         case BTN_LEFT:
574         case BTN_RIGHT:
575         case BTN_MIDDLE:
576         case BTN_SIDE:
577         case BTN_EXTRA:
578         case BTN_FORWARD:
579         case BTN_BACK:
580         case BTN_TASK:
581                 notify_button(device->seat,
582                               time, e->code,
583                               e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
584                                          WL_POINTER_BUTTON_STATE_RELEASED);
585                 break;
586         case BTN_TOOL_PEN:
587         case BTN_TOOL_RUBBER:
588         case BTN_TOOL_BRUSH:
589         case BTN_TOOL_PENCIL:
590         case BTN_TOOL_AIRBRUSH:
591         case BTN_TOOL_MOUSE:
592         case BTN_TOOL_LENS:
593                 touchpad->reset = 1;
594                 break;
595         case BTN_TOOL_FINGER:
596                 if (e->value)
597                         touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
598                 else
599                         touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
600                 break;
601         case BTN_TOOL_DOUBLETAP:
602                 if (e->value)
603                         touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
604                 else
605                         touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
606                 break;
607         case BTN_TOOL_TRIPLETAP:
608                 if (e->value)
609                         touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
610                 else
611                         touchpad->finger_state &= ~TOUCHPAD_FINGERS_THREE;
612                 break;
613         }
614 }
615
616 static void
617 touchpad_process(struct evdev_dispatch *dispatch,
618                  struct evdev_device *device,
619                  struct input_event *e,
620                  uint32_t time)
621 {
622         struct touchpad_dispatch *touchpad =
623                 (struct touchpad_dispatch *) dispatch;
624
625         switch (e->type) {
626         case EV_SYN:
627                 if (e->code == SYN_REPORT)
628                         touchpad->event_mask |= TOUCHPAD_EVENT_REPORT;
629                 break;
630         case EV_ABS:
631                 process_absolute(touchpad, device, e);
632                 break;
633         case EV_KEY:
634                 process_key(touchpad, device, e, time);
635                 break;
636         }
637
638         touchpad_update_state(touchpad, time);
639 }
640
641 static void
642 touchpad_destroy(struct evdev_dispatch *dispatch)
643 {
644         struct touchpad_dispatch *touchpad =
645                 (struct touchpad_dispatch *) dispatch;
646
647         touchpad->filter->interface->destroy(touchpad->filter);
648         wl_event_source_remove(touchpad->fsm.timer_source);
649         free(dispatch);
650 }
651
652 struct evdev_dispatch_interface touchpad_interface = {
653         touchpad_process,
654         touchpad_destroy
655 };
656
657 static int
658 touchpad_init(struct touchpad_dispatch *touchpad,
659               struct evdev_device *device)
660 {
661         struct weston_motion_filter *accel;
662         struct wl_event_loop *loop;
663
664         struct input_absinfo absinfo;
665         unsigned long abs_bits[NBITS(ABS_MAX)];
666
667         double width;
668         double height;
669         double diagonal;
670
671         touchpad->base.interface = &touchpad_interface;
672         touchpad->device = device;
673
674         /* Detect model */
675         touchpad->model = get_touchpad_model(device);
676
677         /* Configure pressure */
678         ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
679         if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
680                 ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo);
681                 configure_touchpad_pressure(touchpad,
682                                             absinfo.minimum,
683                                             absinfo.maximum);
684         }
685
686         /* Configure acceleration factor */
687         width = abs(device->abs.max_x - device->abs.min_x);
688         height = abs(device->abs.max_y - device->abs.min_y);
689         diagonal = sqrt(width*width + height*height);
690
691         touchpad->constant_accel_factor =
692                 DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
693
694         touchpad->min_accel_factor = DEFAULT_MIN_ACCEL_FACTOR;
695         touchpad->max_accel_factor = DEFAULT_MAX_ACCEL_FACTOR;
696
697         touchpad->hysteresis.margin_x =
698                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
699         touchpad->hysteresis.margin_y =
700                 diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
701         touchpad->hysteresis.center_x = 0;
702         touchpad->hysteresis.center_y = 0;
703
704         /* Configure acceleration profile */
705         accel = create_pointer_accelator_filter(touchpad_profile);
706         if (accel == NULL)
707                 return -1;
708         touchpad->filter = accel;
709
710         /* Setup initial state */
711         touchpad->reset = 1;
712
713         memset(touchpad->motion_history, 0, sizeof touchpad->motion_history);
714         touchpad->motion_index = 0;
715         touchpad->motion_count = 0;
716
717         touchpad->state = TOUCHPAD_STATE_NONE;
718         touchpad->last_finger_state = 0;
719         touchpad->finger_state = 0;
720
721         wl_array_init(&touchpad->fsm.events);
722         touchpad->fsm.state = FSM_IDLE;
723
724         loop = wl_display_get_event_loop(device->seat->compositor->wl_display);
725         touchpad->fsm.timer_source =
726                 wl_event_loop_add_timer(loop, fsm_timout_handler, touchpad);
727         if (touchpad->fsm.timer_source == NULL) {
728                 accel->interface->destroy(accel);
729                 return -1;
730         }
731
732         return 0;
733 }
734
735 struct evdev_dispatch *
736 evdev_touchpad_create(struct evdev_device *device)
737 {
738         struct touchpad_dispatch *touchpad;
739
740         touchpad = malloc(sizeof *touchpad);
741         if (touchpad == NULL)
742                 return NULL;
743
744         if (touchpad_init(touchpad, device) != 0) {
745                 free(touchpad);
746                 return NULL;
747         }
748
749         return &touchpad->base;
750 }