e_keyrouter: add longpress and composition key functions 39/223739/11
authorjeon <jhyuni.kang@samsung.com>
Mon, 3 Feb 2020 12:32:47 +0000 (21:32 +0900)
committerjeon <jhyuni.kang@samsung.com>
Fri, 7 Feb 2020 08:25:40 +0000 (17:25 +0900)
Change-Id: I9f104c5e45cbee9fc752ea0329708d60fdb18c47

src/bin/e_keyrouter.c
src/bin/e_keyrouter.h
src/bin/e_keyrouter_conf.c
src/bin/e_keyrouter_events.c
src/bin/e_keyrouter_private.h

index b231a72843d4fc2654fc42b7c0f3dd1870b856cd..1e922fb19e67c6c4f2a6d941baa526da126e2f2b 100644 (file)
@@ -16,6 +16,10 @@ int _keyrouter_log_dom = -1;
 E_API E_Keyrouter_Info e_keyrouter;
 E_KeyrouterPtr krt;
 
+E_API int E_KEYROUTER_EVENT_KEY_LONG = 0;
+E_API int E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS = 0;
+E_API int E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE = 0;
+
 E_API E_Keyrouter_Intercept_Hook *
 e_keyrouter_intercept_hook_add(E_Keyrouter_Intercept_Hook_Point hookpoint, E_Keyrouter_Intercept_Hook_Cb func, const void *data)
 {
@@ -439,6 +443,135 @@ _e_keyrouter_max_keycode_get(void)
    return krt->max_tizen_hwkeys;
 }
 
+E_API int
+e_keyrouter_longkey_add(int keycode, double time)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(krt, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(keycode <= krt->max_tizen_hwkeys, EINA_FALSE);
+
+   if (krt->HardKeys[keycode].longkey.enabled == EINA_TRUE)
+     {
+        KLWRN("The %d keycode'long press is already enabled by time: %lf\n", keycode, krt->HardKeys[keycode].longkey.time);
+        return EINA_FALSE;
+     }
+
+   krt->HardKeys[keycode].longkey.enabled = EINA_TRUE;
+   krt->HardKeys[keycode].longkey.time = time;
+
+   KLINF("To enable %d key's longkey function. (time: %lf)\n", keycode, time);
+
+   return EINA_TRUE;
+}
+
+E_API void
+e_keyrouter_longkey_del(int keycode)
+{
+   /* FIXME: If del request is came, during checking long press,
+             How control this behavior?
+             Cancel current long press or not
+    */
+
+   krt->HardKeys[keycode].longkey.enabled = EINA_FALSE;
+   krt->HardKeys[keycode].longkey.time = 0.0;
+
+   KLINF("To disable %d key's longkey function.\n", keycode);
+}
+
+E_API int
+e_keyrouter_composition_key_add(int *keys, int count)
+{
+   Eina_List *l;
+   int *data, *data2;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(krt, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(keys[0] <= krt->max_tizen_hwkeys, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(keys[1] <= krt->max_tizen_hwkeys, EINA_FALSE);
+
+   if (count != 2)
+     {
+        KLWRN("Currently only two key composition is allowed. (%d)\n", count);
+        return EINA_FALSE;
+     }
+
+   EINA_LIST_FOREACH(krt->HardKeys[keys[0]].composition_key_list, l, data)
+     {
+        if (*data == keys[1])
+          {
+             KLWRN("%d and %d key's key composition is already requested.\n", keys[0], keys[1]);
+             return EINA_FALSE;
+          }
+     }
+   EINA_LIST_FOREACH(krt->HardKeys[keys[1]].composition_key_list, l, data)
+     {
+        if (*data == keys[0])
+          {
+             KLERR("%d and %d key's key composition is already requested. (list currupted)\n", keys[0], keys[1]);
+             return EINA_FALSE;
+          }
+     }
+
+   data = E_NEW(int, 1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
+
+   data2 = E_NEW(int, 1);
+   EINA_SAFETY_ON_NULL_GOTO(data2, failed);
+
+   *data = keys[0];
+   *data2 = keys[1];
+
+   krt->HardKeys[keys[0]].composition_key_list = eina_list_append(krt->HardKeys[keys[0]].composition_key_list, data2);
+   krt->HardKeys[keys[1]].composition_key_list = eina_list_append(krt->HardKeys[keys[1]].composition_key_list, data);
+
+   KLINF("Add %d and %d key composition.\n", keys[0], keys[1]);
+
+   return EINA_TRUE;
+
+failed:
+   if (data) E_FREE(data);
+
+   return EINA_FALSE;
+}
+
+E_API void
+e_keyrouter_composition_key_del(int *keys, int count)
+{
+   /* FIXME: If del request is came, during checking composition key about key press,
+             How control this behavior?
+             Cancel current composition key or not
+    */
+   Eina_List *l, *l_next;
+   int *data;
+
+   if (count != 2)
+     {
+        KLWRN("Currently only two key composition is allowed. (%d)\n", count);
+        return;
+     }
+
+   EINA_LIST_FOREACH_SAFE(krt->HardKeys[keys[0]].composition_key_list, l, l_next, data)
+     {
+        if (*data == keys[1])
+          {
+             krt->HardKeys[keys[0]].composition_key_list = eina_list_remove_list(krt->HardKeys[keys[0]].composition_key_list, l);
+             E_FREE(data);
+             break;
+          }
+     }
+
+   EINA_LIST_FOREACH_SAFE(krt->HardKeys[keys[1]].composition_key_list, l, l_next, data)
+     {
+        if (*data == keys[0])
+          {
+             krt->HardKeys[keys[1]].composition_key_list = eina_list_remove_list(krt->HardKeys[keys[1]].composition_key_list, l);
+             E_FREE(data);
+             break;
+          }
+     }
+
+   KLINF("Delete %d and %d key composition.\n", keys[0], keys[1]);
+}
+
+
 E_API int
 e_keyrouter_init(void)
 {
@@ -464,6 +597,8 @@ e_keyrouter_init(void)
    krt->conf = kconfig;
    krt->pictureoff_disabled = !!kconfig->conf->pictureoff_disabled;
 
+   krt->composition_key.waiting_time = kconfig->conf->composition_key_wait_time;
+
    res = e_keyrouter_wl_init();
    EINA_SAFETY_ON_FALSE_GOTO(res, err);
 
@@ -479,6 +614,13 @@ e_keyrouter_init(void)
    e_keyrouter.keygrab_list_get = _e_keyrouter_keygrab_list_get;
    e_keyrouter.max_keycode_get = _e_keyrouter_max_keycode_get;
 
+   if (!E_KEYROUTER_EVENT_KEY_LONG)
+     E_KEYROUTER_EVENT_KEY_LONG = ecore_event_type_new();
+   if (!E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS)
+     E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS = ecore_event_type_new();
+   if (!E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE)
+     E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE = ecore_event_type_new();
+
    TRACE_INPUT_END();
    return EINA_TRUE;
 
@@ -514,12 +656,33 @@ e_keyrouter_shutdown(void)
      {
         if (krt->HardKeys[i].keyname)
           eina_stringshare_del(krt->HardKeys[i].keyname);
+        EINA_LIST_FREE(krt->HardKeys[i].composition_key_list, keycode_data)
+          E_FREE(keycode_data);
      }
    E_FREE(krt->HardKeys);
 
    EINA_LIST_FREE(krt->ignore_list, keycode_data)
      E_FREE(keycode_data);
 
+   ecore_event_type_flush(E_KEYROUTER_EVENT_KEY_LONG,
+                          E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS,
+                          E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE);
+
+   E_KEYROUTER_EVENT_KEY_LONG = 0;
+   E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS = 0;
+   E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE = 0;
+
+   if (krt->composition_key.waiting_timer)
+     {
+        ecore_timer_del(krt->composition_key.waiting_timer);
+        krt->composition_key.waiting_timer = NULL;
+     }
+   if (krt->longkey.timer)
+     {
+        ecore_timer_del(krt->longkey.timer);
+        krt->longkey.timer = NULL;
+     }
+
    e_keyrouter_wl_shutdown();
 
    E_FREE(krt);
index d8b30c5e7bf2816b1863c396745d0f4f3055668c..c6b2a4ff6ab402baadb541e3c4422e19465b04af 100644 (file)
@@ -9,6 +9,9 @@ typedef struct _E_Keyrouter_Grabbed_Key E_Keyrouter_Grabbed_Key;
 typedef struct _E_Keyrouter_Registered_Window_Info E_Keyrouter_Registered_Window_Info;
 typedef struct _E_Keyrouter_Event_Data E_Keyrouter_Event_Data;
 
+typedef struct _E_Keyrouter_Event_Key_Long E_Keyrouter_Event_Key_Long;
+typedef struct _E_Keyrouter_Event_Key_Composition E_Keyrouter_Event_Key_Composition;
+
 typedef enum _E_Keyrouter_Intercept_Hook_Point
 {
    E_KEYROUTER_INTERCEPT_HOOK_BEFORE_KEYROUTING,
@@ -31,6 +34,10 @@ typedef Eina_Bool (*E_Keyrouter_Intercept_Hook_Cb) (void *data, int type, Ecore_
 
 extern E_API E_Keyrouter_Info e_keyrouter;
 
+extern E_API int E_KEYROUTER_EVENT_KEY_LONG;
+extern E_API int E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS;
+extern E_API int E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE;
+
 struct _E_Keyrouter_Intercept_Hook
 {
    EINA_INLIST;
@@ -75,6 +82,14 @@ struct _E_Keyrouter_Grabbed_Key
    Eina_Bool no_privcheck;
    Eina_Bool repeat;
 
+   struct
+     {
+        Eina_Bool enabled;
+        double time;
+     } longkey;
+
+   Eina_List *composition_key_list;
+
    Eina_List *excl_ptr;
    Eina_List *or_excl_ptr;
    Eina_List *top_ptr;
@@ -95,6 +110,21 @@ struct _E_Keyrouter_Event_Data
    void *data;
 };
 
+struct _E_Keyrouter_Event_Key_Long
+{
+   int keycode;
+
+   void *data;
+};
+
+struct _E_Keyrouter_Event_Key_Composition
+{
+   int keys[2];
+   unsigned int timestamp;
+
+   void *data;
+};
+
 E_API E_Keyrouter_Intercept_Hook *e_keyrouter_intercept_hook_add(E_Keyrouter_Intercept_Hook_Point hookpoint, E_Keyrouter_Intercept_Hook_Cb func, const void *data);
 E_API void e_keyrouter_intercept_hook_del(E_Keyrouter_Intercept_Hook *ch);
 E_API Eina_Bool e_keyrouter_intercept_hook_call(E_Keyrouter_Intercept_Hook_Point hookpoint, int type, Ecore_Event_Key *event);
@@ -102,6 +132,10 @@ E_API Eina_Bool e_keyrouter_intercept_hook_call(E_Keyrouter_Intercept_Hook_Point
 E_API int e_keyrouter_init(void);
 E_API int e_keyrouter_shutdown(void);
 
+E_API int e_keyrouter_longkey_add(int keycode, double time);
+E_API void e_keyrouter_longkey_del(int keycode);
+E_API int e_keyrouter_composition_key_add(int *keys, int count);
+E_API void e_keyrouter_composition_key_del(int *keys, int count);
 
 #endif
 #endif
index 4de89dae603c458aeafd4fc3139a1924caa37afb..8e4b7be4a8889b840485b88446af67c3e99f7ec4 100644 (file)
@@ -22,6 +22,7 @@ e_keyrouter_conf_init(E_Keyrouter_Config_Data *kconfig)
    E_CONFIG_VAL(D, T, num_keycode, INT);
    E_CONFIG_VAL(D, T, max_keycode, INT);
    E_CONFIG_VAL(D, T, pictureoff_disabled, INT);
+   E_CONFIG_VAL(D, T, composition_key_wait_time, DOUBLE);
    E_CONFIG_LIST(D, T, KeyList, kconfig->conf_hwkeys_edd);
 
 #undef T
@@ -30,7 +31,11 @@ e_keyrouter_conf_init(E_Keyrouter_Config_Data *kconfig)
 
    if (!kconfig->conf)
      {
-        KLDBG("Failed to find module.keyrouter config file.");
+        KLWRN("Failed to find module.keyrouter config file.");
+     }
+   else if (!kconfig->conf->composition_key_wait_time)
+     {
+        kconfig->conf->composition_key_wait_time = 0.3;
      }
 }
 
index 65b8f6f34098e9a2516550946595c178eeb6413a..28afc57edaab78330471c43240bea9354cb8dde4 100644 (file)
@@ -69,6 +69,330 @@ _e_keyrouter_event_routed_key_check(Ecore_Event_Key *ev, int type)
    return EINA_TRUE;
 }
 
+static void
+_e_keyrouter_key_free(Ecore_Event_Key *ev)
+{
+   if (!ev) return;
+
+   eina_stringshare_del(ev->keyname);
+   eina_stringshare_del(ev->key);
+   eina_stringshare_del(ev->string);
+   eina_stringshare_del(ev->compose);
+
+   if (ev->data) E_FREE(ev->data);
+   if (ev->dev) ecore_device_unref(ev->dev);
+
+   E_FREE(ev);
+}
+
+static Ecore_Event_Key *
+_e_keyrouter_key_create(char *keyname)
+{
+   Ecore_Event_Key *ev_key;
+   E_Keyrouter_Event_Data *key_data;
+   int keycode;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(keyname, NULL);
+
+   ev_key = E_NEW(Ecore_Event_Key, 1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev_key, NULL);
+
+   key_data = E_NEW(E_Keyrouter_Event_Data, 1);
+   EINA_SAFETY_ON_NULL_GOTO(key_data, failed);
+
+   keycode = e_keyrouter_util_keycode_get_from_string(keyname);
+   EINA_SAFETY_ON_FALSE_GOTO((0 < keycode && keycode <= krt->max_tizen_hwkeys), failed);
+
+   ev_key->key = (char *)eina_stringshare_add(keyname);
+   ev_key->keyname = (char *)eina_stringshare_add(ev_key->key);
+   ev_key->compose = (char *)eina_stringshare_add(ev_key->key);
+   ev_key->timestamp = (int)(ecore_time_get()*1000);
+   ev_key->same_screen = 1;
+
+   ev_key->window = e_comp->ee_win;
+   ev_key->event_window = e_comp->ee_win;
+   ev_key->root_window = e_comp->ee_win;
+   ev_key->keycode = keycode;
+   ev_key->data = key_data;
+
+   return ev_key;
+
+failed:
+   if (ev_key) E_FREE(ev_key);
+   if (key_data) E_FREE(key_data);
+   return NULL;
+}
+
+static void
+_e_keyrouter_key_send(int type, Ecore_Event_Key *ev, E_Keyrouter_Key_List_NodePtr key_node)
+{
+   Eina_Bool res_hook = EINA_TRUE;
+   E_Keyrouter_Event_Data *key_data = NULL;
+
+   if (key_node->focused)
+     {
+        res_hook = e_keyrouter_intercept_hook_call(E_KEYROUTER_INTERCEPT_HOOK_DELIVER_FOCUS, type, ev);
+        key_data = (E_Keyrouter_Event_Data *)ev->data;
+
+        if (!res_hook || key_data->ignored)
+          {
+             KLINF("This hook is called to notify a current key is cancel. Please check why hook returns FALSE or ignored.\n");
+          }
+     }
+   e_keyrouter_wl_key_send(ev, (type == ECORE_EVENT_KEY_DOWN)?EINA_TRUE:EINA_FALSE,
+                           key_node->wc, key_node->surface, key_node->focused);
+}
+
+static void
+_e_keyrouter_key_cancel(int keycode)
+{
+   Ecore_Event_Key *key_cancel, *key_release;
+   Eina_List *l;
+   char *keyname;
+   E_Keyrouter_Key_List_NodePtr key_node_data;
+   int pid = 0;
+   char *pname = NULL, *cmd = NULL;
+
+   key_cancel = _e_keyrouter_key_create("Cancel");
+   EINA_SAFETY_ON_NULL_RETURN(key_cancel);
+
+   keyname = e_keyrouter_util_keyname_get_from_keycode(keycode);
+   key_release = _e_keyrouter_key_create(keyname);
+   EINA_SAFETY_ON_NULL_GOTO(key_release, failed);
+
+   EINA_LIST_FOREACH(krt->HardKeys[keycode].press_ptr, l, key_node_data)
+     {
+        _e_keyrouter_key_send(ECORE_EVENT_KEY_DOWN, key_cancel, key_node_data);
+        _e_keyrouter_key_send(ECORE_EVENT_KEY_UP, key_release, key_node_data);
+        _e_keyrouter_key_send(ECORE_EVENT_KEY_UP, key_cancel, key_node_data);
+
+        pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+        cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+        pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+        KLINF("CANCEL : => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
+              key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
+        if(pname) E_FREE(pname);
+        if(cmd) E_FREE(cmd);
+     }
+
+   _e_keyrouter_key_free(key_cancel);
+   _e_keyrouter_key_free(key_release);
+
+   return;
+
+failed:
+   if (key_cancel) _e_keyrouter_key_free(key_cancel);
+}
+
+
+static Eina_Bool
+_e_keyrouter_long_timer(void *data)
+{
+   E_Keyrouter_Event_Key_Long *ev;
+
+   ev = E_NEW(E_Keyrouter_Event_Key_Long, 1);
+   if (!ev)
+     {
+        krt->longkey.timer = NULL;
+        krt->longkey.key = 0;
+
+        return ECORE_CALLBACK_CANCEL;
+     }
+
+   ev->keycode = krt->longkey.key;
+
+   _e_keyrouter_key_cancel(krt->longkey.key);
+   ecore_event_add(E_KEYROUTER_EVENT_KEY_LONG, ev, NULL, NULL);
+
+   KLINF("LONGKEY : %s(%d) long press event is generated.\n",
+          e_keyrouter_util_keyname_get_from_keycode(krt->longkey.key), krt->longkey.key);
+
+   krt->longkey.timer = NULL;
+
+   /* Cancel a longkey to prevent irregal operation */
+   if (krt->composition_key.waiting_timer)
+     {
+        ecore_timer_del(krt->composition_key.waiting_timer);
+        krt->composition_key.waiting_timer = NULL;
+        krt->composition_key.key[0] = 0;
+        krt->composition_key.key[1] = 0;
+     }
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_e_keyrouter_long_check(int type, Ecore_Event_Key *ev)
+{
+   if (type == ECORE_EVENT_KEY_DOWN)
+     {
+        if (krt->longkey.timer || krt->longkey.key)
+          {
+             KLDBG("Already long pressed key(%d) is exist\n", krt->longkey.key);
+          }
+        else if (krt->HardKeys[ev->keycode].longkey.enabled)
+          {
+             krt->longkey.timer = ecore_timer_add(krt->HardKeys[ev->keycode].longkey.time, _e_keyrouter_long_timer, NULL);
+             krt->longkey.key = ev->keycode;
+          }
+     }
+   else
+     {
+        if (!krt->longkey.timer)
+          {
+             /* Already process a long press key. So ignore a long pressed key's release event */
+             if (krt->longkey.key && krt->longkey.key == ev->keycode)
+               {
+                  krt->longkey.key = 0;
+                  return ECORE_CALLBACK_DONE;
+               }
+             /* just a short press key event */
+             return ECORE_CALLBACK_PASS_ON;
+          }
+
+        /* Current key event is a short press, so cancel a long press timer. */
+        if (krt->longkey.key == ev->keycode)
+          {
+             ecore_timer_del(krt->longkey.timer);
+             krt->longkey.timer = NULL;
+             krt->longkey.key = 0;
+          }
+     }
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_e_keyrouter_composition_key_event(Eina_Bool pressed)
+{
+   E_Keyrouter_Event_Key_Composition *ev = NULL;
+
+   ev = E_NEW(E_Keyrouter_Event_Key_Composition, 1);
+   EINA_SAFETY_ON_NULL_RETURN(ev);
+
+   ev->keys[0] = krt->composition_key.key[0];
+   ev->keys[1] = krt->composition_key.key[1];
+
+   ev->timestamp = (unsigned int)(ecore_time_get()*1000);
+
+   KLINF("COMPOSITION_KEY : %s(%d) and %s(%d) composition key %s event is generated (time: %d).\n",
+          e_keyrouter_util_keyname_get_from_keycode(ev->keys[0]), ev->keys[0],
+          e_keyrouter_util_keyname_get_from_keycode(ev->keys[1]), ev->keys[1],
+          pressed?"press":"release", ev->timestamp);
+
+   if (pressed)
+     ecore_event_add(E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS, ev, NULL, NULL);
+   else
+     ecore_event_add(E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE, ev, NULL, NULL);
+}
+
+static Eina_Bool
+_e_keyrouter_composition_key_timer(void *data)
+{
+   krt->composition_key.key[0] = 0;
+   krt->composition_key.key[1] = 0;
+
+   krt->composition_key.waiting_timer = NULL;
+
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_e_keyrouter_composition_key_check(int type, Ecore_Event_Key *ev)
+{
+   Eina_List *l;
+   int *wait_key_data;
+
+   if (type == ECORE_EVENT_KEY_DOWN)
+     {
+        if (krt->composition_key.waiting_timer)
+          {
+             /* Find modkey */
+             EINA_LIST_FOREACH(krt->HardKeys[krt->composition_key.key[0]].composition_key_list, l, wait_key_data)
+               {
+                  if (*wait_key_data == ev->keycode)
+                    {
+                       krt->composition_key.key[1] = ev->keycode;
+
+                       ecore_timer_del(krt->composition_key.waiting_timer);
+                       krt->composition_key.waiting_timer = NULL;
+
+                       /* Cancel a longkey to prevent irregal operation */
+                       if (krt->longkey.timer)
+                         {
+                            ecore_timer_del(krt->longkey.timer);
+                            krt->longkey.timer = NULL;
+                            krt->longkey.key = 0;
+                         }
+
+                       _e_keyrouter_key_cancel(krt->composition_key.key[0]);
+                       _e_keyrouter_composition_key_event(EINA_TRUE);
+
+                       return ECORE_CALLBACK_DONE;
+                    }
+               }
+
+             /* Not modkey is pressed, cancel current modkey process */
+             if (krt->composition_key.waiting_timer)
+               {
+                  ecore_timer_del(krt->composition_key.waiting_timer);
+                  krt->composition_key.waiting_timer = NULL;
+                  krt->composition_key.key[0] = 0;
+                  krt->composition_key.key[1] = 0;
+               }
+          }
+        else if (!krt->composition_key.key[0] && !krt->composition_key.key[1])
+          {
+             if (eina_list_count(krt->HardKeys[ev->keycode].composition_key_list) > 0)
+               {
+                  krt->composition_key.key[0] = ev->keycode;
+                  krt->composition_key.waiting_timer = ecore_timer_add(krt->composition_key.waiting_time, _e_keyrouter_composition_key_timer, NULL);
+               }
+          }
+     }
+   else
+     {
+        if (!krt->composition_key.waiting_timer)
+          {
+             /* Already send modkey press and modkey release event is came. */
+             if ((krt->composition_key.key[0] == ev->keycode) ||
+                 (krt->composition_key.key[1] == ev->keycode))
+               {
+                  /* send modkey release event */
+                  if (krt->composition_key.key[0] && krt->composition_key.key[1])
+                    {
+                       _e_keyrouter_composition_key_event(EINA_FALSE);
+                    }
+
+                  if (krt->composition_key.key[0] == ev->keycode)
+                    {
+                       krt->composition_key.key[0] = 0;
+                    }
+                  else
+                    {
+                       krt->composition_key.key[1] = 0;
+                    }
+                  return ECORE_CALLBACK_DONE;
+               }
+             /* Modkey is not yet pressed */
+             return ECORE_CALLBACK_PASS_ON;
+          }
+
+        /* Not modkey, just key short press */
+        if (krt->composition_key.key[0] == ev->keycode)
+          {
+             ecore_timer_del(krt->composition_key.waiting_timer);
+             krt->composition_key.waiting_timer = NULL;
+             krt->composition_key.key[0] = 0;
+
+             return ECORE_CALLBACK_PASS_ON;
+          }
+     }
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+
 /* Function for checking the existing grab for a key and sending key event(s) */
 Eina_Bool
 e_keyrouter_event_process(void *event, int type)
@@ -130,11 +454,53 @@ finish:
 static void
 _e_keyrouter_send_key_events(int type, Ecore_Event_Key *ev)
 {
+   int pid = 0, keycode = 0;
+   char *pname = NULL, *cmd = NULL;
+   E_Keyrouter_Key_List_NodePtr key_node_data;
+   Eina_List *l = NULL;
+
+   keycode = ev->keycode;
+
+   if (krt->isPictureOffEnabled == 1)
+     {
+        EINA_LIST_FOREACH(krt->HardKeys[keycode].pic_off_ptr, l, key_node_data)
+          {
+             if (key_node_data)
+               {
+                  _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, key_node_data->focused, TIZEN_KEYROUTER_MODE_SHARED);
+
+                  pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+                  cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+                  pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+                  KLINF("PICTURE OFF : %s(%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
+                        ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keycode, key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
+
+                  if(pname) E_FREE(pname);
+                  if(cmd) E_FREE(cmd);
+               }
+          }
+        return;
+     }
+
+   if (!_e_keyrouter_composition_key_check(type, ev))
+     {
+        KLINF("Ignore %s(%d) key %s. This key is already processed for composition key.\n", ev->keyname, ev->keycode, ((ECORE_EVENT_KEY_DOWN == type) ? "down" : "up"));
+        return;
+     }
+
+   if (!_e_keyrouter_long_check(type, ev))
+     {
+        if (type == ECORE_EVENT_KEY_UP)
+          KLINF("Ignore %s(%d) key up. This key is already processed for long press.\n", ev->keyname, ev->keycode);
+        return;
+     }
+
+
    if (ECORE_EVENT_KEY_DOWN == type)
      {
         _e_keyrouter_send_key_events_press(type, ev);
      }
-  else
+   else
      {
         _e_keyrouter_send_key_events_release(type, ev);
      }
@@ -234,25 +600,6 @@ _e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *ev)
    ec_focus = e_client_focused_get();
    surface_focus = e_keyrouter_util_get_surface_from_eclient(ec_focus);
 
-   if (krt->isPictureOffEnabled == 1)
-     {
-       EINA_LIST_FOREACH(krt->HardKeys[keycode].pic_off_ptr, l, key_node_data)
-          {
-            if (key_node_data)
-                {
-                 _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, key_node_data->focused, TIZEN_KEYROUTER_MODE_SHARED);
-
-                 pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
-                 cmd = e_keyrouter_util_cmd_get_from_pid(pid);
-                 pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
-                 KLINF("PICTURE OFF : %s(%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
-                       ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keycode, key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
-                 if(pname) E_FREE(pname);
-                 if(cmd) E_FREE(cmd);
-                }
-          }
-       return;
-     }
    if (!_e_keyrouter_is_key_grabbed(ev->keycode))
      {
         _e_keyrouter_send_key_events_focus(type, surface_focus, ev, &delivered_surface);
index 179af59822cb9d058800ae66b0832a6b3b631abc..0cb0e162f1e3ee4a87dbbdd0da76eff6a0cdf6ac 100644 (file)
@@ -35,10 +35,11 @@ extern E_KeyrouterPtr krt;
 
 struct _E_Keyrouter_Conf_Edd
 {
-   int num_keycode;          // The numbers of keyrouted keycodes defined by xkb-tizen-data
-   int max_keycode;          // The max value of keycodes
-   int pictureoff_disabled;  // To disable picture_off feature.
-   Eina_List *KeyList;       // The list of routed key data: E_Keyrouter_Tizen_HWKey
+   int num_keycode;                   // The numbers of keyrouted keycodes defined by xkb-tizen-data
+   int max_keycode;                   // The max value of keycodes
+   int pictureoff_disabled;           // To disable picture_off feature.
+   double composition_key_wait_time;  // The time of waiting to composition key's press events
+   Eina_List *KeyList;                // The list of routed key data: E_Keyrouter_Tizen_HWKey
 };
 
 struct _E_Keyrouter_Config_Data
@@ -70,6 +71,19 @@ struct _E_Keyrouter
 #endif
    int isPictureOffEnabled;
    Eina_Bool pictureoff_disabled;
+
+   struct
+     {
+        Ecore_Timer *waiting_timer;
+        double waiting_time;
+
+        int key[2];
+     } composition_key;
+   struct
+     {
+        Ecore_Timer *timer;
+        int key;
+     } longkey;
 };
 
 struct _E_Keyrouter_Grab_Request {