From 9ccb0f3fa83413b16c22d24763baf9e25a5bab31 Mon Sep 17 00:00:00 2001 From: JengHyun Kang Date: Tue, 21 Feb 2017 11:03:54 +0900 Subject: [PATCH] Add a tap gesture Change-Id: I8d9c594ac12c8748542fd95a7b83113593f075ca --- src/e_mod_gesture_events.c | 334 +++++++++++++++++++++++++++++++++++++++++++-- src/e_mod_main.c | 105 +++++++++++++- src/e_mod_main.h | 72 +++++++++- 3 files changed, 498 insertions(+), 13 deletions(-) diff --git a/src/e_mod_gesture_events.c b/src/e_mod_gesture_events.c index e1de548..d95ae94 100644 --- a/src/e_mod_gesture_events.c +++ b/src/e_mod_gesture_events.c @@ -431,6 +431,291 @@ _e_gesture_process_edge_swipe_up(Ecore_Event_Mouse_Button *ev) _e_gesture_edge_swipe_cancel(); } +unsigned int +e_gesture_util_tap_max_fingers_get(void) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + int i; + unsigned int max = 0; + + for (i = 0; i < E_GESTURE_FINGER_MAX +1; i++) + { + if (taps->fingers[i].enabled) max = i; + } + + return max; +} + +unsigned int +e_gesture_util_tap_max_repeats_get(unsigned int fingers) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + int i; + unsigned int max = 0; + + for (i = 0; i < E_GESTURE_TAP_REPEATS_MAX + 1; i++) + { + if (taps->fingers[fingers].repeats[i].client) max = i; + } + + return max; +} + +static void +_e_gesture_tap_cancel(void) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + + if (taps->start_timer) + { + ecore_timer_del(taps->start_timer); + taps->start_timer = NULL; + } + if (taps->done_timer) + { + ecore_timer_del(taps->done_timer); + taps->done_timer = NULL; + } + if (taps->interval_timer) + { + ecore_timer_del(taps->interval_timer); + taps->interval_timer = NULL; + } + + taps->repeats = 0; + taps->enabled_finger = 0; + taps->state = E_GESTURE_TAP_STATE_READY; + gesture->gesture_filter |= TIZEN_GESTURE_TYPE_TAP; + _e_gesture_event_flush(); + gesture->gesture_events.recognized_gesture &= ~TIZEN_GESTURE_TYPE_TAP; +} + +static void +_e_gesture_send_tap(int fingers, int repeats, struct wl_client *client, struct wl_resource *res) +{ + GTINF("Send Tap gesture. %d fingers %d repeats to client (%p)\n", fingers, repeats, client); + tizen_gesture_send_tap(res, TIZEN_GESTURE_MODE_DONE, fingers, repeats); + _e_gesture_event_drop(); + gesture->gesture_events.recognized_gesture |= TIZEN_GESTURE_TYPE_TAP; + + _e_gesture_tap_cancel(); +} + +static Eina_Bool +_e_gesture_timer_tap_start(void *data) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + + if (taps->fingers[taps->enabled_finger].enabled) + { + taps->state = E_GESTURE_TAP_STATE_PROCESS; + } + else + { + _e_gesture_tap_cancel(); + } + + taps->start_timer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_e_gesture_timer_tap_done(void *data) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + + if (gesture->gesture_events.num_pressed) + { + _e_gesture_tap_cancel(); + } + + taps->done_timer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +_e_gesture_timer_tap_interval(void *data) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + + if (taps->fingers[taps->enabled_finger].repeats[taps->repeats].client) + { + _e_gesture_send_tap(taps->enabled_finger, taps->repeats, + taps->fingers[taps->enabled_finger].repeats[taps->repeats].client, + taps->fingers[taps->enabled_finger].repeats[taps->repeats].res); + gesture->event_state = E_GESTURE_EVENT_STATE_KEEP; + gesture->gesture_events.recognized_gesture &= ~TIZEN_GESTURE_TYPE_TAP; + gesture->gesture_filter = E_GESTURE_TYPE_ALL & ~gesture->grabbed_gesture; + } + else + { + _e_gesture_tap_cancel(); + + gesture->event_state = E_GESTURE_EVENT_STATE_KEEP; + gesture->gesture_filter = E_GESTURE_TYPE_ALL & ~gesture->grabbed_gesture; + } + + taps->interval_timer = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void +_e_gesture_tap_start(void) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + + taps->state = E_GESTURE_TAP_STATE_START; + if (!taps->start_timer) + { + taps->start_timer = ecore_timer_add(E_GESTURE_TAP_START_TIME, _e_gesture_timer_tap_start, NULL); + } + if (!taps->done_timer) + { + taps->done_timer = ecore_timer_add(E_GESTURE_TAP_DONE_TIME, _e_gesture_timer_tap_done, NULL); + } +} + +static void +_e_gesture_tap_done(void) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + + if (taps->repeats >= E_GESTURE_TAP_REPEATS_MAX) + _e_gesture_tap_cancel(); + + if (!taps->fingers[taps->enabled_finger].enabled) + _e_gesture_tap_cancel(); + + if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_TAP) && + gesture->gesture_events.num_pressed == 0) + { + taps->state = E_GESTURE_TAP_STATE_WAIT; + taps->repeats++; + if (taps->done_timer) + { + ecore_timer_del(taps->done_timer); + taps->done_timer = NULL; + } + if (taps->repeats == taps->fingers[taps->enabled_finger].max_repeats) + { + ecore_timer_del(taps->interval_timer); + _e_gesture_timer_tap_interval(NULL); + } + else + { + if (!taps->interval_timer) + { + taps->interval_timer = ecore_timer_add(E_GESTURE_TAP_INTERVAL_TIME, _e_gesture_timer_tap_interval, NULL); + } + } + } +} + +static void +_e_gesture_process_tap_down(Ecore_Event_Mouse_Button *ev) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + + if (taps->enabled_finger < gesture->gesture_events.num_pressed) + taps->enabled_finger = gesture->gesture_events.num_pressed; + + if (taps->enabled_finger > taps->max_fingers) + _e_gesture_tap_cancel(); + + switch (taps->state) + { + case E_GESTURE_TAP_STATE_NONE: + return; + + case E_GESTURE_TAP_STATE_READY: + _e_gesture_tap_start(); + break; + + case E_GESTURE_TAP_STATE_START: + break; + + case E_GESTURE_TAP_STATE_PROCESS: + _e_gesture_tap_cancel(); + break; + + case E_GESTURE_TAP_STATE_WAIT: + if (taps->interval_timer) + { + ecore_timer_del(taps->interval_timer); + taps->interval_timer = NULL; + } + _e_gesture_tap_start(); + break; + + case E_GESTURE_TAP_STATE_DONE: + break; + + default: + break; + } +} + +static void +_e_gesture_process_tap_move(Ecore_Event_Mouse_Move *ev) +{ + int diff_x, diff_y; + + diff_x = gesture->gesture_events.base_point[ev->multi.device].axis.x - ev->x; + diff_y = gesture->gesture_events.base_point[ev->multi.device].axis.y - ev->y; + + if (ABS(diff_x) > E_GESTURE_TAP_MOVING_LANGE || + ABS(diff_y) > E_GESTURE_TAP_MOVING_LANGE) + { + GTDBG("%d finger moving too large diff: (%d, %d)\n", ev->multi.device, diff_x, diff_y); + _e_gesture_tap_cancel(); + } +} + +static void +_e_gesture_process_tap_up(Ecore_Event_Mouse_Button *ev) +{ + E_Gesture_Event_Tap *taps = &gesture->gesture_events.taps; + + switch (taps->state) + { + case E_GESTURE_TAP_STATE_NONE: + return; + + case E_GESTURE_TAP_STATE_READY: + _e_gesture_tap_cancel(); + break; + + case E_GESTURE_TAP_STATE_START: + taps->state = E_GESTURE_TAP_STATE_PROCESS; + if (taps->start_timer) + { + ecore_timer_del(taps->start_timer); + taps->start_timer = NULL; + } + _e_gesture_tap_done(); + break; + + case E_GESTURE_TAP_STATE_PROCESS: + _e_gesture_tap_done(); + break; + + case E_GESTURE_TAP_STATE_WAIT: + if (taps->interval_timer) + { + ecore_timer_del(taps->interval_timer); + taps->interval_timer = NULL; + } + _e_gesture_tap_start(); + break; + + case E_GESTURE_TAP_STATE_DONE: + break; + + default: + break; + } +} + static E_Gesture_Event_State _e_gesture_process_mouse_button_down(void *event) { @@ -449,6 +734,10 @@ _e_gesture_process_mouse_button_down(void *event) return E_GESTURE_EVENT_STATE_PROPAGATE; } + gesture->gesture_events.base_point[ev->multi.device].pressed = EINA_TRUE; + gesture->gesture_events.base_point[ev->multi.device].axis.x = ev->x; + gesture->gesture_events.base_point[ev->multi.device].axis.y = ev->y; + if (gesture->gesture_events.recognized_gesture) { return E_GESTURE_EVENT_STATE_IGNORE; @@ -466,6 +755,10 @@ _e_gesture_process_mouse_button_down(void *event) { _e_gesture_process_edge_swipe_down(ev); } + if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_TAP)) + { + _e_gesture_process_tap_down(ev); + } return gesture->event_state; } @@ -483,6 +776,23 @@ _e_gesture_process_mouse_button_up(void *event) { return E_GESTURE_EVENT_STATE_PROPAGATE; } + if (ev->multi.device > E_GESTURE_FINGER_MAX) + { + return E_GESTURE_EVENT_STATE_PROPAGATE; + } + + gesture->gesture_events.base_point[ev->multi.device].pressed = EINA_FALSE; + gesture->gesture_events.base_point[ev->multi.device].axis.x = 0; + gesture->gesture_events.base_point[ev->multi.device].axis.y = 0; + + if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_EDGE_SWIPE)) + { + _e_gesture_process_edge_swipe_up(ev); + } + if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_TAP)) + { + _e_gesture_process_tap_up(ev); + } if (gesture->gesture_events.recognized_gesture) { @@ -493,11 +803,6 @@ _e_gesture_process_mouse_button_up(void *event) return E_GESTURE_EVENT_STATE_IGNORE; } - if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_EDGE_SWIPE)) - { - _e_gesture_process_edge_swipe_up(ev); - } - return gesture->event_state; } @@ -511,6 +816,10 @@ _e_gesture_process_mouse_move(void *event) { return E_GESTURE_EVENT_STATE_PROPAGATE; } + if (ev->multi.device > E_GESTURE_FINGER_MAX) + { + return E_GESTURE_EVENT_STATE_PROPAGATE; + } if (gesture->gesture_events.num_pressed == 0) { return gesture->event_state; @@ -519,6 +828,10 @@ _e_gesture_process_mouse_move(void *event) { return E_GESTURE_EVENT_STATE_PROPAGATE; } + if (gesture->gesture_events.base_point[ev->multi.device].pressed != EINA_TRUE) + { + return gesture->event_state; + } if (gesture->gesture_events.recognized_gesture) { return E_GESTURE_EVENT_STATE_IGNORE; @@ -528,6 +841,10 @@ _e_gesture_process_mouse_move(void *event) { _e_gesture_process_edge_swipe_move(ev); } + if (!(gesture->gesture_filter & TIZEN_GESTURE_TYPE_TAP)) + { + _e_gesture_process_tap_move(ev); + } return gesture->event_state; } @@ -602,9 +919,10 @@ e_gesture_process_events(void *event, int type) if (gesture->gesture_events.num_pressed == 0&& type == ECORE_EVENT_MOUSE_BUTTON_UP) { - if ((gesture->grabbed_gesture & TIZEN_GESTURE_TYPE_EDGE_SWIPE) && - gesture->gesture_events.edge_swipes.event_keep) - gesture->event_state = E_GESTURE_EVENT_STATE_KEEP; + if (gesture->grabbed_gesture & TIZEN_GESTURE_TYPE_TAP || + ((gesture->grabbed_gesture & TIZEN_GESTURE_TYPE_EDGE_SWIPE) && + gesture->gesture_events.edge_swipes.event_keep)) + gesture->event_state = E_GESTURE_EVENT_STATE_KEEP; gesture->gesture_filter = E_GESTURE_TYPE_ALL & ~gesture->grabbed_gesture; } diff --git a/src/e_mod_main.c b/src/e_mod_main.c index 8ee5dbd..7f1a86e 100644 --- a/src/e_mod_main.c +++ b/src/e_mod_main.c @@ -291,9 +291,112 @@ notify: return; } +static void +_e_gesture_cb_grab_tap(struct wl_client *client, + struct wl_resource *resource, + uint32_t fingers, uint32_t repeats) +{ + E_Gesture_Event *gev; + int ret = TIZEN_GESTURE_ERROR_NONE; + + GTINF("client %p requested to grab tap gesture (fingers: %d, repeats: %d)\n", client, fingers, repeats); + + if (fingers > E_GESTURE_FINGER_MAX || repeats > E_GESTURE_TAP_REPEATS_MAX) + { + GTWRN("Not supported fingers /repeats bigger than their maximum values\n"); + ret = TIZEN_GESTURE_ERROR_INVALID_DATA; + goto finish; + } + + gev = &gesture->gesture_events; + + if (gev->taps.fingers[fingers].repeats[repeats].client) + { + GTWRN("%d finger %d repeats is already grabbed by %p client\n", fingers, repeats, gev->taps.fingers[fingers].repeats[repeats].client); + ret = TIZEN_GESTURE_ERROR_GRABBED_ALREADY; + goto finish; + } + + gev->taps.fingers[fingers].repeats[repeats].client = client; + gev->taps.fingers[fingers].repeats[repeats].res = resource; + gev->taps.fingers[fingers].enabled = EINA_TRUE; + + if (gev->taps.max_fingers < fingers) + gev->taps.max_fingers = fingers; + if (gev->taps.fingers[fingers].max_repeats < repeats) + gev->taps.fingers[fingers].max_repeats = repeats; + + gesture->grabbed_gesture |= TIZEN_GESTURE_TYPE_TAP; + gev->taps.state = E_GESTURE_TAP_STATE_READY; + gesture->event_state = E_GESTURE_EVENT_STATE_KEEP; + gesture->gesture_filter = E_GESTURE_TYPE_ALL & ~gesture->grabbed_gesture; + +finish: + tizen_gesture_send_tap_notify(resource, fingers, repeats, ret); +} + +static void +_e_gesture_cb_ungrab_tap(struct wl_client *client, + struct wl_resource *resource, + uint32_t fingers, uint32_t repeats) +{ + int i; + E_Gesture_Event *gev; + int ret = TIZEN_GESTURE_ERROR_NONE; + + GTINF("client %p requested to ungrab tap gesture (fingers: %d, repeats: %d)\n", client, fingers, fingers); + + if (fingers > E_GESTURE_FINGER_MAX || repeats > E_GESTURE_TAP_REPEATS_MAX) + { + GTWRN("Not supported fingers /repeats bigger than their maximum values\n"); + ret = TIZEN_GESTURE_ERROR_INVALID_DATA; + goto finish; + } + + gev = &gesture->gesture_events; + + if (gev->taps.fingers[fingers].repeats[repeats].client == client) + { + gev->taps.fingers[fingers].repeats[repeats].client = NULL; + gev->taps.fingers[fingers].repeats[repeats].res = NULL; + } + + gev->taps.fingers[fingers].enabled = EINA_FALSE; + for (i = 0; i < E_GESTURE_TAP_REPEATS_MAX; i++) + { + if (gev->taps.fingers[fingers].repeats[i].client) + { + gev->taps.fingers[fingers].enabled = EINA_TRUE; + break; + } + } + + gesture->grabbed_gesture &= ~TIZEN_GESTURE_TYPE_TAP; + gev->taps.state = E_GESTURE_TAP_STATE_NONE; + gesture->event_state = E_GESTURE_EVENT_STATE_PROPAGATE; + for (i = 0; i < E_GESTURE_FINGER_MAX; i++) + { + if (gev->taps.fingers[i].enabled) + { + gesture->grabbed_gesture |= TIZEN_GESTURE_TYPE_TAP; + gev->taps.state = E_GESTURE_TAP_STATE_READY; + gesture->event_state = E_GESTURE_EVENT_STATE_KEEP; + break; + } + } + + gev->taps.max_fingers = e_gesture_util_tap_max_fingers_get(); + gev->taps.fingers[fingers].max_repeats = e_gesture_util_tap_max_repeats_get(fingers); + +finish: + tizen_gesture_send_tap_notify(resource, fingers, repeats, ret); +} + static const struct tizen_gesture_interface _e_gesture_implementation = { _e_gesture_cb_grab_edge_swipe, - _e_gesture_cb_ungrab_edge_swipe + _e_gesture_cb_ungrab_edge_swipe, + _e_gesture_cb_grab_tap, + _e_gesture_cb_ungrab_tap }; /* tizen_gesture global object destroy function */ diff --git a/src/e_mod_main.h b/src/e_mod_main.h index 96c3cd8..67fa909 100644 --- a/src/e_mod_main.h +++ b/src/e_mod_main.h @@ -12,8 +12,8 @@ #define GTDBG(msg, ARG...) DBG("[tizen_gesture][%s:%d] "msg, __FUNCTION__, __LINE__, ##ARG) #define E_GESTURE_FINGER_MAX 3 -#define E_GESTURE_TYPE_MAX TIZEN_GESTURE_TYPE_EDGE_SWIPE+1 -#define E_GESTURE_TYPE_ALL TIZEN_GESTURE_TYPE_EDGE_SWIPE +#define E_GESTURE_TYPE_MAX TIZEN_GESTURE_TYPE_TAP+1 +#define E_GESTURE_TYPE_ALL (TIZEN_GESTURE_TYPE_EDGE_SWIPE | TIZEN_GESTURE_TYPE_TAP) #define E_GESTURE_KEYBOARD_NAME "Gesture Keyboard" #define E_GESTURE_AUX_HINT_GESTURE_DISABLE "wm.policy.win.gesture.disable" @@ -30,7 +30,13 @@ #define E_GESTURE_EDGE_SWIPE_BACK_KEY 166 #define E_GESTURE_EDGE_SWIPE_BACK_DEFAULT_ENABLE EINA_TRUE -#define ABS(x) ((x)>0)?(x):-(x) +#define E_GESTURE_TAP_REPEATS_MAX 3 +#define E_GESTURE_TAP_START_TIME 0.05 +#define E_GESTURE_TAP_DONE_TIME 1 +#define E_GESTURE_TAP_INTERVAL_TIME 1 +#define E_GESTURE_TAP_MOVING_LANGE 25 + +#define ABS(x) (((x)>0)?(x):-(x)) typedef struct _E_Gesture E_Gesture; typedef struct _E_Gesture* E_GesturePtr; @@ -42,11 +48,17 @@ typedef struct _E_Gesture_Grabbed_Client E_Gesture_Grabbed_Client; typedef struct _E_Gesture_Conf_Edd E_Gesture_Conf_Edd; typedef struct _E_Gesture_Config_Data E_Gesture_Config_Data; +typedef struct _E_Gesture_Event_Tap_Finger_Repeats E_Gesture_Event_Tap_Finger_Repeats; +typedef struct _E_Gesture_Event_Tap_Finger E_Gesture_Event_Tap_Finger; +typedef struct _E_Gesture_Event_Tap E_Gesture_Event_Tap; + typedef struct _Coords Coords; +typedef struct _E_Gesture_Finger E_Gesture_Finger; typedef struct _E_Gesture_Event_Info E_Gesture_Event_Info; typedef enum _E_Gesture_Edge E_Gesture_Edge; typedef enum _E_Gesture_Event_State E_Gesture_Event_State; +typedef enum _E_Gesture_Tap_State E_Gesture_Tap_State; extern E_GesturePtr gesture; @@ -69,11 +81,27 @@ enum _E_Gesture_Event_State E_GESTURE_EVENT_STATE_IGNORE }; +enum _E_Gesture_Tap_State +{ + E_GESTURE_TAP_STATE_NONE, + E_GESTURE_TAP_STATE_READY, // tap is required, idle + E_GESTURE_TAP_STATE_START, // first finger is pressed + E_GESTURE_TAP_STATE_PROCESS, // all fingers are pressed or first release + E_GESTURE_TAP_STATE_WAIT, // all fingers are released and wait next tap + E_GESTURE_TAP_STATE_DONE +}; + struct _Coords { int x, y; }; +struct _E_Gesture_Finger +{ + Eina_Bool pressed; + Coords axis; +}; + struct _E_Gesture_Event_Info { int type; @@ -144,9 +172,41 @@ struct _E_Gesture_Event_Edge_Swipe Eina_Bool event_keep; }; +struct _E_Gesture_Event_Tap_Finger_Repeats +{ + struct wl_client *client; + struct wl_resource *res; +}; + +struct _E_Gesture_Event_Tap_Finger +{ + Eina_Bool enabled; + unsigned int max_repeats; + E_Gesture_Event_Tap_Finger_Repeats repeats[E_GESTURE_TAP_REPEATS_MAX+1]; +}; + +struct _E_Gesture_Event_Tap +{ + E_Gesture_Event_Tap_Finger fingers[E_GESTURE_FINGER_MAX+1]; + E_Gesture_Tap_State state; + unsigned int enabled_finger; + unsigned int repeats; + unsigned int max_fingers; + + /* pressed timer */ + Ecore_Timer *start_timer; + /* release timer */ + Ecore_Timer *done_timer; + /* interval timer */ + Ecore_Timer *interval_timer; +}; + struct _E_Gesture_Event { E_Gesture_Event_Edge_Swipe edge_swipes; + E_Gesture_Event_Tap taps; + + E_Gesture_Finger base_point[E_GESTURE_FINGER_MAX + 1]; int num_pressed; Eina_Bool recognized_gesture; @@ -171,7 +231,7 @@ struct _E_Gesture char *kbd_identifier; char *kbd_name; Ecore_Device *kbd_device; - }device; + } device; unsigned int grabbed_gesture; E_Gesture_Event gesture_events; @@ -205,4 +265,8 @@ void e_gesture_device_keydev_set(char *option); void e_gesture_event_filter_enable(Eina_Bool enabled); +/* Util functions */ +unsigned int e_gesture_util_tap_max_fingers_get(void); +unsigned int e_gesture_util_tap_max_repeats_get(unsigned int); + #endif -- 2.7.4