chiark / gitweb /
debian/changelog: Start work on sensitivity
[xf86-input-mtrack.git] / src / gestures.c
1 /***************************************************************************
2  *
3  * Multitouch X driver
4  * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
5  * Copyright (C) 2011 Ryan Bourgeois <bluedragonx@gmail.com>
6  *
7  * Gestures
8  * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
9  * Copyright (C) 2010 Arturo Castro <mail@arturocastro.net>
10  * Copyright (C) 2011 Ryan Bourgeois <bluedragonx@gmail.com>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
25  *
26  **************************************************************************/
27
28 #include "gestures.h"
29 #include "mtouch.h"
30 #include "trig.h"
31
32 #define IS_VALID_BUTTON(x) (x >= 0 && x <= 31)
33
34 static void trigger_button_up(struct Gestures* gs, int button)
35 {
36         if (IS_VALID_BUTTON(button)) {
37                 if (button == 0 && gs->button_emulate > 0) {
38                         button = gs->button_emulate;
39                         gs->button_emulate = 0;
40                 }
41                 CLEARBIT(gs->buttons, button);
42 #ifdef DEBUG_GESTURES
43                 xf86Msg(X_INFO, "trigger_button_up: %d up\n", button);
44 #endif
45         }
46 }
47
48 static void trigger_button_down(struct Gestures* gs, int button)
49 {
50         struct timeval epoch;
51         timerclear(&epoch);
52
53         if (IS_VALID_BUTTON(button) && (button != gs->button_delayed || timercmp(&gs->button_delayed_time, &epoch, ==))) {
54                 SETBIT(gs->buttons, button);
55 #ifdef DEBUG_GESTURES
56                 xf86Msg(X_INFO, "trigger_button_down: %d down\n", button);
57 #endif
58         }
59 #ifdef DEBUG_GESTURES
60         else if (IS_VALID_BUTTON(button))
61                 xf86Msg(X_INFO, "trigger_button_down: %d down ignored, in delayed mode\n", button);
62 #endif
63 }
64
65 static void trigger_button_emulation(struct Gestures* gs, int button)
66 {
67         if (IS_VALID_BUTTON(button) && GETBIT(gs->buttons, 0)) {
68                 CLEARBIT(gs->buttons, 0);
69                 SETBIT(gs->buttons, button);
70                 gs->button_emulate = button;
71 #ifdef DEBUG_GESTURES
72                 xf86Msg(X_INFO, "trigger_button_emulation: %d emulated\n", button);
73 #endif
74         }
75 }
76
77 static void trigger_button_click(struct Gestures* gs,
78                         int button, struct timeval* trigger_up_time)
79 {
80         struct timeval epoch;
81         timerclear(&epoch);
82
83         if (IS_VALID_BUTTON(button) && timercmp(&gs->button_delayed_time, &epoch, ==)) {
84                 trigger_button_down(gs, button);
85                 gs->button_delayed = button;
86                 timercp(&gs->button_delayed_time, trigger_up_time);
87                 timerclear(&gs->button_delayed_delta);
88 #ifdef DEBUG_GESTRUES
89                 xf86Msg(X_INFO, "trigger_button_click: %d placed in delayed mode\n");
90 #endif
91         }
92 #ifdef DEBUG_GESTURES
93         else if (IS_VALID_BUTTON(button))
94                 xf86Msg(X_INFO, "trigger_button_click: %d ignored, in delayed mode\n", button);
95 #endif
96 }
97
98 static void trigger_drag_ready(struct Gestures* gs,
99                         const struct MConfig* cfg)
100 {
101         gs->move_drag = GS_DRAG_READY;
102         timeraddms(&gs->time, cfg->drag_timeout, &gs->move_drag_expire);
103 #ifdef DEBUG_GESTURES
104         xf86Msg(X_INFO, "trigger_drag_ready: drag is ready\n");
105 #endif
106 }
107
108 static int trigger_drag_start(struct Gestures* gs,
109                         const struct MConfig* cfg,
110                         int dx, int dy)
111 {
112         if (gs->move_drag == GS_DRAG_READY) {
113                 timerclear(&gs->move_drag_expire);
114                 if (cfg->drag_wait == 0) {
115                         gs->move_drag = GS_DRAG_ACTIVE;
116                         trigger_button_down(gs, 0);
117 #ifdef DEBUG_GESTURES
118                         xf86Msg(X_INFO, "trigger_drag_start: drag is active\n");
119 #endif
120                 }
121                 else {
122                         gs->move_drag = GS_DRAG_WAIT;
123                         gs->move_drag_dx = dx;
124                         gs->move_drag_dy = dy;
125                         timeraddms(&gs->time, cfg->drag_wait, &gs->move_drag_wait);
126 #ifdef DEBUG_GESTURES
127                         xf86Msg(X_INFO, "trigger_drag_start: drag in wait\n");
128 #endif
129                 }
130         }
131         else if (gs->move_drag == GS_DRAG_WAIT) {
132                 gs->move_drag_dx += dx;
133                 gs->move_drag_dy += dy;
134                 if (!timercmp(&gs->time, &gs->move_drag_wait, <)) {
135                         gs->move_drag = GS_DRAG_ACTIVE;
136                         trigger_button_down(gs, 0);
137 #ifdef DEBUG_GESTURES
138                         xf86Msg(X_INFO, "trigger_drag_start: drag is active\n");
139 #endif
140                 }
141                 else if (dist2(gs->move_drag_dx, gs->move_drag_dy) > SQRVAL(cfg->drag_dist)) {
142                         gs->move_drag = GS_NONE;
143 #ifdef DEBUG_GESTURES
144                         xf86Msg(X_INFO, "trigger_drag_start: drag canceled, moved too far\n");
145 #endif
146                 }
147         }
148         return gs->move_drag != GS_DRAG_WAIT;
149 }
150
151 static void trigger_drag_stop(struct Gestures* gs, int force)
152 {
153         if (gs->move_drag == GS_DRAG_READY && force) {
154                 gs->move_drag = GS_NONE;
155                 timerclear(&gs->move_drag_expire);
156 #ifdef DEBUG_GESTURES
157                 xf86Msg(X_INFO, "trigger_drag_stop: drag canceled\n");
158 #endif
159         }
160         else if (gs->move_drag == GS_DRAG_ACTIVE) {
161                 gs->move_drag = GS_NONE;
162                 timerclear(&gs->move_drag_expire);
163                 trigger_button_up(gs, 0);
164 #ifdef DEBUG_GESTURES
165                 xf86Msg(X_INFO, "trigger_drag_stop: drag stopped\n");
166 #endif
167         }
168 }
169
170 static void buttons_update(struct Gestures* gs,
171                         const struct MConfig* cfg,
172                         const struct HWState* hs,
173                         struct MTState* ms)
174 {
175         if (!cfg->button_enable || cfg->trackpad_disable >= 3)
176                 return;
177
178         static bitmask_t button_prev = 0U;
179         int i, down, emulate, touching;
180         down = 0;
181         emulate = GETBIT(hs->button, 0) && !GETBIT(button_prev, 0);
182
183         for (i = 0; i < 32; i++) {
184                 if (GETBIT(hs->button, i) == GETBIT(button_prev, i))
185                         continue;
186                 if (GETBIT(hs->button, i)) {
187                         down++;
188                         trigger_button_down(gs, i);
189                 }
190                 else
191                         trigger_button_up(gs, i);
192         }
193         button_prev = hs->button;
194
195         if (down) {
196                 int earliest, latest, moving = 0;
197                 gs->move_type = GS_NONE;
198                 timeraddms(&gs->time, cfg->gesture_wait, &gs->move_wait);
199                 earliest = -1;
200                 latest = -1;
201                 foreach_bit(i, ms->touch_used) {
202                         if (GETBIT(ms->touch[i].state, MT_INVALID))
203                                 continue;
204                         if (cfg->button_integrated && !GETBIT(ms->touch[i].flags, GS_BUTTON))
205                                 SETBIT(ms->touch[i].flags, GS_BUTTON);
206                         if (earliest == -1 || timercmp(&ms->touch[i].down, &ms->touch[earliest].down, <))
207                                 earliest = i;
208                         if (latest == -1 || timercmp(&ms->touch[i].down, &ms->touch[latest].down, >))
209                                 latest = i;
210                 }
211
212                 if (emulate) {
213                         int try_zone;
214                         int pos;
215
216                         if (cfg->button_zones && earliest >= 0) {
217                                 pos = ms->touch[earliest].x;
218                                 try_zone = 1;
219                         }
220                         if (cfg->bottom_edge_zones) {
221                                 int latest_bottom = -1;
222                                 foreach_bit(i, ms->touch_used) {
223                                         if (!GETBIT(ms->touch[i].state, MT_BOTTOM_EDGE))
224                                                 continue;
225                                         if (GETBIT(ms->touch[i].state, MT_PALM) && cfg->ignore_palm)
226                                                 continue;
227                                         /* we deliberately don't ignore thumbs for bottom button zones */
228
229                                         if (latest_bottom == -1 || timercmp(&ms->touch[i].down, &ms->touch[latest_bottom].down, >))
230                                                 latest_bottom = i;
231                                 }
232                                 if (latest_bottom >= 0) {
233                                         pos = ms->touch[latest_bottom].x;
234                                         try_zone = 1;
235                                 }
236                         }
237
238                         if (try_zone) {
239                                 int zones, left, right;
240                                 double width;
241
242                                 pos -= cfg->pad_xmin;
243
244                                 zones = 0;
245                                 if (cfg->button_1touch > 0)
246                                         zones++;
247                                 if (cfg->button_2touch > 0)
248                                         zones++;
249                                 if (cfg->button_3touch > 0)
250                                         zones++;
251
252                                 if (zones > 0) {
253                                         width = ((double)cfg->pad_width)/((double)zones);
254 #ifdef DEBUG_GESTURES
255                                         xf86Msg(X_INFO, "buttons_update: pad width %d (min %d), zones %d, zone width %f, x %d\n",
256                                                 cfg->pad_width, cfg->pad_xmin, zones, width, pos);
257 #endif
258                                         for (i = 0; i < zones; i++) {
259                                                 left = width*i;
260                                                 right = width*(i+1);
261                                                 if (pos >= left && pos <= right) {
262 #ifdef DEBUG_GESTURES
263                                                         xf86Msg(X_INFO, "buttons_update: button %d, left %d, right %d (found)\n", i, left, right);
264 #endif
265                                                         break;
266                                                 }
267 #ifdef DEBUG_GESTURES
268                                                 else
269                                                         xf86Msg(X_INFO, "buttons_update: button %d, left %d, right %d\n", i, left, right);
270 #endif
271                                         }
272
273                                         if (i == 0)
274                                                 trigger_button_emulation(gs, cfg->button_1touch - 1);
275                                         else if (i == 1)
276                                                 trigger_button_emulation(gs, cfg->button_2touch - 1);
277                                         else
278                                                 trigger_button_emulation(gs, cfg->button_3touch - 1);
279                                 }
280                         }
281                         else if (latest >= 0) {
282                                 touching = 0;
283                                 struct timeval expire;
284                                 foreach_bit(i, ms->touch_used) {
285                                         timeraddms(&ms->touch[i].down, cfg->button_expire, &expire);
286                                         if (cfg->button_move || cfg->button_expire == 0 || timercmp(&ms->touch[latest].down, &expire, <))
287                                                 touching++;
288                                 }
289
290                                 if (cfg->button_integrated)
291                                         touching--;
292
293                                 if (touching == 1 && cfg->button_1touch > 0)
294                                         trigger_button_emulation(gs, cfg->button_1touch - 1);
295                                 else if (touching == 2 && cfg->button_2touch > 0)
296                                         trigger_button_emulation(gs, cfg->button_2touch - 1);
297                                 else if (touching == 3 && cfg->button_3touch > 0)
298                                         trigger_button_emulation(gs, cfg->button_3touch - 1);
299                         }
300                 }
301         }
302 }
303
304 static void tapping_update(struct Gestures* gs,
305                         const struct MConfig* cfg,
306                         struct MTState* ms)
307 {
308         int i, n, dist, released_max;
309         struct timeval tv_tmp;
310         struct timeval epoch;
311
312         if (cfg->trackpad_disable >= 1)
313                 return;
314
315         if (cfg->tap_4touch > 0)
316                 released_max = 4;
317         else if (cfg->tap_3touch > 0)
318                 released_max = 3;
319         else if (cfg->tap_2touch > 0)
320                 released_max = 2;
321         else if (cfg->tap_1touch > 0)
322                 released_max = 1;
323         else
324                 return;
325
326         timerclear(&epoch);
327         timeraddms(&gs->tap_time_down, cfg->tap_timeout, &tv_tmp);
328         if (!timercmp(&gs->tap_time_down, &epoch, ==) && !timercmp(&gs->time, &tv_tmp, <)) {
329                 gs->tap_touching = 0;
330                 gs->tap_released = 0;
331                 timerclear(&gs->tap_time_down);
332
333                 foreach_bit(i, ms->touch_used) {
334                         if (GETBIT(ms->touch[i].flags, GS_TAP))
335                                 CLEARBIT(ms->touch[i].flags, GS_TAP);
336                 }
337         }
338         else {
339                 foreach_bit(i, ms->touch_used) {
340                         if (GETBIT(ms->touch[i].state, MT_INVALID) || GETBIT(ms->touch[i].flags, GS_BUTTON)) {
341                                 if (GETBIT(ms->touch[i].flags, GS_TAP)) {
342                                         CLEARBIT(ms->touch[i].flags, GS_TAP);
343                                         gs->tap_touching--;
344 #ifdef DEBUG_GESTURES
345                                         xf86Msg(X_INFO, "tapping_update: tap_touching-- (%d): invalid or button\n", gs->tap_touching);
346 #endif
347                                 }
348                         }
349                         else {
350                                 if (GETBIT(ms->touch[i].state, MT_NEW)) {
351                                         SETBIT(ms->touch[i].flags, GS_TAP);
352                                         gs->tap_touching++;
353 #ifdef DEBUG_GESTURES
354                                         xf86Msg(X_INFO, "tapping_update: tap_touching++ (%d): new touch\n", gs->tap_touching);
355 #endif
356                                         timerclear(&tv_tmp);
357                                         if (timercmp(&gs->tap_time_down, &epoch, ==))
358                                                 timercp(&gs->tap_time_down, &gs->time);
359                                 }
360
361                                 if (GETBIT(ms->touch[i].flags, GS_TAP)) {
362                                         dist = dist2(ms->touch[i].total_dx, ms->touch[i].total_dy);
363                                         if (dist >= SQRVAL(cfg->tap_dist)) {
364                                                 CLEARBIT(ms->touch[i].flags, GS_TAP);
365                                                 gs->tap_touching--;
366 #ifdef DEBUG_GESTURES
367                                         xf86Msg(X_INFO, "tapping_update: tap_touching-- (%d): moved too far\n", gs->tap_touching);
368 #endif
369                                         }
370                                         else if (GETBIT(ms->touch[i].state, MT_RELEASED)) {
371                                                 gs->tap_touching--;
372                                                 gs->tap_released++;
373 #ifdef DEBUG_GESTURES
374                                         xf86Msg(X_INFO, "tapping_update: tap_touching-- (%d): released\n", gs->tap_touching);
375                                         xf86Msg(X_INFO, "tapping_update: tap_released++ (%d) (max %d): released\n", gs->tap_released, released_max);
376 #endif
377                                         }
378                                 }
379                         }
380                 }
381         }
382
383         if ((gs->tap_touching == 0 && gs->tap_released > 0) || gs->tap_released >= released_max) {
384                 foreach_bit(i, ms->touch_used) {
385                         if (GETBIT(ms->touch[i].flags, GS_TAP))
386                                 CLEARBIT(ms->touch[i].flags, GS_TAP);
387                 }
388
389                 if (gs->tap_released == 1)
390                         n = cfg->tap_1touch - 1;
391                 else if (gs->tap_released == 2)
392                         n = cfg->tap_2touch - 1;
393                 else if (gs->tap_released == 3)
394                         n = cfg->tap_3touch - 1;
395                 else
396                         n = cfg->tap_4touch - 1;
397
398                 trigger_button_click(gs, n, &tv_tmp);
399                 if (cfg->drag_enable && n == 0)
400                         trigger_drag_ready(gs, cfg);
401
402                 gs->move_type = GS_NONE;
403                 timeraddms(&gs->time, cfg->gesture_wait, &gs->move_wait);
404
405                 gs->tap_touching = 0;
406                 gs->tap_released = 0;
407                 timerclear(&gs->tap_time_down);
408         }
409 }
410
411 static void trigger_move(struct Gestures* gs,
412                         const struct MConfig* cfg,
413                         int dx, int dy)
414 {
415         if ((gs->move_type == GS_MOVE || !timercmp(&gs->time, &gs->move_wait, <)) && (dx != 0 || dy != 0)) {
416                 if (trigger_drag_start(gs, cfg, dx, dy)) {
417                         gs->move_dx = (int)(dx*cfg->sensitivity);
418                         gs->move_dy = (int)(dy*cfg->sensitivity);
419                         gs->move_type = GS_MOVE;
420                         gs->move_dist = 0;
421                         gs->move_dir = TR_NONE;
422                         gs->move_speed = hypot(gs->move_dx, gs->move_dy)/timertomicro(&gs->dt);
423                         timerclear(&gs->move_wait);
424 #ifdef DEBUG_GESTURES
425                         xf86Msg(X_INFO, "trigger_move: %d, %d (speed %f)\n",
426                                 gs->move_dx, gs->move_dy, gs->move_speed);
427 #endif
428                 }
429         }
430 }
431
432 static void trigger_scroll(struct Gestures* gs,
433                         const struct MConfig* cfg,
434                         double dist, int dir)
435 {
436         if (gs->move_type == GS_SCROLL || !timercmp(&gs->time, &gs->move_wait, <)) {
437                 struct timeval tv_tmp;
438                 trigger_drag_stop(gs, 1);
439                 if (gs->move_type != GS_SCROLL || gs->move_dir != dir)
440                         gs->move_dist = 0;
441                 gs->move_dx = 0;
442                 gs->move_dy = 0;
443                 gs->move_type = GS_SCROLL;
444                 gs->move_dist += (int)ABSVAL(dist);
445                 gs->move_dir = dir;
446                 gs->move_speed = dist/timertomicro(&gs->dt);
447                 timeraddms(&gs->time, cfg->gesture_wait, &gs->move_wait);
448
449                 if (gs->move_dist >= cfg->scroll_dist) {
450                         gs->move_dist = MODVAL(gs->move_dist, cfg->scroll_dist);
451                         timeraddms(&gs->time, cfg->gesture_hold, &tv_tmp);
452                         if (dir == TR_DIR_UP)
453                                 trigger_button_click(gs, cfg->scroll_up_btn - 1, &tv_tmp);
454                         else if (dir == TR_DIR_DN)
455                                 trigger_button_click(gs, cfg->scroll_dn_btn - 1, &tv_tmp);
456                         else if (dir == TR_DIR_LT)
457                                 trigger_button_click(gs, cfg->scroll_lt_btn - 1, &tv_tmp);
458                         else if (dir == TR_DIR_RT)
459                                 trigger_button_click(gs, cfg->scroll_rt_btn - 1, &tv_tmp);
460                 }
461 #ifdef DEBUG_GESTURES
462                 xf86Msg(X_INFO, "trigger_scroll: scrolling %+f in direction %d (at %d of %d) (speed %f)\n",
463                         dist, dir, gs->move_dist, cfg->scroll_dist, gs->move_speed);
464 #endif
465         }
466 }
467
468 static void trigger_swipe(struct Gestures* gs,
469                         const struct MConfig* cfg,
470                         double dist, int dir, int isfour)
471 {
472         if (gs->move_type == GS_SWIPE || !timercmp(&gs->time, &gs->move_wait, <)) {
473                 struct timeval tv_tmp;
474                 trigger_drag_stop(gs, 1);
475                 if (gs->move_type != GS_SWIPE || gs->move_dir != dir)
476                         gs->move_dist = 0;
477                 gs->move_dx = 0;
478                 gs->move_dy = 0;
479                 gs->move_type = GS_SWIPE;
480                 gs->move_dist += (int)ABSVAL(dist);
481                 gs->move_dir = dir;
482                 gs->move_speed = dist/timertomicro(&gs->dt);
483                 timeraddms(&gs->time, cfg->gesture_wait, &gs->move_wait);
484                 timeraddms(&gs->time, cfg->gesture_hold, &tv_tmp);
485
486                 if (isfour) {
487                         if (cfg->swipe4_dist > 0 && gs->move_dist >= cfg->swipe4_dist) {
488                                 gs->move_dist = MODVAL(gs->move_dist, cfg->swipe4_dist);
489                                 if (dir == TR_DIR_UP)
490                                         trigger_button_click(gs, cfg->swipe4_up_btn - 1, &tv_tmp);
491                                 else if (dir == TR_DIR_DN)
492                                         trigger_button_click(gs, cfg->swipe4_dn_btn - 1, &tv_tmp);
493                                 else if (dir == TR_DIR_LT)
494                                         trigger_button_click(gs, cfg->swipe4_lt_btn - 1, &tv_tmp);
495                                 else if (dir == TR_DIR_RT)
496                                         trigger_button_click(gs, cfg->swipe4_rt_btn - 1, &tv_tmp);
497                         }
498 #ifdef DEBUG_GESTURES
499                         xf86Msg(X_INFO, "trigger_swipe4: swiping %+f in direction %d (at %d of %d) (speed %f)\n",
500                                 dist, dir, gs->move_dist, cfg->swipe_dist, gs->move_speed);
501 #endif
502                 }
503                 else {
504                         if (cfg->swipe_dist > 0 && gs->move_dist >= cfg->swipe_dist) {
505                                 gs->move_dist = MODVAL(gs->move_dist, cfg->swipe_dist);
506                                 if (dir == TR_DIR_UP)
507                                         trigger_button_click(gs, cfg->swipe_up_btn - 1, &tv_tmp);
508                                 else if (dir == TR_DIR_DN)
509                                         trigger_button_click(gs, cfg->swipe_dn_btn - 1, &tv_tmp);
510                                 else if (dir == TR_DIR_LT)
511                                         trigger_button_click(gs, cfg->swipe_lt_btn - 1, &tv_tmp);
512                                 else if (dir == TR_DIR_RT)
513                                         trigger_button_click(gs, cfg->swipe_rt_btn - 1, &tv_tmp);
514                         }
515 #ifdef DEBUG_GESTURES
516                         xf86Msg(X_INFO, "trigger_swipe: swiping %+f in direction %d (at %d of %d)\n", dist, dir, gs->move_dist, cfg->swipe_dist);
517 #endif
518                 }
519         }
520 }
521
522 static void trigger_scale(struct Gestures* gs,
523                         const struct MConfig* cfg,
524                         double dist, int dir)
525 {
526         if (gs->move_type == GS_SCALE || !timercmp(&gs->time, &gs->move_wait, <)) {
527                 struct timeval tv_tmp;
528                 trigger_drag_stop(gs, 1);
529                 if (gs->move_type != GS_SCALE || gs->move_dir != dir)
530                         gs->move_dist = 0;
531                 gs->move_dx = 0;
532                 gs->move_dy = 0;
533                 gs->move_type = GS_SCALE;
534                 gs->move_dist += (int)ABSVAL(dist);
535                 gs->move_dir = dir;
536                 gs->move_speed = dist/timertomicro(&gs->dt);
537                 timeraddms(&gs->time, cfg->gesture_wait, &gs->move_wait);
538                 if (gs->move_dist >= cfg->scale_dist) {
539                         gs->move_dist = MODVAL(gs->move_dist, cfg->scale_dist);
540                         timeraddms(&gs->time, cfg->gesture_hold, &tv_tmp);
541                         if (dir == TR_DIR_UP)
542                                 trigger_button_click(gs, cfg->scale_up_btn - 1, &tv_tmp);
543                         else if (dir == TR_DIR_DN)
544                                 trigger_button_click(gs, cfg->scale_dn_btn - 1, &tv_tmp);
545                 }
546 #ifdef DEBUG_GESTURES
547                 xf86Msg(X_INFO, "trigger_scale: scaling %+f in direction %d (at %d of %d) (speed %f)\n",
548                         dist, dir, gs->move_dist, cfg->scale_dist, gs->move_speed);
549 #endif
550         }
551 }
552
553 static void trigger_rotate(struct Gestures* gs,
554                         const struct MConfig* cfg,
555                         double dist, int dir)
556 {
557         if (gs->move_type == GS_ROTATE || !timercmp(&gs->time, &gs->move_wait, <)) {
558                 struct timeval tv_tmp;
559                 trigger_drag_stop(gs, 1);
560                 if (gs->move_type != GS_ROTATE || gs->move_dir != dir)
561                         gs->move_dist = 0;
562                 gs->move_dx = 0;
563                 gs->move_dy = 0;
564                 gs->move_type = GS_ROTATE;
565                 gs->move_dist += (int)ABSVAL(dist);
566                 gs->move_dir = dir;
567                 gs->move_speed = dist/timertomicro(&gs->dt);
568                 timeraddms(&gs->time, cfg->gesture_wait, &gs->move_wait);
569                 if (gs->move_dist >= cfg->rotate_dist) {
570                         gs->move_dist = MODVAL(gs->move_dist, cfg->rotate_dist);
571                         timeraddms(&gs->time, cfg->gesture_hold, &tv_tmp);
572                         if (dir == TR_DIR_LT)
573                                 trigger_button_click(gs, cfg->rotate_lt_btn - 1, &tv_tmp);
574                         else if (dir == TR_DIR_RT)
575                                 trigger_button_click(gs, cfg->rotate_rt_btn - 1, &tv_tmp);
576                 }
577 #ifdef DEBUG_GESTURES
578                 xf86Msg(X_INFO, "trigger_rotate: rotating %+f in direction %d (at %d of %d) (speed %f)\n",
579                         dist, dir, gs->move_dist, cfg->rotate_dist, gs->move_speed);
580 #endif
581         }
582 }
583
584 static void trigger_reset(struct Gestures* gs)
585 {
586         trigger_drag_stop(gs, 0);
587         gs->move_dx = 0;
588         gs->move_dy = 0;
589         gs->move_type = GS_NONE;
590         gs->move_dist = 0;
591         gs->move_dir = TR_NONE;
592         timerclear(&gs->move_wait);
593 }
594
595 static int get_scroll_dir(const struct Touch* t1,
596                         const struct Touch* t2)
597 {
598         if (trig_angles_acute(t1->direction, t2->direction) < 2.0) {
599                 double angles[2];
600                 angles[0] = t1->direction;
601                 angles[1] = t2->direction;
602                 return trig_generalize(trig_angles_avg(angles, 2));
603         }
604         return TR_NONE;
605 }
606
607 static int get_rotate_dir(const struct Touch* t1,
608                         const struct Touch* t2)
609 {
610         double v, d1, d2;
611         v = trig_direction(t2->x - t1->x, t2->y - t1->y);
612         d1 = trig_angles_add(v, 2);
613         d2 = trig_angles_sub(v, 2);
614         if (trig_angles_acute(t1->direction, d1) < 2 && trig_angles_acute(t2->direction, d2) < 2)
615                 return TR_DIR_RT;
616         else if (trig_angles_acute(t1->direction, d2) < 2 && trig_angles_acute(t2->direction, d1) < 2)
617                 return TR_DIR_LT;
618         return TR_NONE;
619 }
620
621 static int get_scale_dir(const struct Touch* t1,
622                         const struct Touch* t2)
623 {
624         double v;
625         if (trig_angles_acute(t1->direction, t2->direction) >= 2) {
626                 v = trig_direction(t2->x - t1->x, t2->y - t1->y);
627                 if (trig_angles_acute(v, t1->direction) < 2)
628                         return TR_DIR_DN;
629                 else
630                         return TR_DIR_UP;
631         }
632         return TR_NONE;
633 }
634
635 static int get_swipe_dir(const struct Touch* t1,
636                         const struct Touch* t2,
637                         const struct Touch* t3)
638 {
639         double angles[3];
640         angles[0] = t1->direction;
641         angles[1] = t2->direction;
642         angles[2] = t3->direction;
643         return trig_generalize(trig_angles_avg(angles, 3));
644 }
645
646 static int get_swipe4_dir(const struct Touch* t1,
647                         const struct Touch* t2,
648                         const struct Touch* t3,
649                         const struct Touch* t4)
650 {
651         double angles[4];
652         angles[0] = t1->direction;
653         angles[1] = t2->direction;
654         angles[2] = t3->direction;
655         angles[3] = t4->direction;
656         return trig_generalize(trig_angles_avg(angles, 4));
657 }
658
659 static void moving_update(struct Gestures* gs,
660                         const struct MConfig* cfg,
661                         struct MTState* ms)
662 {
663         int i, count, btn_count, dx, dy, dir;
664         double dist;
665         struct Touch* touches[4];
666         count = btn_count = 0;
667         dx = dy = 0;
668         dir = 0;
669
670         // Reset movement.
671         gs->move_dx = 0;
672         gs->move_dy = 0;
673
674         // Count touches and aggregate touch movements.
675         foreach_bit(i, ms->touch_used) {
676                 if (GETBIT(ms->touch[i].state, MT_INVALID))
677                         continue;
678                 else if (GETBIT(ms->touch[i].flags, GS_BUTTON)) {
679                         btn_count++;
680                         dx += ms->touch[i].dx;
681                         dy += ms->touch[i].dy;
682                 }
683                 else if (!GETBIT(ms->touch[i].flags, GS_TAP)) {
684                         if (count < 4)
685                                 touches[count++] = &ms->touch[i];
686                 }
687         }
688
689         // Determine gesture type.
690         if (count == 0) {
691                 if (btn_count >= 1 && cfg->trackpad_disable < 2)
692                         trigger_move(gs, cfg, dx, dy);
693                 else if (btn_count < 1)
694                         trigger_reset(gs);
695         }
696         else if (count == 1 && cfg->trackpad_disable < 2) {
697                 dx += touches[0]->dx;
698                 dy += touches[0]->dy;
699                 trigger_move(gs, cfg, dx, dy);
700         }
701         else if (count == 2 && cfg->trackpad_disable < 1) {
702                 // scroll, scale, or rotate
703                 if ((dir = get_scroll_dir(touches[0], touches[1])) != TR_NONE) {
704                         dist = hypot(
705                                 touches[0]->dx + touches[1]->dx,
706                                 touches[0]->dy + touches[1]->dy);
707                         trigger_scroll(gs, cfg, dist/2, dir);
708                 }
709                 else if ((dir = get_rotate_dir(touches[0], touches[1])) != TR_NONE) {
710                         dist = ABSVAL(hypot(touches[0]->dx, touches[0]->dy)) +
711                                 ABSVAL(hypot(touches[1]->dx, touches[1]->dy));
712                         trigger_rotate(gs, cfg, dist/2, dir);
713                 }
714                 else if ((dir = get_scale_dir(touches[0], touches[1])) != TR_NONE) {
715                         dist = ABSVAL(hypot(touches[0]->dx, touches[0]->dy)) +
716                                 ABSVAL(hypot(touches[1]->dx, touches[1]->dy));
717                         trigger_scale(gs, cfg, dist/2, dir);
718                 }
719         }
720         else if (count == 3 && cfg->trackpad_disable < 1) {
721                 if ((dir = get_swipe_dir(touches[0], touches[1], touches[2])) != TR_NONE) {
722                         dist = hypot(
723                                 touches[0]->dx + touches[1]->dx + touches[2]->dx,
724                                 touches[0]->dy + touches[1]->dy + touches[2]->dy);
725                         trigger_swipe(gs, cfg, dist/3, dir, 0);
726                 }
727         }
728         else if (count == 4 && cfg->trackpad_disable < 1) {
729                 if ((dir = get_swipe4_dir(touches[0], touches[1], touches[2], touches[3])) != TR_NONE) {
730                         dist = hypot(
731                                 touches[0]->dx + touches[1]->dx + touches[2]->dx + touches[3]->dx,
732                                 touches[0]->dy + touches[1]->dy + touches[2]->dy + touches[3]->dy);
733                         trigger_swipe(gs, cfg, dist/4, dir, 1);
734                 }
735         }
736 }
737
738 static void dragging_update(struct Gestures* gs)
739 {
740         if (gs->move_drag == GS_DRAG_READY && timercmp(&gs->time, &gs->move_drag_expire, >)) {
741 #ifdef DEBUG_GESTURES
742                 xf86Msg(X_INFO, "dragging_update: drag expired\n");
743 #endif
744                 trigger_drag_stop(gs, 1);
745         }
746 }
747
748 static void delayed_update(struct Gestures* gs)
749 {
750         struct timeval epoch;
751         timerclear(&epoch);
752
753         if (timercmp(&gs->button_delayed_time, &epoch, ==))
754                 return;
755
756         if (!timercmp(&gs->time, &gs->button_delayed_time, <)) {
757 #ifdef DEBUG_GESTURES
758                 xf86Msg(X_INFO, "delayed_update: %d delay expired, triggering up\n", gs->button_delayed);
759 #endif
760                 trigger_button_up(gs, gs->button_delayed);
761                 gs->button_delayed = 0;
762                 timerclear(&gs->button_delayed_time);
763                 timerclear(&gs->button_delayed_delta);
764         }
765         else {
766                 timersub(&gs->button_delayed_time, &gs->time, &gs->button_delayed_delta);
767         }
768 }
769
770 void gestures_init(struct MTouch* mt)
771 {
772         memset(&mt->gs, 0, sizeof(struct Gestures));
773 }
774
775 void gestures_extract(struct MTouch* mt)
776 {
777         timersub(&mt->hs.evtime, &mt->gs.time, &mt->gs.dt);
778         timercp(&mt->gs.time, &mt->hs.evtime);
779
780         dragging_update(&mt->gs);
781         buttons_update(&mt->gs, &mt->cfg, &mt->hs, &mt->state);
782         tapping_update(&mt->gs, &mt->cfg, &mt->state);
783         moving_update(&mt->gs, &mt->cfg, &mt->state);
784         delayed_update(&mt->gs);
785 }
786
787 static int gestures_sleep(struct MTouch* mt, const struct timeval* sleep)
788 {
789         if (mtdev_empty(&mt->dev)) {
790                 struct timeval now;
791                 mtdev_idle(&mt->dev, mt->fd, timertoms(sleep));
792                 microtime(&now);
793                 timersub(&now, &mt->gs.time, &mt->gs.dt);
794                 timercp(&mt->gs.time, &now);
795                 return 1;
796         }
797         return 0;
798 }
799
800 int gestures_delayed(struct MTouch* mt)
801 {
802         struct Gestures* gs = &mt->gs;
803         struct timeval epoch;
804         timerclear(&epoch);
805
806         if (timercmp(&gs->button_delayed_time, &epoch, >)) {
807                 if (gestures_sleep(mt, &gs->button_delayed_delta)) {
808 #ifdef DEBUG_GESTURES
809                         xf86Msg(X_INFO, "gestures_delayed: %d up, timer expired\n", gs->button_delayed);
810 #endif
811                         trigger_button_up(gs, gs->button_delayed);
812                         gs->move_dx = 0;
813                         gs->move_dy = 0;
814                         gs->button_delayed = 0;
815                         timerclear(&gs->button_delayed_time);
816                         timerclear(&gs->button_delayed_delta);
817                         return 1;
818                 }
819         }
820         return 0;
821 }
822