ecore_x: Add key router feature related with client side. 71/39671/5 accepted/tizen/common/20150521.125548 accepted/tizen/mobile/20150522.005633 accepted/tizen/tv/20150522.004731 accepted/tizen/wearable/20150522.005518 submit/tizen/20150520.110027
authorJi-Youn Park <jy0703.park@samsung.com>
Wed, 13 May 2015 11:47:36 +0000 (20:47 +0900)
committerGwanglim Lee <gl77.lee@samsung.com>
Thu, 21 May 2015 00:26:17 +0000 (17:26 -0700)
Currently app only grab key using Xgrabkey.
Keyrouter will support several keygrab mode and apps can use it.

Change-Id: I051185968c00dc45002c1608ce16415285273dd4
Signed-off-by: Jiyoun Park <jy0703.park@samsung.com>
Conflicts:
src/lib/ecore_x/Ecore_X.h
src/lib/ecore_x/Ecore_X_Atoms.h
src/lib/ecore_x/ecore_x_atoms_decl.h
src/lib/ecore_x/xlib/ecore_x_e.c
origin: upstream

src/Makefile_Ecore_X.am
src/lib/ecore_x/Ecore_X.h
src/lib/ecore_x/Ecore_X_Atoms.h
src/lib/ecore_x/ecore_x_atoms_decl.h
src/lib/ecore_x/xlib/ecore_x_e.c
src/lib/ecore_x/xlib/ecore_x_keygrab.c [new file with mode: 0644]

index 43c0647..38727f1 100644 (file)
@@ -82,6 +82,7 @@ lib/ecore_x/xlib/ecore_x_composite.c \
 lib/ecore_x/xlib/ecore_x_error.c \
 lib/ecore_x/xlib/ecore_x_events.c \
 lib/ecore_x/xlib/ecore_x_icccm.c \
+lib/ecore_x/xlib/ecore_x_keygrab.c \
 lib/ecore_x/xlib/ecore_x_netwm.c \
 lib/ecore_x/xlib/ecore_x_mwm.c \
 lib/ecore_x/xlib/ecore_x_e.c \
index 521e5c4..0850a67 100644 (file)
@@ -2716,6 +2716,26 @@ EAPI void                                  ecore_x_e_virtual_keyboard_on_prepare
 EAPI void                                  ecore_x_e_virtual_keyboard_off_prepare_request_send(Ecore_X_Window win);
 EAPI void                                  ecore_x_e_virtual_keyboard_off_prepare_done_send(Ecore_X_Window root, Ecore_X_Window win);
 
+//this enum and API for keyrouter and client window side
+//keycode (8~255)
+typedef enum
+{
+   ECORE_X_WIN_KEYGRAB_UNKNOWN = 0, /**< Unknown keygrab mode */
+   ECORE_X_WIN_KEYGRAB_SHARED  = (1 << 8), /**< Getting the grabbed-key together with the other client windows */
+   ECORE_X_WIN_KEYGRAB_TOPMOST = (1 << 9), /**< Getting the grabbed-key only when window is top of the stack */
+   ECORE_X_WIN_KEYGRAB_EXCLUSIVE = (1 << 10), /**< Getting the grabbed-key exclusively regardless of window's position */
+   ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE = (1 << 11) /**< Getting the grabbed-key exclusively regardless of window's position. Being overrided the grab by the other client window  */
+} Ecore_X_Win_Keygrab_Mode;
+
+//add mod, anymod, priority for the future.
+//we will support modifier and priority feature later.
+EAPI Eina_Bool                             ecore_x_window_keygrab_set(Ecore_X_Window win, const char *key, int mod, int any_mod, int priority, Ecore_X_Win_Keygrab_Mode grab_mode);
+EAPI Eina_Bool                             ecore_x_window_keygrab_unset(Ecore_X_Window win, const char *key, int mod, int any_mod);
+
+//this API for keyrouter protocol
+EAPI void                                  ecore_x_e_keyrouter_set(Ecore_X_Window root, Eina_Bool on); //Key router set keyrouter flag using this
+EAPI Eina_Bool                             ecore_x_e_keyrouter_get(Ecore_X_Window root); //Client check the existance of keyrouter using this
+
 #ifdef __cplusplus
 }
 #endif // ifdef __cplusplus
index ca418cd..4f24857 100644 (file)
@@ -344,4 +344,8 @@ EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_REQUEST;
 EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_DONE;
 EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_REQUEST;
 EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_DONE;
+
+/* E keyrouter protocol */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_KEYROUTER_SUPPORTED; /**< @since 1.15 */
+EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE; /**< @since 1.15 */
 #endif /* _ECORE_X_ATOMS_H */
index 6581530..29d453a 100644 (file)
@@ -374,6 +374,10 @@ EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ON_PREPARE_DONE = 0;
 EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_REQUEST = 0;
 EAPI Ecore_X_Atom ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF_PREPARE_DONE = 0;
 
+/* E keyrouter protocol */
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_KEYROUTER_SUPPORTED = 0;
+EAPI Ecore_X_Atom ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE = 0;
+
 typedef struct _Atom_Item Atom_Item;
 
 struct _Atom_Item
index 433770c..a7b7711 100644 (file)
@@ -2457,3 +2457,41 @@ ecore_x_e_virtual_keyboard_off_prepare_done_send(Ecore_X_Window root,
               SubstructureRedirectMask | SubstructureNotifyMask,
               &xev);
 }
+
+/*
+ * Does keyrouter exist?
+ */
+EAPI void
+ecore_x_e_keyrouter_set(Ecore_X_Window win EINA_UNUSED,
+                        Eina_Bool on)
+{
+   //key router call this api when it start running
+   unsigned int val;
+   Ecore_X_Window root;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   root = DefaultRootWindow(_ecore_x_disp);
+
+   val = (on) ? 1 : 0;
+   ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_E_KEYROUTER_SUPPORTED,
+                                  &val, 1);
+}
+
+EAPI Eina_Bool
+ecore_x_e_keyrouter_get(Ecore_X_Window win EINA_UNUSED)
+{
+   //check the existance of keyrouter
+   int ret;
+   unsigned int val;
+   Ecore_X_Window root;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+   root = DefaultRootWindow(_ecore_x_disp);
+
+   ret = ecore_x_window_prop_card32_get(root, ECORE_X_ATOM_E_KEYROUTER_SUPPORTED,
+                                        &val, 1);
+   if (ret != 1) return EINA_FALSE;
+
+   return val == 1 ? EINA_TRUE : EINA_FALSE;
+}
diff --git a/src/lib/ecore_x/xlib/ecore_x_keygrab.c b/src/lib/ecore_x/xlib/ecore_x_keygrab.c
new file mode 100644 (file)
index 0000000..b0dbd29
--- /dev/null
@@ -0,0 +1,617 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* ifdef HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+
+#ifdef LOGRT
+#include <dlfcn.h>
+#endif /* ifdef LOGRT */
+
+#include "ecore_x_private.h"
+#include "Ecore_X.h"
+#include "Ecore_X_Atoms.h"
+
+
+//////////////////////////////////////////////////////////////////////////////
+// This api and structure only for the key router and window client side
+// Application do not use this
+
+//this mask is defined by key router.
+//after discussing with keyrouter module, this mask can be changed
+#define GRAB_MASK 0xffff00
+#define OVERRIDE_EXCLUSIVE_GRAB 0xf00000
+#define EXCLUSIVE_GRAB 0x0f0000
+#define TOPMOST_GRAB 0x00f000
+#define SHARED_GRAB 0x000f00
+
+//if _ecore_keyrouter = 0, not yet check keyrouter
+//if _ecore_keyrouter = -1, keyrouter not exist
+//if _ecore_keyrouter = 1, keyrouter exist
+int _ecore_keyrouter = 0;
+
+struct _Ecore_X_Window_Key_Table
+{
+   Ecore_X_Window       win;       //windo ID
+   int                 *key_list;  //list of key
+   unsigned long        key_cnt;   // the number of key
+};
+
+typedef struct _Ecore_X_Window_Key_Table             Ecore_X_Window_Key_Table;
+
+static int       _ecore_x_window_keytable_key_search(Ecore_X_Window_Key_Table *keytable, int key);
+static Eina_Bool _ecore_x_window_keytable_key_del(Ecore_X_Window_Key_Table *key_table, int key, Ecore_X_Atom keytable_atom);
+
+static Eina_Bool _ecore_x_window_keytable_key_add(Ecore_X_Window_Key_Table *keytable,
+                                 int keycode,
+                                 Ecore_X_Win_Keygrab_Mode grab_mode);
+
+static Eina_Bool _ecore_x_window_keygrab_set_internal(Ecore_X_Window win, const char *key, Ecore_X_Win_Keygrab_Mode grab_mode);
+static Eina_Bool _ecore_x_window_keygrab_unset_internal(Ecore_X_Window win, const char *key);
+static Eina_Bool _ecore_x_window_keytable_get(Ecore_X_Window win, Ecore_X_Window_Key_Table *keytable);
+
+
+//(Below Atom and exclusiveness_get/set functions) should be changed after keyrouter finds the solution to avoid race condition
+//solution 1. window manages two key table. keytable and keytable result
+//solution 2. using client messabe between the window client and the key router.
+
+static Atom _atom_grab_excl_win = None;
+#define STR_ATOM_GRAB_EXCL_WIN "_GRAB_EXCL_WIN_KEYCODE"
+
+static void
+_keytable_free(Ecore_X_Window_Key_Table *keytable)
+{
+   if (keytable->key_list)
+     free(keytable->key_list);
+   keytable->key_list = NULL;
+   keytable->win = 0;
+   keytable->key_cnt = 0;
+}
+
+static int
+_keytable_property_list_get(Ecore_X_Window win,
+                            Ecore_X_Atom atom,
+                            unsigned int **plst)
+{
+   unsigned char *prop_ret;
+   Atom type_ret;
+   unsigned long bytes_after, num_ret;
+   int format_ret;
+   unsigned int i, *val;
+   int num;
+
+   *plst = NULL;
+   prop_ret = NULL;
+   if (XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False,
+                          XA_CARDINAL, &type_ret, &format_ret, &num_ret,
+                          &bytes_after, &prop_ret) != Success)
+     {
+        WRN("XGetWindowProperty failed");
+        return -1;
+     }
+   else if ((num_ret == 0) || (!prop_ret))
+     num = 0;
+   else
+     {
+        val = malloc(num_ret * sizeof(unsigned int));
+        if (!val)
+          {
+             if (prop_ret) XFree(prop_ret);
+             WRN("Memory alloc failed");
+             return -1;
+          }
+        for (i = 0; i < num_ret; i++)
+          val[i] = ((unsigned long *)prop_ret)[i];
+        num = num_ret;
+        *plst = val;
+     }
+
+   if (_ecore_xlib_sync) ecore_x_sync();
+   if (prop_ret)
+     XFree(prop_ret);
+   return num;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_possible_global_exclusiveness_get(int keycode)
+{
+   int ret = 0;
+
+   Ecore_X_Window_Key_Table keytable;
+
+   keytable.win = ecore_x_window_root_first_get();
+   keytable.key_list = NULL;
+   keytable.key_cnt = 0;
+
+   if(_atom_grab_excl_win == None )
+     _atom_grab_excl_win = XInternAtom(_ecore_x_disp, STR_ATOM_GRAB_EXCL_WIN, False);
+
+   ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
+                                     (unsigned int **)&(keytable.key_list));
+
+   if (ret < 0)
+     {
+           return EINA_FALSE;
+     }
+
+   keytable.key_cnt = ret;
+
+   if (keytable.key_cnt == 0)
+     {
+        WRN("There is no keygrab entry in the table");
+        return EINA_TRUE;
+     }
+
+   //check keycode exists in the global exclusiveness keytable
+
+   ret = _ecore_x_window_keytable_key_search(&keytable, keycode);
+   if (ret != -1)
+     {
+        WRN("Can't search keygrab entry in the table");
+        _keytable_free(&keytable);
+        return EINA_FALSE;
+     }
+   _keytable_free(&keytable);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_possible_global_exclusiveness_set(int keycode)
+{
+   int ret = 0;
+
+   Ecore_X_Window_Key_Table keytable;
+
+   keytable.win = ecore_x_window_root_first_get();
+   keytable.key_list = NULL;
+   keytable.key_cnt = 0;
+
+   if(_atom_grab_excl_win == None )
+     _atom_grab_excl_win = XInternAtom(_ecore_x_disp, STR_ATOM_GRAB_EXCL_WIN, False);
+
+   ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
+                                     (unsigned int **)&(keytable.key_list));
+   if (ret < 0) return EINA_FALSE;
+
+   keytable.key_cnt = ret;
+
+   if (keytable.key_cnt == 0)
+     {
+        XChangeProperty(_ecore_x_disp, keytable.win, _atom_grab_excl_win, XA_CARDINAL, 32,
+                        PropModeReplace, (unsigned char *)&keycode, 1);
+        XSync(_ecore_x_disp, False);
+        _keytable_free(&keytable);
+        return EINA_TRUE;
+     }
+
+   //check keycode exists in the global exclusiveness keytable
+   ret = _ecore_x_window_keytable_key_search(&keytable, keycode);
+   if (ret != -1)
+     {
+        XChangeProperty(_ecore_x_disp, keytable.win, _atom_grab_excl_win, XA_CARDINAL, 32,
+                        PropModeAppend, (unsigned char *)&keycode, 1);
+        XSync(_ecore_x_disp, False);
+        _keytable_free(&keytable);
+        return EINA_TRUE;
+     }
+   WRN("Already key is grabbed");
+   _keytable_free(&keytable);
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_possible_global_exclusiveness_unset(int keycode)
+{
+   int ret = 0;
+
+   Ecore_X_Window_Key_Table keytable;
+
+   keytable.win = ecore_x_window_root_first_get();
+   keytable.key_list = NULL;
+   keytable.key_cnt = 0;
+
+   if(_atom_grab_excl_win == None )
+     _atom_grab_excl_win = XInternAtom(_ecore_x_disp, STR_ATOM_GRAB_EXCL_WIN, False);
+
+   ret = _keytable_property_list_get(keytable.win, _atom_grab_excl_win,
+                                     (unsigned int **)&(keytable.key_list));
+   if (ret <= 0) return EINA_FALSE;
+
+   keytable.key_cnt = ret;
+
+   //check keycode exists in the global exclusiveness keytable
+   ret = _ecore_x_window_keytable_key_search(&keytable, keycode);
+   if (ret == -1)
+     {
+        WRN("Already key exists");
+        _keytable_free(&keytable);
+        return EINA_FALSE;
+     }
+   else
+     ret = _ecore_x_window_keytable_key_del(&keytable, keycode, _atom_grab_excl_win);
+
+   _keytable_free(&keytable);
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_keycode_decode(int keycode_encoded,
+                                        int *keycode,
+                                        Ecore_X_Win_Keygrab_Mode *grab_mode)
+{
+   int key_mask = 0;
+
+   *keycode = keycode_encoded & (~GRAB_MASK);
+   key_mask = keycode_encoded & GRAB_MASK;
+
+   if (key_mask == SHARED_GRAB)
+     {
+        *grab_mode = ECORE_X_WIN_KEYGRAB_SHARED;
+        return EINA_TRUE;
+     }
+   else if (key_mask == TOPMOST_GRAB)
+     {
+        *grab_mode = ECORE_X_WIN_KEYGRAB_TOPMOST;
+        return EINA_TRUE;
+     }
+   else if (key_mask == EXCLUSIVE_GRAB)
+     {
+        *grab_mode = ECORE_X_WIN_KEYGRAB_EXCLUSIVE;
+        return EINA_TRUE;
+     }
+   else if (key_mask == OVERRIDE_EXCLUSIVE_GRAB)
+     {
+        *grab_mode = ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE;
+        return EINA_TRUE;
+     }
+   else
+     {
+        *grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
+        WRN("Keycode decoding failed. Unknown Keygrab mode");
+        return EINA_FALSE;
+     }
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_keycode_encode(int keycode,
+                                        Ecore_X_Win_Keygrab_Mode grab_mode,
+                                        int *keycode_encoded)
+{
+   if ((grab_mode <= ECORE_X_WIN_KEYGRAB_UNKNOWN) || (grab_mode > ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE))
+     {
+        *keycode_encoded = 0;
+        WRN("Keycode encoding failed. Unknown Keygrab mode");
+        return EINA_FALSE;
+     }
+   if (grab_mode == ECORE_X_WIN_KEYGRAB_SHARED)
+     *keycode_encoded = keycode | SHARED_GRAB;
+   else if (grab_mode == ECORE_X_WIN_KEYGRAB_TOPMOST)
+     *keycode_encoded = keycode | TOPMOST_GRAB;
+   else if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
+     *keycode_encoded = keycode | EXCLUSIVE_GRAB;
+   else if (grab_mode == ECORE_X_WIN_KEYGRAB_OVERRIDE_EXCLUSIVE)
+     *keycode_encoded = keycode | OVERRIDE_EXCLUSIVE_GRAB;
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_get(Ecore_X_Window win,
+                             Ecore_X_Window_Key_Table *keytable)
+{
+   int ret = 0;
+
+   ret = _keytable_property_list_get(win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE,
+                                     (unsigned int **)&(keytable->key_list));
+   if (ret < 0) return EINA_FALSE;
+
+   keytable->key_cnt = ret;
+
+   return EINA_TRUE;
+}
+
+static int
+_ecore_x_window_keytable_key_search(Ecore_X_Window_Key_Table *keytable,
+                                    int key)
+{
+   int  i;
+   int keycode = 0;
+   unsigned long key_cnt;
+   int *key_list = NULL;
+
+   keycode = key & (~GRAB_MASK);
+   key_cnt = keytable->key_cnt;
+   key_list = keytable->key_list;
+
+   for (i = key_cnt - 1; i >= 0; i--)
+     {
+        if ((key_list[i] & (~GRAB_MASK)) == keycode) break;
+     }
+   return i;
+}
+
+
+static Eina_Bool
+_ecore_x_window_keytable_key_add(Ecore_X_Window_Key_Table *keytable,
+                                 int keycode,
+                                 Ecore_X_Win_Keygrab_Mode grab_mode)
+{
+   int i = 0;
+   int keycode_masked = 0;
+
+   Ecore_Window   win;
+   unsigned long  key_cnt;
+
+   win = keytable->win;
+   key_cnt = keytable->key_cnt;
+
+   if (!_ecore_x_window_keytable_keycode_encode(keycode, grab_mode, &keycode_masked))
+     return EINA_FALSE;
+
+   if (key_cnt == 0)
+     {
+        XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE, XA_CARDINAL, 32,
+                        PropModeReplace, (unsigned char *)&keycode_masked, 1);
+        XSync(_ecore_x_disp, False);
+        return EINA_TRUE;
+     }
+   else
+     {
+        i = _ecore_x_window_keytable_key_search(keytable, keycode_masked);
+        if ( i != -1 )
+          {
+             //already exist key in key table
+             WRN("Already key exists");
+             return EINA_FALSE;
+          }
+        XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE, XA_CARDINAL, 32,
+                        PropModeAppend, (unsigned char *)&keycode_masked, 1);
+        XSync(_ecore_x_disp, False);
+        return EINA_TRUE;
+     }
+}
+
+static Eina_Bool
+_ecore_x_window_keytable_key_del(Ecore_X_Window_Key_Table *key_table,
+                                 int key,
+                                 Ecore_X_Atom keytable_atom)
+{
+   int i;
+   int *new_key_list = NULL;
+   unsigned long key_cnt = 0;
+
+   // Only one element is exists in the list of grabbed key
+   i = _ecore_x_window_keytable_key_search(key_table, key);
+
+   if (i == -1)
+     {
+        WRN("Key doesn't exist in the key table.");
+        return EINA_FALSE;
+     }
+
+   (key_table->key_cnt)--;
+   key_cnt = key_table->key_cnt;
+
+   if (key_cnt == 0)
+     {
+        XDeleteProperty(_ecore_x_disp, key_table->win, keytable_atom);
+        XSync(_ecore_x_disp, False);
+        return EINA_TRUE;
+     }
+
+   // Shrink the buffer
+   new_key_list = malloc((key_cnt) * sizeof(int));
+
+   if (new_key_list == NULL)
+     return EINA_FALSE;
+
+   // copy head
+   if (i > 0)
+     memcpy(new_key_list, key_table->key_list, sizeof(int) * i);
+
+   // copy tail
+   if ((key_cnt) - i > 0)
+     {
+        memcpy(new_key_list + i,
+               key_table->key_list + i + 1,
+               sizeof(int) * (key_cnt - i));
+     }
+
+   XChangeProperty(_ecore_x_disp, key_table->win, keytable_atom, XA_CARDINAL, 32,
+                   PropModeReplace, (unsigned char *)new_key_list, key_cnt);
+   XSync(_ecore_x_disp, False);
+
+   free(new_key_list);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_ecore_x_window_keygrab_set_internal(Ecore_X_Window win,
+                                     const char *key,
+                                     Ecore_X_Win_Keygrab_Mode grab_mode)
+{
+   KeyCode keycode = 0;
+   KeySym keysym;
+
+   Eina_Bool ret = EINA_FALSE;
+   Ecore_X_Window_Key_Table keytable;
+
+   keytable.win = win;
+   keytable.key_list = NULL;
+   keytable.key_cnt = 0;
+
+
+   //check the key string
+   if (!strncmp(key, "Keycode-", 8))
+     keycode = atoi(key + 8);
+   else
+     {
+        keysym = XStringToKeysym(key);
+        if (keysym == NoSymbol)
+          {
+             WRN("Keysym of key(\"%s\") doesn't exist", key);
+             return ret;
+          }
+        keycode = XKeysymToKeycode(_ecore_x_disp, keysym);
+     }
+
+   if (keycode == 0)
+     {
+        WRN("Keycode of key(\"%s\") doesn't exist", key);
+        return ret;
+     }
+
+   if(grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
+     {
+        //Only one window can grab this key;
+        //keyrouter should avoid race condition
+        if (!_ecore_x_window_keytable_possible_global_exclusiveness_get(keycode))
+          return EINA_FALSE;
+     }
+
+   if (!_ecore_x_window_keytable_get(win, &keytable))
+     return EINA_FALSE;
+
+   ret = _ecore_x_window_keytable_key_add(&keytable, keycode, grab_mode);
+
+
+   if (!ret)
+     {
+        WRN("Key(\"%s\") add failed", key);
+        return ret;
+     }
+
+   if(grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
+     {
+        //Only one window can grab this key;
+        if(!_ecore_x_window_keytable_possible_global_exclusiveness_set(keycode))
+          {
+             _ecore_x_window_keytable_key_del(&keytable, keycode, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
+             WRN("Key(\"%s\") already is grabbed", key);
+             goto error;
+          }
+     }
+
+   _keytable_free(&keytable);
+   return EINA_TRUE;
+error:
+   _keytable_free(&keytable);
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_x_window_keygrab_unset_internal(Ecore_X_Window win,
+                                       const char *key)
+{
+   KeyCode keycode = 0;
+   KeySym keysym;
+
+   int i;
+   int key_masked = 0;
+   int key_decoded = 0;
+
+   Eina_Bool ret = EINA_FALSE;
+
+   Ecore_X_Window_Key_Table keytable;
+   Ecore_X_Win_Keygrab_Mode grab_mode = ECORE_X_WIN_KEYGRAB_UNKNOWN;
+
+   keytable.win = win;
+   keytable.key_list = NULL;
+   keytable.key_cnt = 0;
+
+   if (!strncmp(key, "Keycode-", 8))
+     keycode = atoi(key + 8);
+   else
+     {
+        keysym = XStringToKeysym(key);
+        if (keysym == NoSymbol)
+          {
+             WRN("Keysym of key(\"%s\") doesn't exist", key);
+             return EINA_FALSE;
+          }
+        keycode = XKeysymToKeycode(_ecore_x_disp, keysym);
+     }
+
+   if (keycode == 0)
+     {
+        WRN("Keycode of key(\"%s\") doesn't exist", key);
+        return EINA_FALSE;
+     }
+
+   //construct the keytable structure using Xproperty
+   if (!_ecore_x_window_keytable_get(win, &keytable))
+      return EINA_FALSE;
+
+   if (keytable.key_cnt <= 0)
+     return EINA_FALSE;
+
+   i = _ecore_x_window_keytable_key_search(&keytable, keycode);
+
+   if (i == -1) //cannot find key in keytable
+     {
+        WRN("Key(\"%s\") doesn't exist", key);
+        goto error;
+     }
+
+   //find key in keytable
+   key_masked = keytable.key_list[i];
+
+   ret = _ecore_x_window_keytable_keycode_decode(key_masked, &key_decoded, &grab_mode);
+
+   if (!ret)
+     goto error;
+
+   ret = _ecore_x_window_keytable_key_del(&keytable, key_masked, ECORE_X_ATOM_E_KEYROUTER_WINDOW_KEYTABLE);
+   if (!ret)
+     goto error;
+
+   if (grab_mode == ECORE_X_WIN_KEYGRAB_EXCLUSIVE)
+     {
+        ret = _ecore_x_window_keytable_possible_global_exclusiveness_unset(keycode);
+     }
+
+  return EINA_TRUE;
+error:
+   _keytable_free(&keytable);
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_x_window_keygrab_set(Ecore_X_Window win,
+                           const char *key,
+                           int mod EINA_UNUSED,
+                           int not_mod EINA_UNUSED,
+                           int priority EINA_UNUSED,
+                           Ecore_X_Win_Keygrab_Mode grab_mode)
+{
+   if (_ecore_keyrouter == 0)
+     {
+        if(ecore_x_e_keyrouter_get(win))
+          _ecore_keyrouter = 1;
+        else
+          {
+             WRN("Keyrouter is not supported");
+             _ecore_keyrouter = -1;
+          }
+     }
+   if (_ecore_keyrouter < 0)
+     return EINA_FALSE;
+
+   return _ecore_x_window_keygrab_set_internal(win, key, grab_mode);
+}
+
+EAPI Eina_Bool
+ecore_x_window_keygrab_unset(Ecore_X_Window win,
+                             const char *key,
+                             int mod EINA_UNUSED,
+                             int any_mod EINA_UNUSED)
+{
+   if (_ecore_keyrouter != 1)
+     {
+        WRN("Keyrouter is not supported");
+        return EINA_FALSE;
+     }
+
+   return _ecore_x_window_keygrab_unset_internal(win, key);
+}
+