2 * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Flora License, Version 1.1 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "screen_reader_gestures.h"
21 #include <Ecore_Input.h>
25 #include <Ecore_Wayland.h>
28 static GestureCB _global_cb;
29 static void *_global_data;
32 static Ecore_X_Window win;
34 static Ecore_Wl_Window *win;
37 static Ecore_Event_Handler *property_changed_hld;
39 struct _Gestures_Config {
40 // minimal required length of flick gesture (in pixels)
41 int one_finger_flick_min_length;
42 // maximal time of gesture
43 int one_finger_flick_max_time;
44 // timeout period to activate hover gesture (first longpress timeout)
45 double one_finger_hover_longpress_timeout;
46 // to activate flick gesture by 2 fingers (it is hotfix - gestures need serious refactoring)
47 int two_finger_flick_to_scroll_timeout;
48 // after mowing this pixels flick two finger flick to scroll gesture is started
49 int two_finger_flick_to_scroll_min_length;
50 // tap timeout - maximal ammount of time allowed between seqiential taps
51 double one_finger_tap_timeout;
52 // tap radius(in pixels)
53 int one_finger_tap_radius;
55 typedef struct _Gestures_Config Gestures_Config;
58 FLICK_DIRECTION_UNDEFINED,
62 FLICK_DIRECTION_RIGHT,
63 FLICK_DIRECTION_DOWN_RETURN,
64 FLICK_DIRECTION_UP_RETURN,
65 FLICK_DIRECTION_LEFT_RETURN,
66 FLICK_DIRECTION_RIGHT_RETURN,
70 GESTURE_NOT_STARTED = 0, // Gesture is ready to start
71 GESTURE_ONGOING, // Gesture in progress.
72 GESTURE_FINISHED, // Gesture finished - should be emited
73 GESTURE_ABORTED // Gesture aborted
77 ONE_FINGER_GESTURE = 1,
84 Ecore_X_Window win; /**< Input window covering given zone */
86 Ecore_Wl_Window *win; /**< Input window covering given zone */
88 unsigned int n_taps; /**< Number of fingers touching screen */
89 unsigned int event_time;
92 gesture_state_e state; // current state of gesture
93 unsigned int timestamp[3]; // time of gesture;
94 int finger[3]; // finger number which initiates gesture
95 int x_org[3], y_org[3]; // coorinates of finger down event
96 int x_end[3], y_end[3]; // coorinates of finger up event
97 flick_direction_e dir; // direction of flick
98 int n_fingers; // number of fingers in gesture
99 int n_fingers_left; // number of fingers in gesture
100 // still touching screen
101 Eina_Bool finger_out[3]; // finger is out of the finger boundary
102 Eina_Bool return_flick[3];
103 Eina_Bool flick_to_scroll;
104 int flick_to_scroll_last_x;
105 int flick_to_scroll_last_y;
109 gesture_state_e state; // currest gesture state
113 unsigned int timestamp; // time of gesture;
114 unsigned int last_emission_time; // last time of gesture emission
116 Eina_Bool longpressed;
120 Eina_Bool started; // indicates if taps recognition process has started
121 Eina_Bool pressed; // indicates if finger is down
122 int n_taps; // number of taps captures in sequence
123 int finger[3]; // device id of finget
124 Ecore_Timer *timer; // sequence expiration timer
125 int x_org[3], y_org[3]; // coordinates of first tap
126 gesture_type_e tap_type;
129 typedef struct _Cover Cover;
131 Gestures_Config *_e_mod_config;
133 static Ecore_X_Window scrolled_win;
136 static Eina_List *handlers;
138 static int win_angle;
140 static void _hover_event_emit(Cover * cov, int state);
141 static unsigned int _win_angle_get(void);
143 void __transform_coordinates(int *ax, int *ay)
149 ecore_x_window_geometry_get(ecore_x_window_root_first_get(), NULL, NULL, &w, &h);
151 ecore_wl_screen_size_get(&w, &h);
154 win_angle = _win_angle_get();
171 static void _event_emit(Gesture g, int x, int y, int x_e, int y_e, int state, int event_time)
173 Gesture_Info *info = calloc(sizeof(Gesture_Info), 1);
174 EINA_SAFETY_ON_NULL_RETURN(info);
176 __transform_coordinates(&x, &y);
177 __transform_coordinates(&x_e, &y_e);
185 info->event_time = event_time;
188 _global_cb(_global_data, info);
192 static void _flick_gesture_mouse_down(Ecore_Event_Mouse_Button * ev, Cover * cov)
194 if (cov->flick_gesture.state == GESTURE_NOT_STARTED) {
195 cov->flick_gesture.state = GESTURE_ONGOING;
196 cov->flick_gesture.finger[0] = ev->multi.device;
197 cov->flick_gesture.x_org[0] = ev->root.x;
198 cov->flick_gesture.y_org[0] = ev->root.y;
199 cov->flick_gesture.timestamp[0] = ev->timestamp;
200 cov->flick_gesture.flick_to_scroll = EINA_FALSE;
201 cov->flick_gesture.n_fingers = 1;
202 cov->flick_gesture.n_fingers_left = 1;
203 cov->flick_gesture.dir = FLICK_DIRECTION_UNDEFINED;
204 cov->flick_gesture.finger_out[0] = EINA_FALSE;
205 cov->flick_gesture.return_flick[0] = EINA_FALSE;
206 } else if (cov->flick_gesture.state == GESTURE_ONGOING) {
207 // abort gesture if too many fingers touched screen
208 if ((cov->n_taps > 3) || (cov->flick_gesture.n_fingers > 2)) {
209 cov->flick_gesture.state = GESTURE_ABORTED;
213 cov->flick_gesture.x_org[cov->flick_gesture.n_fingers] = ev->root.x;
214 cov->flick_gesture.y_org[cov->flick_gesture.n_fingers] = ev->root.y;
215 cov->flick_gesture.timestamp[cov->flick_gesture.n_fingers] = ev->timestamp;
216 cov->flick_gesture.finger[cov->flick_gesture.n_fingers] = ev->multi.device;
217 cov->flick_gesture.n_fingers++;
218 cov->flick_gesture.n_fingers_left++;
219 if (cov->flick_gesture.n_fingers < 3) { /* n_fingers == 3 makes out of bounds write */
220 cov->flick_gesture.finger_out[cov->flick_gesture.n_fingers] = EINA_FALSE;
221 cov->flick_gesture.return_flick[cov->flick_gesture.n_fingers] = EINA_FALSE;
226 static Eina_Bool _flick_gesture_time_check(unsigned int event_time, unsigned int gesture_time)
228 DEBUG("Flick time: %d", event_time - gesture_time);
229 if ((event_time - gesture_time) < _e_mod_config->one_finger_flick_max_time * 2) //Double time because of the possible of return flick
235 static Eina_Bool _flick_gesture_length_check(int x, int y, int x_org, int y_org)
240 if ((dx * dx + dy * dy) > (_e_mod_config->one_finger_flick_min_length * _e_mod_config->one_finger_flick_min_length))
246 static flick_direction_e _flick_gesture_direction_get(int x, int y, int x_org, int y_org)
265 if ((dy < 0) && (abs(dx) < -dy))
266 return FLICK_DIRECTION_UP;
267 if ((dy > 0) && (abs(dx) < dy))
268 return FLICK_DIRECTION_DOWN;
269 if ((dx > 0) && (dx > abs(dy)))
270 return FLICK_DIRECTION_RIGHT;
271 if ((dx < 0) && (-dx > abs(dy)))
272 return FLICK_DIRECTION_LEFT;
274 return FLICK_DIRECTION_UNDEFINED;
277 static void _flick_event_emit(Cover * cov)
279 int ax, ay, axe, aye, i, type = -1;
280 ax = ay = axe = aye = 0;
282 for (i = 0; i < cov->flick_gesture.n_fingers; i++) {
283 ax += cov->flick_gesture.x_org[i];
284 ay += cov->flick_gesture.y_org[i];
285 axe += cov->flick_gesture.x_end[i];
286 aye += cov->flick_gesture.y_end[i];
289 ax /= cov->flick_gesture.n_fingers;
290 ay /= cov->flick_gesture.n_fingers;
291 axe /= cov->flick_gesture.n_fingers;
292 aye /= cov->flick_gesture.n_fingers;
294 if (cov->flick_gesture.dir == FLICK_DIRECTION_LEFT) {
295 if (cov->flick_gesture.n_fingers == 1)
296 type = ONE_FINGER_FLICK_LEFT;
297 if (cov->flick_gesture.n_fingers == 2)
298 type = TWO_FINGERS_FLICK_LEFT;
299 if (cov->flick_gesture.n_fingers == 3)
300 type = THREE_FINGERS_FLICK_LEFT;
301 } else if (cov->flick_gesture.dir == FLICK_DIRECTION_RIGHT) {
302 if (cov->flick_gesture.n_fingers == 1)
303 type = ONE_FINGER_FLICK_RIGHT;
304 if (cov->flick_gesture.n_fingers == 2)
305 type = TWO_FINGERS_FLICK_RIGHT;
306 if (cov->flick_gesture.n_fingers == 3)
307 type = THREE_FINGERS_FLICK_RIGHT;
308 } else if (cov->flick_gesture.dir == FLICK_DIRECTION_UP) {
309 if (cov->flick_gesture.n_fingers == 1)
310 type = ONE_FINGER_FLICK_UP;
311 if (cov->flick_gesture.n_fingers == 2)
312 type = TWO_FINGERS_FLICK_UP;
313 if (cov->flick_gesture.n_fingers == 3)
314 type = THREE_FINGERS_FLICK_UP;
315 } else if (cov->flick_gesture.dir == FLICK_DIRECTION_DOWN) {
316 if (cov->flick_gesture.n_fingers == 1)
317 type = ONE_FINGER_FLICK_DOWN;
318 if (cov->flick_gesture.n_fingers == 2)
319 type = TWO_FINGERS_FLICK_DOWN;
320 if (cov->flick_gesture.n_fingers == 3)
321 type = THREE_FINGERS_FLICK_DOWN;
322 } else if (cov->flick_gesture.dir == FLICK_DIRECTION_DOWN_RETURN) {
323 if (cov->flick_gesture.n_fingers == 1)
324 type = ONE_FINGER_FLICK_DOWN_RETURN;
325 if (cov->flick_gesture.n_fingers == 2)
326 type = TWO_FINGERS_FLICK_DOWN_RETURN;
327 if (cov->flick_gesture.n_fingers == 3)
328 type = THREE_FINGERS_FLICK_DOWN_RETURN;
329 } else if (cov->flick_gesture.dir == FLICK_DIRECTION_UP_RETURN) {
330 if (cov->flick_gesture.n_fingers == 1)
331 type = ONE_FINGER_FLICK_UP_RETURN;
332 if (cov->flick_gesture.n_fingers == 2)
333 type = TWO_FINGERS_FLICK_UP_RETURN;
334 if (cov->flick_gesture.n_fingers == 3)
335 type = THREE_FINGERS_FLICK_UP_RETURN;
336 } else if (cov->flick_gesture.dir == FLICK_DIRECTION_LEFT_RETURN) {
337 if (cov->flick_gesture.n_fingers == 1)
338 type = ONE_FINGER_FLICK_LEFT_RETURN;
339 if (cov->flick_gesture.n_fingers == 2)
340 type = TWO_FINGERS_FLICK_LEFT_RETURN;
341 if (cov->flick_gesture.n_fingers == 3)
342 type = THREE_FINGERS_FLICK_LEFT_RETURN;
343 } else if (cov->flick_gesture.dir == FLICK_DIRECTION_RIGHT_RETURN) {
344 if (cov->flick_gesture.n_fingers == 1)
345 type = ONE_FINGER_FLICK_RIGHT_RETURN;
346 if (cov->flick_gesture.n_fingers == 2)
347 type = TWO_FINGERS_FLICK_RIGHT_RETURN;
348 if (cov->flick_gesture.n_fingers == 3)
349 type = THREE_FINGERS_FLICK_RIGHT_RETURN;
351 DEBUG("FLICK GESTURE: N: %d F: %d", cov->flick_gesture.n_fingers, cov->flick_gesture.dir);
352 _event_emit(type, ax, ay, axe, aye, 2, cov->event_time);
355 static void _flick_gesture_mouse_up(Ecore_Event_Mouse_Button * ev, Cover * cov)
357 if (cov->flick_gesture.state == GESTURE_ONGOING) {
359 // check if fingers match
360 for (i = 0; i < cov->flick_gesture.n_fingers; i++) {
361 if (cov->flick_gesture.finger[i] == ev->multi.device)
364 if (i == cov->flick_gesture.n_fingers) {
365 DEBUG("Finger id not recognized. Gesture aborted.");
366 cov->flick_gesture.state = GESTURE_ABORTED;
369 if (cov->flick_gesture.flick_to_scroll)
371 if (ev->multi.device == 1) {
372 //if it is second finger then update x and y,
373 //We use last x and y coordinates in end_scroll.
374 //So if the first finger is up before
375 //the second one we will use latest x and y of second finger
376 //because second was the finger that scroll follows.
377 //Else we can encounter that delta between last continue_scroll
378 //coordinates and end_scroll coordinates will be high.
379 cov->flick_gesture.flick_to_scroll_last_x = ev->x;
380 cov->flick_gesture.flick_to_scroll_last_y = ev->y;
383 DEBUG("Flick gesture was interpreted as scroll so we aborting it.");
384 cov->flick_gesture.state = GESTURE_ABORTED;
387 // check if flick for given finger is valid
388 if (!_flick_gesture_time_check(ev->timestamp, cov->flick_gesture.timestamp[i])) {
389 DEBUG("finger flick gesture timeout expired. Gesture aborted.");
390 cov->flick_gesture.state = GESTURE_ABORTED;
393 // check minimal flick length
394 if (!_flick_gesture_length_check(ev->root.x, ev->root.y, cov->flick_gesture.x_org[i], cov->flick_gesture.y_org[i])) {
395 if (!cov->flick_gesture.finger_out[i]) {
396 DEBUG("Minimal gesture length not reached and no return flick. Gesture aborted.");
397 cov->flick_gesture.state = GESTURE_ABORTED;
400 cov->flick_gesture.return_flick[i] = EINA_TRUE;
403 flick_direction_e s = cov->flick_gesture.return_flick[i] ? cov->flick_gesture.dir : _flick_gesture_direction_get(ev->root.x, ev->root.y,
404 cov->flick_gesture.x_org[i],
405 cov->flick_gesture.y_org[i]);
407 cov->flick_gesture.n_fingers_left--;
409 if ((cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED || cov->flick_gesture.dir > FLICK_DIRECTION_RIGHT)
410 && cov->flick_gesture.return_flick[i] == EINA_FALSE) {
411 DEBUG("Flick gesture");
412 cov->flick_gesture.dir = s;
414 // gesture is valid only if all flicks are in same direction
415 if (cov->flick_gesture.dir != s) {
416 DEBUG("Flick in different direction. Gesture aborted.");
417 cov->flick_gesture.state = GESTURE_ABORTED;
421 cov->flick_gesture.x_end[i] = ev->root.x;
422 cov->flick_gesture.y_end[i] = ev->root.y;
424 if (!cov->flick_gesture.n_fingers_left) {
425 _flick_event_emit(cov);
426 cov->flick_gesture.state = GESTURE_NOT_STARTED;
431 // if no finger is touching a screen, gesture will be reseted.
432 if (cov->flick_gesture.state == GESTURE_ABORTED) {
433 if (cov->flick_gesture.flick_to_scroll) {
434 end_scroll(cov->flick_gesture.flick_to_scroll_last_x, cov->flick_gesture.flick_to_scroll_last_y);
435 cov->flick_gesture.flick_to_scroll = EINA_FALSE;
437 if (cov->n_taps == 0)
438 cov->flick_gesture.state = GESTURE_NOT_STARTED;
442 static Eina_Bool _flick_to_scroll_gesture_conditions_met(Ecore_Event_Mouse_Move * ev, int gesture_timestamp, int dx, int dy)
444 if (ev->timestamp - gesture_timestamp > _e_mod_config->two_finger_flick_to_scroll_timeout)
445 if (abs(dx) > _e_mod_config->two_finger_flick_to_scroll_min_length || abs(dy) > _e_mod_config->two_finger_flick_to_scroll_min_length)
451 static void _flick_gesture_mouse_move(Ecore_Event_Mouse_Move * ev, Cover * cov)
453 if (cov->flick_gesture.state == GESTURE_ONGOING) {
455 for (i = 0; i < cov->flick_gesture.n_fingers; ++i) {
456 if (cov->flick_gesture.finger[i] == ev->multi.device)
459 if (i == cov->flick_gesture.n_fingers) {
460 if (cov->flick_gesture.n_fingers >= 3) //that is because of the EFL bug. Mouse move event before mouse down(!)
462 ERROR("Finger id not recognized. Gesture aborted.");
463 cov->flick_gesture.state = GESTURE_ABORTED;
468 int dx = ev->root.x - cov->flick_gesture.x_org[i];
469 int dy = ev->root.y - cov->flick_gesture.y_org[i];
485 if (cov->flick_gesture.flick_to_scroll || _flick_to_scroll_gesture_conditions_met(ev, cov->flick_gesture.timestamp[i], dx, dy)) {
486 if (!cov->flick_gesture.flick_to_scroll) {
487 start_scroll(ev->x, ev->y);
488 cov->flick_gesture.flick_to_scroll = EINA_TRUE;
490 continue_scroll(ev->x, ev->y);
492 cov->flick_gesture.flick_to_scroll_last_x = ev->x;
493 cov->flick_gesture.flick_to_scroll_last_y = ev->y;
498 if (!cov->flick_gesture.finger_out[i]) {
499 if (abs(dx) > _e_mod_config->one_finger_flick_min_length) {
500 cov->flick_gesture.finger_out[i] = EINA_TRUE;
502 if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED || cov->flick_gesture.dir == FLICK_DIRECTION_RIGHT_RETURN) {
503 cov->flick_gesture.dir = FLICK_DIRECTION_RIGHT_RETURN;
505 ERROR("Invalid direction, abort");
506 cov->flick_gesture.state = GESTURE_ABORTED;
509 if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED || cov->flick_gesture.dir == FLICK_DIRECTION_LEFT_RETURN) {
510 cov->flick_gesture.dir = FLICK_DIRECTION_LEFT_RETURN;
512 ERROR("Invalid direction, abort");
513 cov->flick_gesture.state = GESTURE_ABORTED;
519 else if (abs(dy) > _e_mod_config->one_finger_flick_min_length) {
520 cov->flick_gesture.finger_out[i] = EINA_TRUE;
522 if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED || cov->flick_gesture.dir == FLICK_DIRECTION_DOWN_RETURN) {
523 cov->flick_gesture.dir = FLICK_DIRECTION_DOWN_RETURN;
525 ERROR("Invalid direction, abort");
526 cov->flick_gesture.state = GESTURE_ABORTED;
529 if (cov->flick_gesture.dir == FLICK_DIRECTION_UNDEFINED || cov->flick_gesture.dir == FLICK_DIRECTION_UP_RETURN) {
530 cov->flick_gesture.dir = FLICK_DIRECTION_UP_RETURN;
532 ERROR("Invalid direction, abort");
533 cov->flick_gesture.state = GESTURE_ABORTED;
543 static Eina_Bool _on_hover_timeout(void *data)
546 DEBUG("Hover timer expierd");
548 cov->hover_gesture.longpressed = EINA_TRUE;
549 cov->hover_gesture.timer = NULL;
551 if (cov->hover_gesture.last_emission_time == -1) {
552 _hover_event_emit(cov, 0);
553 cov->hover_gesture.last_emission_time = cov->event_time;
558 static void _hover_gesture_timer_reset(Cover * cov, double time)
560 DEBUG("Hover timer reset");
561 cov->hover_gesture.longpressed = EINA_FALSE;
562 if (cov->hover_gesture.timer) {
563 ecore_timer_reset(cov->hover_gesture.timer);
566 cov->hover_gesture.timer = ecore_timer_add(time, _on_hover_timeout, cov);
569 static void _hover_gesture_mouse_down(Ecore_Event_Mouse_Button * ev, Cover * cov)
571 if (cov->hover_gesture.state == GESTURE_NOT_STARTED && cov->n_taps == 1) {
572 cov->hover_gesture.state = GESTURE_ONGOING;
573 cov->hover_gesture.timestamp = ev->timestamp;
574 cov->hover_gesture.last_emission_time = -1;
575 cov->hover_gesture.x[0] = ev->root.x;
576 cov->hover_gesture.y[0] = ev->root.y;
577 cov->hover_gesture.finger[0] = ev->multi.device;
578 cov->hover_gesture.n_fingers = 1;
579 _hover_gesture_timer_reset(cov, _e_mod_config->one_finger_hover_longpress_timeout);
581 if (cov->hover_gesture.state == GESTURE_ONGOING && cov->n_taps == 2) {
582 if (cov->hover_gesture.longpressed) {
583 _hover_event_emit(cov, 2);
586 cov->hover_gesture.timestamp = -1;
587 cov->hover_gesture.last_emission_time = -1;
588 cov->hover_gesture.x[1] = ev->root.x;
589 cov->hover_gesture.y[1] = ev->root.y;
590 cov->hover_gesture.finger[1] = ev->multi.device;
591 cov->hover_gesture.n_fingers = 2;
592 _hover_gesture_timer_reset(cov, _e_mod_config->one_finger_hover_longpress_timeout);
594 // abort gesture if more then 2 fingers touched screen
595 if ((cov->hover_gesture.state == GESTURE_ONGOING) && cov->n_taps > 2) {
596 DEBUG("More then 2 finged. Abort hover gesture");
597 _hover_event_emit(cov, 2);
603 cov->hover_gesture.state = GESTURE_ABORTED;
604 if (cov->hover_gesture.timer)
605 ecore_timer_del(cov->hover_gesture.timer);
606 cov->hover_gesture.timer = NULL;
609 static void _hover_gesture_mouse_up(Ecore_Event_Mouse_Button * ev, Cover * cov)
612 if (cov->hover_gesture.state == GESTURE_ONGOING) {
614 for (i = 0; i < cov->hover_gesture.n_fingers; i++) {
615 if (cov->hover_gesture.finger[i] == ev->multi.device)
618 if (i == cov->hover_gesture.n_fingers) {
619 DEBUG("Invalid finger id: %d", ev->multi.device);
622 cov->hover_gesture.state = GESTURE_ABORTED;
623 if (cov->hover_gesture.timer)
624 ecore_timer_del(cov->hover_gesture.timer);
625 cov->hover_gesture.timer = NULL;
626 // aditionally emit event to complete sequence
627 if (cov->hover_gesture.longpressed)
628 _hover_event_emit(cov, 2);
631 // reset gesture only if user released all his fingers
632 if (cov->n_taps == 0)
633 cov->hover_gesture.state = GESTURE_NOT_STARTED;
636 static void _get_root_coords(Ecore_X_Window win, int *x, int *y)
638 Ecore_X_Window root = ecore_x_window_root_first_get();
639 Ecore_X_Window parent = ecore_x_window_parent_get(win);
647 while (parent && (root != parent)) {
648 ecore_x_window_geometry_get(parent, &wx, &wy, NULL, NULL);
653 parent = ecore_x_window_parent_get(parent);
657 Ecore_X_Window top_window_get(int x, int y)
659 Ecore_X_Window wins[1] = { win };
660 Ecore_X_Window under = ecore_x_window_at_xy_with_skip_get(x, y, wins, sizeof(wins) / sizeof(wins[0]));
662 _get_root_coords(under, &rx, &ry);
663 DEBUG("Recieved window with coords:%d %d", rx, ry);
669 Ecore_Wl_Window *top_window_get(int x, int y)
676 void start_scroll(int x, int y)
679 Ecore_X_Window wins[1] = { win };
680 Ecore_X_Window under = ecore_x_window_at_xy_with_skip_get(x, y, wins, sizeof(wins) / sizeof(wins[0]));
681 _get_root_coords(under, &rx, &ry);
682 ecore_x_mouse_in_send(under, x - rx, y - ry);
683 ecore_x_window_focus(under);
684 ecore_x_mouse_down_send(under, x - rx, y - ry, 1);
685 scrolled_win = under;
689 void continue_scroll(int x, int y)
692 ecore_x_mouse_move_send(scrolled_win, x - rx, y - ry);
696 void end_scroll(int x, int y)
699 ecore_x_mouse_up_send(scrolled_win, x - rx, y - ry, 1);
700 ecore_x_mouse_out_send(scrolled_win, x - rx, y - ry);
704 static unsigned int _win_angle_get(void)
708 Ecore_X_Window root, first_root;
711 unsigned char *prop_data = NULL;
713 first_root = ecore_x_window_root_first_get();
714 root = ecore_x_window_root_get(first_root);
715 ret = ecore_x_window_prop_property_get(root, ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE, ECORE_X_ATOM_CARDINAL, 32, &prop_data, &count);
717 if (ret && prop_data)
718 memcpy(&angle, prop_data, sizeof(int));
728 static void _hover_event_emit(Cover * cov, int state)
730 int ax = 0, ay = 0, j;
732 for (j = 0; j < cov->hover_gesture.n_fingers; j++) {
733 ax += cov->hover_gesture.x[j];
734 ay += cov->hover_gesture.y[j];
737 ax /= cov->hover_gesture.n_fingers;
738 ay /= cov->hover_gesture.n_fingers;
740 switch (cov->hover_gesture.n_fingers) {
742 INFO("ONE FINGER HOVER");
743 _event_emit(ONE_FINGER_HOVER, ax, ay, ax, ay, state, cov->event_time);
750 static void _hover_gesture_mouse_move(Ecore_Event_Mouse_Move * ev, Cover * cov)
752 if (cov->hover_gesture.state == GESTURE_ONGOING) {
755 if (!cov->hover_gesture.longpressed)
758 for (i = 0; i < cov->hover_gesture.n_fingers; i++) {
759 if (cov->hover_gesture.finger[i] == ev->multi.device)
762 if (i == cov->hover_gesture.n_fingers) {
763 DEBUG("Invalid finger id: %d", ev->multi.device);
766 cov->hover_gesture.x[i] = ev->root.x;
767 cov->hover_gesture.y[i] = ev->root.y;
768 _hover_event_emit(cov, 1);
772 static void _tap_event_emit(Cover * cov, int state)
774 switch (cov->tap_gesture_data.n_taps) {
776 if (cov->tap_gesture_data.tap_type == ONE_FINGER_GESTURE) {
777 DEBUG("ONE_FINGER_SINGLE_TAP");
778 _event_emit(ONE_FINGER_SINGLE_TAP, cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], state, cov->event_time);
779 } else if (cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE) {
780 DEBUG("TWO_FINGERS_SINGLE_TAP");
781 _event_emit(TWO_FINGERS_SINGLE_TAP, cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1], state, cov->event_time);
782 } else if (cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE) {
783 DEBUG("THREE_FINGERS_SINGLE_TAP");
784 _event_emit(THREE_FINGERS_SINGLE_TAP, cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2], state, cov->event_time);
786 ERROR("Unknown tap");
790 if (cov->tap_gesture_data.tap_type == ONE_FINGER_GESTURE) {
791 DEBUG("ONE_FINGER_DOUBLE_TAP");
792 _event_emit(ONE_FINGER_DOUBLE_TAP, cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], state, cov->event_time);
793 } else if (cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE) {
794 DEBUG("TWO_FINGERS_DOUBLE_TAP");
795 _event_emit(TWO_FINGERS_DOUBLE_TAP, cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1], state, cov->event_time);
796 } else if (cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE) {
797 DEBUG("THREE_FINGERS_DOUBLE_TAP");
798 _event_emit(THREE_FINGERS_DOUBLE_TAP, cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2], state, cov->event_time);
800 ERROR("Unknown tap");
804 if (cov->tap_gesture_data.tap_type == ONE_FINGER_GESTURE) {
805 DEBUG("ONE_FINGER_TRIPLE_TAP");
806 _event_emit(ONE_FINGER_TRIPLE_TAP, cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], state, cov->event_time);
807 } else if (cov->tap_gesture_data.tap_type == TWO_FINGERS_GESTURE) {
808 DEBUG("TWO_FINGERS_TRIPLE_TAP");
809 _event_emit(TWO_FINGERS_TRIPLE_TAP, cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], cov->tap_gesture_data.x_org[1], cov->tap_gesture_data.y_org[1], state, cov->event_time);
810 } else if (cov->tap_gesture_data.tap_type == THREE_FINGERS_GESTURE) {
811 DEBUG("THREE_FINGERS_TRIPLE_TAP");
812 _event_emit(THREE_FINGERS_TRIPLE_TAP, cov->tap_gesture_data.x_org[0], cov->tap_gesture_data.y_org[0], cov->tap_gesture_data.x_org[2], cov->tap_gesture_data.y_org[2], state, cov->event_time);
814 ERROR("Unknown tap");
818 ERROR("Unknown tap");
823 static Eina_Bool _on_tap_timer_expire(void *data)
826 DEBUG("Timer expired");
828 if (cov->tap_gesture_data.started && !cov->tap_gesture_data.pressed)
829 _tap_event_emit(cov, 2);
831 _tap_event_emit(cov, 3);
834 cov->tap_gesture_data.started = EINA_FALSE;
835 cov->tap_gesture_data.timer = NULL;
836 cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
837 cov->tap_gesture_data.finger[0] = -1;
838 cov->tap_gesture_data.finger[1] = -1;
839 cov->tap_gesture_data.finger[2] = -1;
844 static int _tap_gesture_finger_check(Cover * cov, int x, int y)
846 int dx = x - cov->tap_gesture_data.x_org[0];
847 int dy = y - cov->tap_gesture_data.y_org[0];
849 if (cov->tap_gesture_data.finger[0] != -1 && (dx * dx + dy * dy < _e_mod_config->one_finger_tap_radius * _e_mod_config->one_finger_tap_radius)) {
853 dx = x - cov->tap_gesture_data.x_org[1];
854 dy = y - cov->tap_gesture_data.y_org[1];
855 if (cov->tap_gesture_data.finger[1] != -1 && (dx * dx + dy * dy < _e_mod_config->one_finger_tap_radius * _e_mod_config->one_finger_tap_radius)) {
859 dx = x - cov->tap_gesture_data.x_org[2];
860 dy = y - cov->tap_gesture_data.y_org[2];
861 if (cov->tap_gesture_data.finger[2] != -1 && (dx * dx + dy * dy < _e_mod_config->one_finger_tap_radius * _e_mod_config->one_finger_tap_radius)) {
868 static void _tap_gestures_mouse_down(Ecore_Event_Mouse_Button * ev, Cover * cov)
870 if (cov->n_taps > 4) {
871 ERROR("Too many fingers");
875 cov->tap_gesture_data.pressed = EINA_TRUE;
877 if (cov->tap_gesture_data.started == EINA_FALSE) {
878 DEBUG("First finger down");
879 cov->tap_gesture_data.started = EINA_TRUE;
880 cov->tap_gesture_data.finger[0] = ev->multi.device;
881 cov->tap_gesture_data.x_org[0] = ev->root.x;
882 cov->tap_gesture_data.y_org[0] = ev->root.y;
883 cov->tap_gesture_data.finger[1] = -1;
884 cov->tap_gesture_data.finger[2] = -1;
885 cov->tap_gesture_data.n_taps = 0;
886 cov->tap_gesture_data.timer = ecore_timer_add(_e_mod_config->one_finger_tap_timeout, _on_tap_timer_expire, cov);
887 cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
891 if (ev->multi.device == cov->tap_gesture_data.finger[0]) {
892 DEBUG("First finger down");
894 if (_tap_gesture_finger_check(cov, ev->root.x, ev->root.y) == -1) {
895 ERROR("Abort gesture");
896 cov->tap_gesture_data.started = EINA_FALSE;
897 ecore_timer_del(cov->tap_gesture_data.timer);
898 cov->tap_gesture_data.timer = NULL;
899 cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
900 cov->tap_gesture_data.finger[0] = -1;
901 cov->tap_gesture_data.finger[1] = -1;
902 cov->tap_gesture_data.finger[2] = -1;
903 _tap_gestures_mouse_down(ev, cov);
907 cov->tap_gesture_data.x_org[0] = ev->root.x;
908 cov->tap_gesture_data.y_org[0] = ev->root.y;
909 } else if (cov->tap_gesture_data.finger[1] == -1 || cov->tap_gesture_data.finger[1] == ev->multi.device) {
910 DEBUG("Second finger down");
911 cov->tap_gesture_data.finger[1] = ev->multi.device;
913 cov->tap_gesture_data.x_org[1] = ev->root.x;
914 cov->tap_gesture_data.y_org[1] = ev->root.y;
915 if (cov->tap_gesture_data.tap_type < TWO_FINGERS_GESTURE)
916 cov->tap_gesture_data.tap_type = TWO_FINGERS_GESTURE;
917 } else if (cov->tap_gesture_data.finger[2] == -1 || cov->tap_gesture_data.finger[2] == ev->multi.device) {
918 DEBUG("Third finger down");
919 cov->tap_gesture_data.finger[2] = ev->multi.device;
921 cov->tap_gesture_data.x_org[2] = ev->root.x;
922 cov->tap_gesture_data.y_org[2] = ev->root.y;
923 if (cov->tap_gesture_data.tap_type < THREE_FINGERS_GESTURE)
924 cov->tap_gesture_data.tap_type = THREE_FINGERS_GESTURE;
926 ERROR("Unknown finger down");
928 ecore_timer_reset(cov->tap_gesture_data.timer);
932 static void _tap_gestures_mouse_up(Ecore_Event_Mouse_Button * ev, Cover * cov)
934 if (cov->tap_gesture_data.timer) {
935 cov->tap_gesture_data.pressed = EINA_FALSE;
937 if (ev->multi.device == cov->tap_gesture_data.finger[0]) {
938 DEBUG("First finger up");
940 int dx = ev->root.x - cov->tap_gesture_data.x_org[0];
941 int dy = ev->root.y - cov->tap_gesture_data.y_org[0];
943 if ((dx * dx + dy * dy) < _e_mod_config->one_finger_tap_radius * _e_mod_config->one_finger_tap_radius) {
944 if (cov->n_taps == 0) {
945 cov->tap_gesture_data.n_taps++;
948 ERROR("Abort gesture");
949 cov->tap_gesture_data.started = EINA_FALSE;
951 } else if (ev->multi.device == cov->tap_gesture_data.finger[1]) {
952 DEBUG("Second finger up");
954 int dx = ev->root.x - cov->tap_gesture_data.x_org[1];
955 int dy = ev->root.y - cov->tap_gesture_data.y_org[1];
957 if ((dx * dx + dy * dy) < _e_mod_config->one_finger_tap_radius * _e_mod_config->one_finger_tap_radius) {
958 if (cov->n_taps == 0) {
959 cov->tap_gesture_data.n_taps++;
962 ERROR("Abort gesture");
963 cov->tap_gesture_data.started = EINA_FALSE;
965 } else if (ev->multi.device == cov->tap_gesture_data.finger[2]) {
966 DEBUG("Third finger up");
968 int dx = ev->root.x - cov->tap_gesture_data.x_org[2];
969 int dy = ev->root.y - cov->tap_gesture_data.y_org[2];
971 if ((dx * dx + dy * dy) < _e_mod_config->one_finger_tap_radius * _e_mod_config->one_finger_tap_radius) {
972 if (cov->n_taps == 0) {
973 cov->tap_gesture_data.n_taps++;
976 ERROR("Abort gesture");
977 cov->tap_gesture_data.started = EINA_FALSE;
980 ERROR("Unknown finger up, abort gesture");
981 cov->tap_gesture_data.started = EINA_FALSE;
986 static void _tap_gestures_move(Ecore_Event_Mouse_Move * ev, Cover * cov)
989 for (i = 0; i < sizeof(cov->tap_gesture_data.finger) / sizeof(cov->tap_gesture_data.finger[0]); i++) {
990 if (ev->multi.device == cov->tap_gesture_data.finger[i]) {
991 int dx = ev->root.x - cov->tap_gesture_data.x_org[i];
992 int dy = ev->root.y - cov->tap_gesture_data.y_org[i];
994 if ((dx * dx + dy * dy) > _e_mod_config->one_finger_tap_radius * _e_mod_config->one_finger_tap_radius) {
995 DEBUG("abort tap gesutre");
996 cov->tap_gesture_data.started = EINA_FALSE;
997 ecore_timer_del(cov->tap_gesture_data.timer);
998 cov->tap_gesture_data.timer = NULL;
999 cov->tap_gesture_data.tap_type = ONE_FINGER_GESTURE;
1000 cov->tap_gesture_data.finger[0] = -1;
1001 cov->tap_gesture_data.finger[1] = -1;
1002 cov->tap_gesture_data.finger[2] = -1;
1009 static Eina_Bool _cb_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1011 Ecore_Event_Mouse_Button *ev = event;
1014 cov->event_time = ev->timestamp;
1016 DEBUG("mouse down: multi.device: %d, taps: %d", ev->multi.device, cov->n_taps);
1018 win_angle = _win_angle_get();
1020 _flick_gesture_mouse_down(ev, cov);
1021 _hover_gesture_mouse_down(ev, cov);
1022 _tap_gestures_mouse_down(ev, cov);
1024 return ECORE_CALLBACK_PASS_ON;
1027 static Eina_Bool _cb_mouse_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1029 Ecore_Event_Mouse_Button *ev = event;
1032 cov->event_time = ev->timestamp;
1034 DEBUG("mouse up, multi.device: %d, taps: %d", ev->multi.device, cov->n_taps);
1036 _flick_gesture_mouse_up(ev, cov);
1037 _hover_gesture_mouse_up(ev, cov);
1038 _tap_gestures_mouse_up(ev, cov);
1040 return ECORE_CALLBACK_PASS_ON;
1043 static Eina_Bool _cb_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
1045 Ecore_Event_Mouse_Move *ev = event;
1047 cov->event_time = ev->timestamp;
1049 _flick_gesture_mouse_move(ev, cov);
1050 _hover_gesture_mouse_move(ev, cov);
1051 _tap_gestures_move(ev, cov);
1053 return ECORE_CALLBACK_PASS_ON;
1056 static Eina_Bool _gesture_input_win_create(void)
1062 Ecore_Window root = ecore_x_window_root_first_get();
1065 ecore_x_window_geometry_get(root, NULL, NULL, &w, &h);
1066 win = ecore_x_window_input_new(root, 0, 0, w, h);
1068 ecore_wl_screen_size_get(&w, &h);
1069 win = ecore_wl_window_new(NULL, 0, 0, w, h, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW);
1076 ecore_x_input_multi_select(win);
1077 ecore_x_window_show(win);
1078 ecore_x_window_raise(win);
1080 ecore_wl_window_show(win);
1081 ecore_wl_window_raise(win);
1084 memset(cov, 0x0, sizeof(Cover));
1089 static Eina_Bool _win_property_changed(void *data, int type, void *event)
1091 Ecore_X_Event_Window_Property *wp = event;
1093 if (wp->atom != ECORE_X_ATOM_NET_CLIENT_LIST_STACKING)
1096 _gesture_input_win_create();
1102 static Eina_Bool _gestures_input_window_init(void)
1105 Ecore_Window root = ecore_x_window_root_first_get();
1107 ERROR("No root window found. Is Window manager running?");
1110 ecore_x_event_mask_set(root, ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
1111 property_changed_hld = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, _win_property_changed, NULL);
1113 return _gesture_input_win_create();
1116 static void _gestures_input_widnow_shutdown(void)
1118 ecore_event_handler_del(property_changed_hld);
1121 ecore_x_window_free(win);
1123 ecore_wl_window_free(win);
1128 Eina_Bool screen_reader_gestures_init(void)
1134 ecore_wl_init(NULL);
1136 cov = calloc(sizeof(Cover), 1);
1138 if (!_gestures_input_window_init()) {
1143 _e_mod_config = calloc(sizeof(Gestures_Config), 1);
1144 _e_mod_config->one_finger_flick_min_length = 100;
1145 _e_mod_config->one_finger_flick_max_time = 400;
1146 _e_mod_config->two_finger_flick_to_scroll_timeout = 100;
1147 _e_mod_config->two_finger_flick_to_scroll_min_length = 50;
1148 _e_mod_config->one_finger_hover_longpress_timeout = 0.81;
1149 _e_mod_config->one_finger_tap_timeout = 0.4;
1150 _e_mod_config->one_finger_tap_radius = 100;
1152 handlers = eina_list_append(NULL, ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _cb_mouse_move, NULL));
1153 handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _cb_mouse_up, NULL));
1154 handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _cb_mouse_down, NULL));
1159 void screen_reader_gestures_shutdown(void)
1161 Ecore_Event_Handler *hdlr;
1162 EINA_LIST_FREE(handlers, hdlr) {
1163 ecore_event_handler_del(hdlr);
1165 _gestures_input_widnow_shutdown();
1169 ecore_wl_shutdown();
1172 free(_e_mod_config);
1176 void screen_reader_gestures_tracker_register(GestureCB cb, void *data)
1179 _global_data = data;