1 /***************************************************************************
4 * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
5 * Copyright (C) 2011 Ryan Bourgeois <bluedragonx@gmail.com>
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>
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.
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.
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
26 **************************************************************************/
32 #define IS_VALID_BUTTON(x) (x >= 0 && x <= 31)
34 static void trigger_button_up(struct Gestures* gs, int button)
36 if (IS_VALID_BUTTON(button)) {
37 if (button == 0 && gs->button_emulate > 0) {
38 button = gs->button_emulate;
39 gs->button_emulate = 0;
41 CLEARBIT(gs->buttons, button);
43 xf86Msg(X_INFO, "trigger_button_up: %d up\n", button);
48 static void trigger_button_down(struct Gestures* gs, int button)
53 if (IS_VALID_BUTTON(button) && (button != gs->button_delayed || timercmp(&gs->button_delayed_time, &epoch, ==))) {
54 SETBIT(gs->buttons, button);
56 xf86Msg(X_INFO, "trigger_button_down: %d down\n", button);
60 else if (IS_VALID_BUTTON(button))
61 xf86Msg(X_INFO, "trigger_button_down: %d down ignored, in delayed mode\n", button);
65 static void trigger_button_emulation(struct Gestures* gs, int button)
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;
72 xf86Msg(X_INFO, "trigger_button_emulation: %d emulated\n", button);
77 static void trigger_button_click(struct Gestures* gs,
78 int button, struct timeval* trigger_up_time)
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);
89 xf86Msg(X_INFO, "trigger_button_click: %d placed in delayed mode\n");
93 else if (IS_VALID_BUTTON(button))
94 xf86Msg(X_INFO, "trigger_button_click: %d ignored, in delayed mode\n", button);
98 static void trigger_drag_ready(struct Gestures* gs,
99 const struct MConfig* cfg)
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");
108 static int trigger_drag_start(struct Gestures* gs,
109 const struct MConfig* cfg,
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");
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");
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");
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");
148 return gs->move_drag != GS_DRAG_WAIT;
151 static void trigger_drag_stop(struct Gestures* gs, int force)
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");
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");
170 static void buttons_update(struct Gestures* gs,
171 const struct MConfig* cfg,
172 const struct HWState* hs,
175 if (!cfg->button_enable || cfg->trackpad_disable >= 3)
178 static bitmask_t button_prev = 0U;
179 int i, down, emulate, touching;
181 emulate = GETBIT(hs->button, 0) && !GETBIT(button_prev, 0);
183 for (i = 0; i < 32; i++) {
184 if (GETBIT(hs->button, i) == GETBIT(button_prev, i))
186 if (GETBIT(hs->button, i)) {
188 trigger_button_down(gs, i);
191 trigger_button_up(gs, i);
193 button_prev = hs->button;
196 int earliest, latest, moving = 0;
197 gs->move_type = GS_NONE;
198 timeraddms(&gs->time, cfg->gesture_wait, &gs->move_wait);
201 foreach_bit(i, ms->touch_used) {
202 if (GETBIT(ms->touch[i].state, MT_INVALID))
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, <))
208 if (latest == -1 || timercmp(&ms->touch[i].down, &ms->touch[latest].down, >))
216 if (cfg->button_zones && earliest >= 0) {
217 pos = ms->touch[earliest].x;
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))
225 if (GETBIT(ms->touch[i].state, MT_PALM) && cfg->ignore_palm)
227 /* we deliberately don't ignore thumbs for bottom button zones */
229 if (latest_bottom == -1 || timercmp(&ms->touch[i].down, &ms->touch[latest_bottom].down, >))
232 if (latest_bottom >= 0) {
233 pos = ms->touch[latest_bottom].x;
239 int zones, left, right;
242 pos -= cfg->pad_xmin;
245 if (cfg->button_1touch > 0)
247 if (cfg->button_2touch > 0)
249 if (cfg->button_3touch > 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);
258 for (i = 0; i < zones; i++) {
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);
267 #ifdef DEBUG_GESTURES
269 xf86Msg(X_INFO, "buttons_update: button %d, left %d, right %d\n", i, left, right);
274 trigger_button_emulation(gs, cfg->button_1touch - 1);
276 trigger_button_emulation(gs, cfg->button_2touch - 1);
278 trigger_button_emulation(gs, cfg->button_3touch - 1);
281 else if (latest >= 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, <))
290 if (cfg->button_integrated)
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);
304 static void tapping_update(struct Gestures* gs,
305 const struct MConfig* cfg,
308 int i, n, dist, released_max;
309 struct timeval tv_tmp;
310 struct timeval epoch;
312 if (cfg->trackpad_disable >= 1)
315 if (cfg->tap_4touch > 0)
317 else if (cfg->tap_3touch > 0)
319 else if (cfg->tap_2touch > 0)
321 else if (cfg->tap_1touch > 0)
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);
333 foreach_bit(i, ms->touch_used) {
334 if (GETBIT(ms->touch[i].flags, GS_TAP))
335 CLEARBIT(ms->touch[i].flags, GS_TAP);
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);
344 #ifdef DEBUG_GESTURES
345 xf86Msg(X_INFO, "tapping_update: tap_touching-- (%d): invalid or button\n", gs->tap_touching);
350 if (GETBIT(ms->touch[i].state, MT_NEW)) {
351 SETBIT(ms->touch[i].flags, GS_TAP);
353 #ifdef DEBUG_GESTURES
354 xf86Msg(X_INFO, "tapping_update: tap_touching++ (%d): new touch\n", gs->tap_touching);
357 if (timercmp(&gs->tap_time_down, &epoch, ==))
358 timercp(&gs->tap_time_down, &gs->time);
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);
366 #ifdef DEBUG_GESTURES
367 xf86Msg(X_INFO, "tapping_update: tap_touching-- (%d): moved too far\n", gs->tap_touching);
370 else if (GETBIT(ms->touch[i].state, MT_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);
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);
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;
396 n = cfg->tap_4touch - 1;
398 trigger_button_click(gs, n, &tv_tmp);
399 if (cfg->drag_enable && n == 0)
400 trigger_drag_ready(gs, cfg);
402 gs->move_type = GS_NONE;
403 timeraddms(&gs->time, cfg->gesture_wait, &gs->move_wait);
405 gs->tap_touching = 0;
406 gs->tap_released = 0;
407 timerclear(&gs->tap_time_down);
411 static void trigger_move(struct Gestures* gs,
412 const struct MConfig* cfg,
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;
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);
432 static void trigger_scroll(struct Gestures* gs,
433 const struct MConfig* cfg,
434 double dist, int dir)
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)
443 gs->move_type = GS_SCROLL;
444 gs->move_dist += (int)ABSVAL(dist);
446 gs->move_speed = dist/timertomicro(&gs->dt);
447 timeraddms(&gs->time, cfg->gesture_wait, &gs->move_wait);
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);
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);
468 static void trigger_swipe(struct Gestures* gs,
469 const struct MConfig* cfg,
470 double dist, int dir, int isfour)
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)
479 gs->move_type = GS_SWIPE;
480 gs->move_dist += (int)ABSVAL(dist);
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);
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);
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);
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);
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);
522 static void trigger_scale(struct Gestures* gs,
523 const struct MConfig* cfg,
524 double dist, int dir)
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)
533 gs->move_type = GS_SCALE;
534 gs->move_dist += (int)ABSVAL(dist);
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);
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);
553 static void trigger_rotate(struct Gestures* gs,
554 const struct MConfig* cfg,
555 double dist, int dir)
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)
564 gs->move_type = GS_ROTATE;
565 gs->move_dist += (int)ABSVAL(dist);
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);
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);
584 static void trigger_reset(struct Gestures* gs)
586 trigger_drag_stop(gs, 0);
589 gs->move_type = GS_NONE;
591 gs->move_dir = TR_NONE;
592 timerclear(&gs->move_wait);
595 static int get_scroll_dir(const struct Touch* t1,
596 const struct Touch* t2)
598 if (trig_angles_acute(t1->direction, t2->direction) < 2.0) {
600 angles[0] = t1->direction;
601 angles[1] = t2->direction;
602 return trig_generalize(trig_angles_avg(angles, 2));
607 static int get_rotate_dir(const struct Touch* t1,
608 const struct Touch* t2)
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)
616 else if (trig_angles_acute(t1->direction, d2) < 2 && trig_angles_acute(t2->direction, d1) < 2)
621 static int get_scale_dir(const struct Touch* t1,
622 const struct Touch* t2)
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)
635 static int get_swipe_dir(const struct Touch* t1,
636 const struct Touch* t2,
637 const struct Touch* t3)
640 angles[0] = t1->direction;
641 angles[1] = t2->direction;
642 angles[2] = t3->direction;
643 return trig_generalize(trig_angles_avg(angles, 3));
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)
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));
659 static void moving_update(struct Gestures* gs,
660 const struct MConfig* cfg,
663 int i, count, btn_count, dx, dy, dir;
665 struct Touch* touches[4];
666 count = btn_count = 0;
674 // Count touches and aggregate touch movements.
675 foreach_bit(i, ms->touch_used) {
676 if (GETBIT(ms->touch[i].state, MT_INVALID))
678 else if (GETBIT(ms->touch[i].flags, GS_BUTTON)) {
680 dx += ms->touch[i].dx;
681 dy += ms->touch[i].dy;
683 else if (!GETBIT(ms->touch[i].flags, GS_TAP)) {
685 touches[count++] = &ms->touch[i];
689 // Determine gesture type.
691 if (btn_count >= 1 && cfg->trackpad_disable < 2)
692 trigger_move(gs, cfg, dx, dy);
693 else if (btn_count < 1)
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);
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) {
705 touches[0]->dx + touches[1]->dx,
706 touches[0]->dy + touches[1]->dy);
707 trigger_scroll(gs, cfg, dist/2, dir);
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);
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);
720 else if (count == 3 && cfg->trackpad_disable < 1) {
721 if ((dir = get_swipe_dir(touches[0], touches[1], touches[2])) != TR_NONE) {
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);
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) {
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);
738 static void dragging_update(struct Gestures* gs)
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");
744 trigger_drag_stop(gs, 1);
748 static void delayed_update(struct Gestures* gs)
750 struct timeval epoch;
753 if (timercmp(&gs->button_delayed_time, &epoch, ==))
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);
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);
766 timersub(&gs->button_delayed_time, &gs->time, &gs->button_delayed_delta);
770 void gestures_init(struct MTouch* mt)
772 memset(&mt->gs, 0, sizeof(struct Gestures));
775 void gestures_extract(struct MTouch* mt)
777 timersub(&mt->hs.evtime, &mt->gs.time, &mt->gs.dt);
778 timercp(&mt->gs.time, &mt->hs.evtime);
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);
787 static int gestures_sleep(struct MTouch* mt, const struct timeval* sleep)
789 if (mtdev_empty(&mt->dev)) {
791 mtdev_idle(&mt->dev, mt->fd, timertoms(sleep));
793 timersub(&now, &mt->gs.time, &mt->gs.dt);
794 timercp(&mt->gs.time, &now);
800 int gestures_delayed(struct MTouch* mt)
802 struct Gestures* gs = &mt->gs;
803 struct timeval epoch;
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);
811 trigger_button_up(gs, gs->button_delayed);
814 gs->button_delayed = 0;
815 timerclear(&gs->button_delayed_time);
816 timerclear(&gs->button_delayed_delta);