From: Sung-Jin Park Date: Fri, 15 May 2015 11:41:07 +0000 (+0900) Subject: [wl_keyrouter] Add keyrouter wayland protocol/backend-implementation X-Git-Tag: submit/tizen/20150516.064906^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=43b6eeb2c27457517650cda09bc6245872b0f607;p=platform%2Fcore%2Fuifw%2Fe-mod-tizen-keyrouter.git [wl_keyrouter] Add keyrouter wayland protocol/backend-implementation Change-Id: I88bf63212598364fe48cb22264e9671ddc0c95ec --- diff --git a/configure.ac b/configure.ac index 81fac40..8585f6a 100644 --- a/configure.ac +++ b/configure.ac @@ -92,6 +92,30 @@ AC_SUBST(ENLIGHTENMENT_LIBS) #AC_MSG_CHECKING([Which edje_cc to use]) #AC_MSG_RESULT(${EDJE_CC}) +dnl ======================================================================== +# checks for the existence of wayland_scanner +dnl ======================================================================== +AC_PATH_PROG([wayland_scanner], [wayland-scanner]) +if test x$wayland_scanner = x; then + AC_MSG_ERROR([wayland-scanner is needed to compile]) +fi + +PKG_CHECK_MODULES(WAYLAND_SCANNER, [wayland-scanner]) +PKG_CHECK_MODULES(WAYLAND, [wayland-server wayland-client ecore-wayland]) + +dnl ======================================================================== +# checks for wayland only argument +dnl ======================================================================== +have_wayland_only=no +AC_ARG_ENABLE([wayland-only], + AS_HELP_STRING([--enable-wayland-only],[enable wayland-only version of enlightenment @<:@default=disabled@:>@]), + [have_wayland_only=$enableval], + [have_wayland_only=no]) +AC_MSG_CHECKING([whether wayland-only version is enabled]) +AM_CONDITIONAL(WAYLAND_ONLY, test x$have_wayland_only = xyes) +if test "x${have_wayland_only}" != "xno"; then + AC_DEFINE_UNQUOTED([HAVE_WAYLAND_ONLY],[1],[enable wayland-only version of enlightenment]) +fi dnl ======================================================================= diff --git a/packaging/e-mod-tizen-keyrouter.spec b/packaging/e-mod-tizen-keyrouter.spec index 6b2ddf1..72e12d2 100644 --- a/packaging/e-mod-tizen-keyrouter.spec +++ b/packaging/e-mod-tizen-keyrouter.spec @@ -1,7 +1,8 @@ %bcond_with x +%bcond_with wayland Name: e-mod-tizen-keyrouter -Version: 0.0.3 +Version: 0.1.0 Release: 1 Summary: The Enlightenment Keyrouter Module for Tizen URL: http://www.enlightenment.org @@ -10,18 +11,21 @@ Source0: %{name}-%{version}.tar.gz License: BSD-2-Clause BuildRequires: pkgconfig(enlightenment) BuildRequires: gettext +%if %{with x} BuildRequires: pkgconfig(x11) BuildRequires: pkgconfig(xi) BuildRequires: pkgconfig(xtst) BuildRequires: pkgconfig(xrandr) BuildRequires: pkgconfig(utilX) +%endif +%if %{with wayland} +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(wayland-server) +#BuildRequires: pkgconfig(ecore-wayland) +%endif BuildRequires: pkgconfig(dlog) BuildRequires: e-tizen-data -%if !%{with x} -ExclusiveArch: -%endif - %description This package is a the Enlightenment Keyrouter Module for Tizen. @@ -35,8 +39,15 @@ export CFLAGS+=" -Wall -g -fPIC -rdynamic ${GC_SECTIONS_FLAGS}" export LDFLAGS+=" -Wl,--hash-style=both -Wl,--as-needed -Wl,--rpath=/usr/lib" %autogen +%if %{with wayland} %configure --prefix=/usr \ + --enable-wayland-only \ --with-tizen-keylayout-file=/usr/share/X11/xkb/tizen_key_layout.txt +%else +%configure --prefix=/usr \ + --with-tizen-keylayout-file=/usr/share/X11/xkb/tizen_key_layout.txt +%endif + make %install diff --git a/protocol/keyrouter.xml b/protocol/keyrouter.xml new file mode 100644 index 0000000..38aad84 --- /dev/null +++ b/protocol/keyrouter.xml @@ -0,0 +1,89 @@ + + + Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved. + Contact: Sung-Jin Park (sj76.park@samsung.com), + Jeonghyun Kang (jhyuni.kang@samsung.com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + In tradition, all the keys in a keyboard and a device on which + some keys are attached will be sent to focus surface by default. + Currently it's possible to set up each focus for each key in a keyboard and a device. + Therefore, by setting a key grab for a surface, the owner of the + surface will get the key event when it has the key grab for the key. + + + + + + + + + + + + + + + This value is used to set a mode for a key grab. With this mode and + the order of the surface between surfaces' stack, the compositor will determine the destination client + surface. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Makefile.am b/src/Makefile.am index f698443..64996ad 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,12 +5,33 @@ LDFLAGS += pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH) pkg_LTLIBRARIES = module.la +if WAYLAND_ONLY +module_la_SOURCES = e_mod_main_wl.c \ + e_mod_main_wl.h \ + keyrouter-protocol.c +module_la_CFLAGS = @ENLIGHTENMENT_CFLAGS@ @WAYLAND_CFLAGS@ -DHAVE_WAYLAND_ONLY +module_la_LDFLAGS = -module -avoid-version @WAYLAND_LIBS@ @ENLIGHTENMENT_LIBS@ +else module_la_SOURCES = e_mod_main.c \ e_mod_main.h module_la_LIBADD = module_la_CFLAGS = @ENLIGHTENMENT_CFLAGS@ module_la_LDFLAGS = -module -avoid-version @ENLIGHTENMENT_LIBS@ +endif module_la_DEPENDENCIES = $(top_builddir)/config.h #uninstall: # rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE) + +if WAYLAND_ONLY +BUILT_SOURCES = keyrouter-protocol.c keyrouter-protocol.h + +CLEANFILES = $(BUILT_SOURCES) + +%-protocol.c : $(top_srcdir)/protocol/%.xml + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code < $< > $@ + +%-protocol.h : $(top_srcdir)/protocol/%.xml + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header < $< > $@ + +endif diff --git a/src/e_mod_main.c b/src/e_mod_main.c old mode 100755 new mode 100644 diff --git a/src/e_mod_main.h b/src/e_mod_main.h old mode 100755 new mode 100644 diff --git a/src/e_mod_main_wl.c b/src/e_mod_main_wl.c new file mode 100644 index 0000000..eefcb48 --- /dev/null +++ b/src/e_mod_main_wl.c @@ -0,0 +1,1076 @@ +#define E_COMP_WL +#include "e.h" +#include "e_mod_main_wl.h" +#include "keyrouter-protocol.h" +#include + +E_KeyrouterPtr krt; +EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Keyrouter Module of Window Manager" }; + +/* wl_keyrouter_set_keygrab request handler */ +static void +_e_keyrouter_cb_keygrab_set(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key, uint32_t mode) +{ + (void) client; + (void) resource; + (void) surface; + (void) key; + (void) mode; + int res=0; + + if (!surface) + { + /* Regarding exclusive mode, a client can request to grab a key without a surface. */ + if (mode < WL_KEYROUTER_MODE_EXCLUSIVE) + { + KLDBG("Invalid surface ! (key=%d, mode=%d)\n", key, mode); + + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, mode, WL_KEYROUTER_ERROR_INVALID_SURFACE); + } + else + { + KLDBG("Null surface will be permitted only for (or)exclusive mode !\n"); + } + } + + /* Check the given key range */ + if (0 > key || MAX_HWKEYS < key ) + { + KLDBG("Invalid range of key ! (keycode:%d)\n", key); + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, mode, WL_KEYROUTER_ERROR_INVALID_KEY); + } + + /* Check whether the key can be grabbed or not ! + * Only key listed in Tizen key layout file can be grabbed. */ + if (0 == krt->HardKeys[key].keycode) + { + KLDBG("Invalid key ! Disabled to grab ! (keycode:%d)\n", key); + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, mode, WL_KEYROUTER_ERROR_INVALID_KEY); + } + + /* Check whether the mode is valid or not */ + if (WL_KEYROUTER_MODE_NONE > mode || WL_KEYROUTER_MODE_EXCLUSIVE < mode) + { + KLDBG("Invalid range of mode ! (mode:%d)\n", mode); + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, mode, WL_KEYROUTER_ERROR_INVALID_MODE); + } + + /* Check whether the request key can be grabbed or not */ + res = _e_keyrouter_set_keygrab_in_list(surface, client, key, mode); + + KLDBG("Result of grab check for a key (key:%d, mode:%d, res:%d)\n", key, mode, res); + + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, mode, res); +} + +/* wl_keyrouter unset_keygrab request handler */ +static void +_e_keyrouter_cb_keygrab_unset(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key) +{ + (void) client; + (void) resource; + (void) surface; + (void) key; + + E_Pixmap *ep = NULL; + E_Client *ec = NULL; + + if (!surface) + { + if ((krt->HardKeys[key].excl_ptr) && (client == krt->HardKeys[key].excl_ptr->wc)) + { + _e_keyrouter_remove_from_keylist(ec, key, WL_KEYROUTER_MODE_EXCLUSIVE, NULL, krt->HardKeys[key].excl_ptr); + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, WL_KEYROUTER_MODE_NONE, WL_KEYROUTER_ERROR_NONE); + } + } + + if (!surface || !(ep = wl_resource_get_user_data(surface))) + { + KLDBG("Surface or E_Pixman from the surface is invalid ! Return error !\n"); + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, WL_KEYROUTER_MODE_NONE, WL_KEYROUTER_ERROR_INVALID_SURFACE); + } + + if (!(ec = e_pixmap_client_get(ep))) + { + KLDBG("E_Client pointer from E_Pixman from surface is invalid ! Return error !\n"); + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, WL_KEYROUTER_MODE_NONE, WL_KEYROUTER_ERROR_INVALID_SURFACE); + } + + /* EXCLUSIVE grab */ + if ((krt->HardKeys[key].excl_ptr) && (ec == krt->HardKeys[key].excl_ptr->ec)) + { + _e_keyrouter_remove_from_keylist(ec, key, WL_KEYROUTER_MODE_EXCLUSIVE, NULL, krt->HardKeys[key].excl_ptr); + } + + /* OVERRIDABLE_EXCLUSIVE grab */ + _e_keyrouter_find_and_remove_client_from_list(ec, key, WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE); + + /* TOPMOST(TOP_POSITION) grab */ + _e_keyrouter_find_and_remove_client_from_list(ec, key, WL_KEYROUTER_MODE_TOPMOST); + + /* SHARED grab */ + _e_keyrouter_find_and_remove_client_from_list(ec, key, WL_KEYROUTER_MODE_SHARED); + + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, WL_KEYROUTER_MODE_NONE, WL_KEYROUTER_ERROR_NONE); +} + +/* wl_keyrouter get_keygrab_status request handler */ +static void +_e_keyrouter_cb_get_keygrab_status(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t key) +{ + (void) client; + (void) resource; + (void) surface; + (void) key; + + if (!surface) + { + KLDBG("No surface !\n"); + + /* Regarding exclusive mode, a client can request to grab a key without a surface. + * TODO : Need to check the (grab) mode */ +#if 0 + if (mode < WL_KEYROUTER_MODE_EXCLUSIVE) + { + KLDBG("Invalid surface ! (key=%d, mode=%d)\n", key, mode); + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, WL_KEYROUTER_MODE_NONE, WL_KEYROUTER_ERROR_INVALID_SURFACE); + return; + } + else + { + KLDBG("Null surface will be permitted only for EXCLUSIVE mode !\n"); + } +#endif + } + + /* TODO : Need to check key grab status for the requesting wl client */ + + WL_KEYGRAB_NOTIFY_WITH_VAL(resource, surface, key, WL_KEYROUTER_MODE_NONE, WL_KEYROUTER_ERROR_NONE); +} + +/* Function for adding a new key grab information into the keyrouting list */ +static int +_e_keyrouter_set_keygrab_in_list(struct wl_resource *surface, struct wl_client *client, uint32_t key, uint32_t mode) +{ + E_Pixmap *ep = NULL; + E_Client *ec = NULL; + + int res = WL_KEYROUTER_ERROR_NONE; + + if (!surface && mode == WL_KEYROUTER_MODE_EXCLUSIVE) + { + struct wl_listener *destroy_listener = NULL; + if (krt->HardKeys[key].excl_ptr) + { + KLDBG("key(%d) is already exclusive grabbed\n", key); + return WL_KEYROUTER_ERROR_GRABBED_ALREADY; + } + + E_Keyrouter_Key_List_NodePtr new_keyptr = E_NEW(E_Keyrouter_Key_List_Node, 1); + + if (!new_keyptr) + { + KLDBG("Failled to allocate memory for new_keyptr\n"); + return WL_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES; + } + + new_keyptr->ec = NULL; + new_keyptr->wc = client; + new_keyptr->next = NULL; + krt->HardKeys[key].excl_ptr = new_keyptr; + + KLDBG("Succeed to set keygrab information (WL_Client:%p, key:%d, mode:EXCLUSIVE(no surface))\n", client, key); + + destroy_listener = E_NEW(struct wl_listener, 1); + + if (!destroy_listener) + { + KLDBG("Failed to allocate memory for wl_client destroy listener !\n"); + return WL_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES; + } + + destroy_listener->notify = _e_keyrouter_wl_client_cb_destroy; + wl_client_add_destroy_listener(client, destroy_listener); + + KLDBG("Add a wl_client(%p) destroy listener(%p)\n", client, destroy_listener); + + return WL_KEYROUTER_ERROR_NONE; + } + + if (!surface || !(ep = wl_resource_get_user_data(surface))) + { + KLDBG("Surface or E_Pixman from the surface is invalid ! Return error !\n"); + return WL_KEYROUTER_ERROR_INVALID_SURFACE; + } + + if (!(ec = e_pixmap_client_get(ep))) + { + KLDBG("E_Client pointer from E_Pixman from surface is invalid ! Return error !\n"); + return WL_KEYROUTER_ERROR_INVALID_SURFACE; + } + + KLDBG("E_Client(%p) request to grab a key(%d) with mode(%d)\n", ec, key, mode); + + switch(mode) + { + case WL_KEYROUTER_MODE_EXCLUSIVE: + if (krt->HardKeys[key].excl_ptr) + { + KLDBG("key(%d) is already exclusive grabbed\n", key); + return WL_KEYROUTER_ERROR_GRABBED_ALREADY; + } + + E_Keyrouter_Key_List_NodePtr new_keyptr = E_NEW(E_Keyrouter_Key_List_Node, 1); + + if (!new_keyptr) + { + KLDBG("Failled to allocate memory for new_keyptr\n"); + return WL_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES; + } + + new_keyptr->ec = ec; + new_keyptr->wc = client; + new_keyptr->next = NULL; + krt->HardKeys[key].excl_ptr = new_keyptr; + KLDBG("Succeed to set keygrab information (E_Client:%p, key:%d, mode:EXCLUSIVE)\n", ec, key); + break; + + case WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + res = _e_keyrouter_prepend_to_keylist(ec, client, key, mode); + CHECK_ERR_VAL(res); + KLDBG("Succeed to set keygrab information (E_Client:%p, key:%d, mode:OR_EXCLUSIVE)\n", ec, key); + break; + + case WL_KEYROUTER_MODE_TOPMOST: + res = _e_keyrouter_prepend_to_keylist(ec, client, key, mode); + CHECK_ERR_VAL(res); + KLDBG("Succeed to set keygrab information (E_Client:%p, key:%d, mode:TOPMOST)\n", ec, key); + break; + + case WL_KEYROUTER_MODE_SHARED: + res = _e_keyrouter_prepend_to_keylist(ec, client, key, mode); + CHECK_ERR_VAL(res); + KLDBG("Succeed to set keygrab information (E_Client:%p, key:%d, mode:SHARED)\n", ec, key); + break; + + default: + KLDBG("Unknown key(%d) grab mode(%d)\n", key, mode); + return WL_KEYROUTER_ERROR_INVALID_MODE; + } + + //KLDBG("krt->HardKeys[%d].keycode: %d\n", key, krt->HardKeys[key].keycode); + return WL_KEYROUTER_ERROR_NONE; +} + + +/* Function for checking whether the key has been grabbed already by the same wl_surface or not */ +static int +_e_keyrouter_find_duplicated_client(E_Client *ec, uint32_t key, uint32_t mode) +{ + E_Keyrouter_Key_List_NodePtr keylist_ptr; + + switch(mode) + { + case WL_KEYROUTER_MODE_EXCLUSIVE: + return WL_KEYROUTER_ERROR_NONE; + + case WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + keylist_ptr = krt->HardKeys[key].or_excl_ptr; + break; + + case WL_KEYROUTER_MODE_TOPMOST: + keylist_ptr = krt->HardKeys[key].top_ptr; + break; + + case WL_KEYROUTER_MODE_SHARED: + keylist_ptr = krt->HardKeys[key].shared_ptr; + break; + + case WL_KEYROUTER_MODE_PRESSED: + keylist_ptr = krt->HardKeys[key].press_ptr; + break; + + default: + KLDBG("Unknown key(%d) and grab mode(%d)\n", key, mode); + return WL_KEYROUTER_ERROR_INVALID_MODE; + } + + while(keylist_ptr) + { + if (keylist_ptr->ec == ec) + { + KLDBG("The key(%d) is already grabbed same mode(%d) on the same E_Client(%p)\n", key, mode, ec); + return WL_KEYROUTER_ERROR_GRABBED_ALREADY; + } + keylist_ptr = keylist_ptr->next; + } + + //KLDBG("The key(%d) is not grabbed by mode(%d) for the same E_Client(%p)\n", key, mode, ec); + return WL_KEYROUTER_ERROR_NONE; +} + +/* Function for prepending a new key grab information in the keyrouting list */ +static int +_e_keyrouter_prepend_to_keylist(E_Client *ec, struct wl_client *wc, uint32_t key, uint32_t mode) +{ + int res = WL_KEYROUTER_ERROR_NONE; + + res = _e_keyrouter_find_duplicated_client(ec, key, mode); + CHECK_ERR_VAL(res); + + E_Keyrouter_Key_List_NodePtr new_keyptr = E_NEW(E_Keyrouter_Key_List_Node, 1); + + if (!new_keyptr) + { + KLDBG("Failled to allocate memory for new_keyptr\n"); + return WL_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES; + } + + new_keyptr->ec = ec; + new_keyptr->wc = wc; + + KLDBG("Now it's going to add a key(%d) mode(%d) for ec(%p)\n", key, mode, ec); + + switch(mode) + { + case WL_KEYROUTER_MODE_EXCLUSIVE: + new_keyptr->next = krt->HardKeys[key].excl_ptr; + krt->HardKeys[key].excl_ptr = new_keyptr; + KLDBG("WL_KEYROUTER_MODE_EXCLUSIVE, key=%d, E_Client(%p) has been set !\n", key, ec); + break; + + case WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + new_keyptr->next = krt->HardKeys[key].or_excl_ptr; + krt->HardKeys[key].or_excl_ptr = new_keyptr; + KLDBG("WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, key=%d, E_Client(%p) has been set !\n", key, ec); + break; + + case WL_KEYROUTER_MODE_TOPMOST: + new_keyptr->next = krt->HardKeys[key].top_ptr; + krt->HardKeys[key].top_ptr = new_keyptr; + KLDBG("WL_KEYROUTER_MODE_TOPMOST, key=%d, E_Client(%p) has been set !\n", key, ec); + break; + + case WL_KEYROUTER_MODE_SHARED: + new_keyptr->next = krt->HardKeys[key].shared_ptr; + krt->HardKeys[key].shared_ptr = new_keyptr; + KLDBG("WL_KEYROUTER_MODE_SHARED, key=%d, E_Client(%p) has been set !\n", key, ec); + break; + + case WL_KEYROUTER_MODE_PRESSED: + new_keyptr->next = krt->HardKeys[key].press_ptr; + krt->HardKeys[key].press_ptr = new_keyptr; + KLDBG("WL_KEYROUTER_MODE_PRESSED, key=%d, E_Client(%p) has been set !\n", key, ec); + break; + + default: + KLDBG("Unknown key(%d) and grab mode(%d)\n", key, mode); + return WL_KEYROUTER_ERROR_INVALID_MODE; + } + + return WL_KEYROUTER_ERROR_NONE; +} + +/* Function to be called by the other functions regarding the removal of key grab information */ +static void +_e_keyrouter_remove_from_keylist(E_Client *ec, uint32_t key, uint32_t mode, E_Keyrouter_Key_List_NodePtr prev_node, E_Keyrouter_Key_List_NodePtr key_node) +{ + /* TODO: memory free after remove from list */ + + KLDBG("Try to remove e_client(%p) key(%d) mode(%d) prev_node: %p, key_node: %p\n", ec, key, mode, prev_node, key_node); + + switch(mode) + { + case WL_KEYROUTER_MODE_EXCLUSIVE: + key_node->ec = NULL; + key_node ->wc = NULL; + E_FREE(key_node); + + key_node = NULL; + krt->HardKeys[key].excl_ptr = key_node; + KLDBG("WL_KEYROUTER_MODE_EXCLUSIVE Succeed to remove grab information ! (e_client:%p, key:%d)\n", ec, key); + break; + + case WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + case WL_KEYROUTER_MODE_TOPMOST: + case WL_KEYROUTER_MODE_SHARED: + if (!prev_node) + { + /* First Node */ + switch (mode) + { + case WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + krt->HardKeys[key].or_excl_ptr = key_node->next; + break; + + case WL_KEYROUTER_MODE_TOPMOST: + krt->HardKeys[key].top_ptr = key_node->next; + break; + + case WL_KEYROUTER_MODE_SHARED: + krt->HardKeys[key].shared_ptr = key_node->next; + break; + + default: + break; + } + key_node->ec = NULL; + key_node = NULL; + } + else + { + prev_node->next = key_node->next; + key_node->ec = NULL; + key_node = NULL; + } + + if (mode == WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE) + { + KLDBG("WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE Succeed to remove grab information ! (e_client:%p, key:%d)\n", ec, key); + } + else if (mode == WL_KEYROUTER_MODE_TOPMOST) + { + KLDBG("WL_KEYROUTER_MODE_TOPMOST Succeed to remove grab information ! (e_client:%p, key:%d)\n", ec, key); + } + else if (mode == WL_KEYROUTER_MODE_SHARED) + { + KLDBG("WL_KEYROUTER_MODE_SHARED Succeed to remove grab information ! (e_client:%p, key:%d)\n", ec, key); + } + break; + + default: + KLDBG("Unknown key(%d) and grab mode(%d)\n", key, mode); + return; + } + + return; +} + +/* Function for removing the existing key grab information from the list */ +static void +_e_keyrouter_find_and_remove_client_from_list(E_Client *ec, uint32_t key, uint32_t mode) +{ + E_Keyrouter_Key_List_NodePtr prev_node = NULL, cur_node = NULL; + + switch (mode) + { + case WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + cur_node = krt->HardKeys[key].or_excl_ptr; + break; + + case WL_KEYROUTER_MODE_TOPMOST: + cur_node = krt->HardKeys[key].top_ptr; + break; + + case WL_KEYROUTER_MODE_SHARED: + cur_node = krt->HardKeys[key].shared_ptr; + break; + + default: + KLDBG("Unknown key(%d) and grab mode(%d)\n", key, mode); + return; + } + + while (cur_node) + { + if (ec == cur_node->ec) + { + _e_keyrouter_remove_from_keylist(ec, key, mode, prev_node, cur_node); + break; + } + + prev_node = cur_node; + cur_node = cur_node->next; + } +} + +static void +_e_keyrouter_remove_client_from_list(E_Client *ec, struct wl_client *wc) +{ + int index = 0; + if (!ec && !wc) + { + return; + } + + for(index=0; indexHardKeys[index].keycode) + { + continue; + } + + /* exclusive grab */ + if (krt->HardKeys[index].excl_ptr) + { + if (ec && (ec == krt->HardKeys[index].excl_ptr->ec) ) + { + KLDBG("Remove exclusive key(%d) by ec(%p)", index, ec); + _e_keyrouter_remove_from_keylist(ec, index, WL_KEYROUTER_MODE_EXCLUSIVE, NULL, krt->HardKeys[index].excl_ptr); + } + else if (wc && (wc == krt->HardKeys[index].excl_ptr->wc) ) + { + KLDBG("Remove exclusive key(%d) by wc(%p)", index, wc); + _e_keyrouter_remove_from_keylist(ec, index, WL_KEYROUTER_MODE_EXCLUSIVE, NULL, krt->HardKeys[index].excl_ptr); + } + } + + /* or exclusive grab */ + _e_keyrouter_find_and_remove_client_from_list(ec, index, WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE); + + /* top position grab */ + _e_keyrouter_find_and_remove_client_from_list(ec, index, WL_KEYROUTER_MODE_TOPMOST); + + /* shared grab */ + _e_keyrouter_find_and_remove_client_from_list(ec, index, WL_KEYROUTER_MODE_SHARED); + } +} + +static Eina_Bool +_e_keyrouter_is_key_grabbed(int key) +{ + if (!krt->HardKeys[key].keycode) + { + return EINA_FALSE; + } + if (!krt->HardKeys[key].excl_ptr && + !krt->HardKeys[key].or_excl_ptr && + !krt->HardKeys[key].top_ptr && + !krt->HardKeys[key].shared_ptr) + { + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static const struct wl_keyrouter_interface _e_keyrouter_implementation = { + _e_keyrouter_cb_keygrab_set, + _e_keyrouter_cb_keygrab_unset, + _e_keyrouter_cb_get_keygrab_status +}; + +/* wl_keyrouter global object destroy function */ +static void +_e_keyrouter_cb_destory(struct wl_resource *resource) +{ + /* TODO : destroy resources if exist */ +} + +/* wl_keyrouter global object bind function */ +static void +_e_keyrouter_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + E_KeyrouterPtr krt_instance = data; + struct wl_resource *resource; + + resource = wl_resource_create(client, &wl_keyrouter_interface, MIN(version, 1), id); + + KLDBG("wl_resource_create(...,&wl_keyrouter_interface,...)\n"); + + if (!resource) + { + KLDBG("Failed to create resource ! (version :%d, id:%d)\n", version, id); + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &_e_keyrouter_implementation, krt_instance, _e_keyrouter_cb_destory); + + KLDBG("wl_resource_set_implementation(..., _e_keyrouter_implementation, ...)\n"); +} + +/* Function for checking the existing grab for a key and sending key event(s) */ +static Eina_Bool +_e_keyrouter_process_key_event(void *event, int type) +{ + Eina_Bool res = EINA_TRUE; + Ecore_Event_Key *ev = event; + + if (!ev) return res; + + KLDBG("type=%s\n", (type == ECORE_EVENT_KEY_DOWN) ? "ECORE_EVENT_KEY_DOWN" : "ECORE_EVENT_KEY_UP"); + + if (0 > ev->keycode || MAX_HWKEYS < ev->keycode) + { + KLDBG("The key(%d) is too larger to process keyrouting: Invalid keycode\n", ev->keycode); + return res; + } + + if ( (ECORE_EVENT_KEY_DOWN == type) && (!_e_keyrouter_is_key_grabbed(ev->keycode)) ) + { + KLDBG("The press key(%d) isn't a grabbable key or has not been grabbed yet !\n", ev->keycode); + return res; + } + + if ( (ECORE_EVENT_KEY_UP == type) && (!krt->HardKeys[ev->keycode].press_ptr) ) + { + KLDBG("The release key(%d) isn't a grabbable key or has not been grabbed yet !\n", ev->keycode); + return res; + } + + //KLDBG("The key(%d) is going to be sent to the proper wl client(s) !\n", ev->keycode); + + if (_e_keyrouter_send_key_events(type, ev)) + { + res = EINA_FALSE; + KLDBG("Key event(s) has/have been sent to wl client(s) !\n"); + } + + return res; +} + +/* Function for sending key events to wl_client(s) */ +static Eina_Bool +_e_keyrouter_send_key_events(int type, Ecore_Event_Key *ev) +{ + Eina_Bool res; + if (ECORE_EVENT_KEY_DOWN == type) + { + res = _e_keyrouter_send_key_events_press(type, ev); + } + else + { + res = _e_keyrouter_send_key_events_release(type, ev); + } + return res; +} + +static Eina_Bool +_e_keyrouter_send_key_events_release(int type, Ecore_Event_Key *ev) +{ + E_Keyrouter_Key_List_NodePtr press_key = NULL, next_key = NULL; + + for (press_key = krt->HardKeys[ev->keycode].press_ptr; press_key; press_key = press_key->next) + { + _e_keyrouter_send_key_event(type, press_key->ec, ev); + KLDBG("Press/Release Pair : Key %s(%d) ===> Client (%p)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "UP "), ev->keycode, krt->HardKeys[ev->keycode].press_ptr->ec); + } + + for (press_key = krt->HardKeys[ev->keycode].press_ptr; press_key; press_key = next_key) + { + next_key = press_key->next; + E_FREE(press_key); + } + krt->HardKeys[ev->keycode].press_ptr = NULL; + + return EINA_TRUE; +} + +static Eina_Bool +_e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *ev) +{ + unsigned int keycode = ev->keycode; + E_Client *ec_focus; + + if (krt->HardKeys[keycode].excl_ptr) + { + _e_keyrouter_send_key_event(type, krt->HardKeys[keycode].excl_ptr->ec, ev); + KLDBG("EXCLUSIVE Mode : Key %s(%d) ===> Client (%p)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "UP "), ev->keycode, krt->HardKeys[keycode].excl_ptr->ec); + + return EINA_TRUE; + } + + if (krt->HardKeys[keycode].or_excl_ptr) + { + _e_keyrouter_send_key_event(type, krt->HardKeys[keycode].or_excl_ptr->ec, ev); + KLDBG("OVERRIDABLE_EXCLUSIVE Mode : Key %s (%d) ===> Client (%p)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "UP"), ev->keycode, krt->HardKeys[keycode].or_excl_ptr->ec); + + return EINA_TRUE; + } + + ec_focus = e_client_focused_get(); + + if (krt->HardKeys[keycode].top_ptr) + { + E_Comp *c; + + if ((EINA_FALSE == krt->isWindowStackChanged) && (ec_focus == krt->HardKeys[keycode].top_ptr->ec)) + { + _e_keyrouter_send_key_event(type, krt->HardKeys[keycode].top_ptr->ec, ev); + KLDBG("TOPMOST (TOP_POSITION) Mode : Key %s (%d) ===> Client (%p)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "UP"), ev->keycode, krt->HardKeys[keycode].top_ptr->ec); + + return EINA_TRUE; + } + + krt->isWindowStackChanged = EINA_FALSE; + + c = e_comp_find_by_window(ev->window); + if (_e_keyrouter_check_top_visible_window(c, ec_focus, keycode)) + { + KLDBG("TOPMOST (TOP_POSITION) Mode : Key %s (%d) ===> Client (%p)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "UP"), ev->keycode, krt->HardKeys[keycode].top_ptr->ec); + _e_keyrouter_send_key_event(type, krt->HardKeys[keycode].top_ptr->ec, ev); + + return EINA_TRUE; + } + } + if (krt->HardKeys[keycode].shared_ptr) + { + E_Keyrouter_Key_List_NodePtr keylist_deliver = krt->HardKeys[keycode].shared_ptr; + + _e_keyrouter_send_key_event(type, ec_focus, ev); + KLDBG("SHARED [Focus client] : Key %s (%d) ===> Client (%p)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "UP "), ev->keycode, ec_focus); + + while (keylist_deliver) + { + if (keylist_deliver->ec != ec_focus) + { + _e_keyrouter_send_key_event(type, keylist_deliver->ec, ev); + KLDBG("SHARED Mode : Key %s (%d) ===> Client (%p)\n", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "UP"), ev->keycode, krt->HardKeys[keycode].shared_ptr->ec); + } + keylist_deliver = keylist_deliver->next; + } + + return EINA_TRUE; + } + + return EINA_FALSE; +} + +static Eina_Bool +_e_keyrouter_check_top_visible_window(E_Comp *c, E_Client *ec_focus, int arr_idx) +{ + E_Client *ec_top; + E_Keyrouter_Key_List_NodePtr keylistPtr; + + ec_top = e_client_top_get(c); + KLDBG("Top Client: %p\n", ec_top); + + while (ec_top) + { + if (!ec_top->visible && ec_top == ec_focus) + { + KLDBG("Top Client(%p) is invisible(%d) but focus client\n", ec_top, ec_top->visible); + return EINA_FALSE; + } + + /* TODO: Check this client is located inside a display boundary */ + + for (keylistPtr = krt->HardKeys[arr_idx].top_ptr; keylistPtr; keylistPtr=keylistPtr->next) + { + if (ec_top == keylistPtr->ec) + { + _e_keyrouter_rearray_list_item_to_top(WL_KEYROUTER_MODE_TOPMOST, arr_idx, keylistPtr); + KLDBG("Move a client(%p) to first index of list, krt->HardKey[%d].top_ptr->ec: (%p)\n", + ec_top, arr_idx, krt->HardKeys[arr_idx].top_ptr->ec); + + return EINA_TRUE; + } + } + + if (ec_top == ec_focus) + { + KLDBG("The Client(%p) is a focus client\n", ec_top); + return EINA_FALSE; + } + + ec_top = e_client_below_get(ec_top); + KLDBG("Next client: %p\n", ec_top); + } + return EINA_FALSE; +} + +static void +_e_keyrouter_rearray_list_item_to_top(int mode, int arr_idx, E_Keyrouter_Key_List_NodePtr keylistPtr) +{ + E_Keyrouter_Key_List_NodePtr beforePtr, currentPtr; + + switch (mode) + { + case WL_KEYROUTER_MODE_EXCLUSIVE: + case WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + break; + + case WL_KEYROUTER_MODE_TOPMOST: + beforePtr = currentPtr = krt->HardKeys[arr_idx].top_ptr; + for ( ; currentPtr; currentPtr = currentPtr->next) + { + if (currentPtr->ec == keylistPtr->ec) + { + if (currentPtr->ec == krt->HardKeys[arr_idx].top_ptr->ec) + { + break; + } + + beforePtr->next = currentPtr->next; + currentPtr->next = krt->HardKeys[arr_idx].top_ptr; + krt->HardKeys[arr_idx].top_ptr = currentPtr; + } + beforePtr = currentPtr; + } + break; + + case WL_KEYROUTER_MODE_SHARED: + default: + break; + } +} + +/* Function for sending key event to wl_client(s) */ +static void +_e_keyrouter_send_key_event(int type, E_Client *ec, Ecore_Event_Key *ev) +{ + struct wl_client *wc; + struct wl_resource *res; + + uint evtype; + uint serial; + Eina_List *l; + + if (ec == NULL) + { + wc = krt->HardKeys[ev->keycode].excl_ptr->wc; + } + else + { + wc = wl_resource_get_client(ec->comp_data->wl_surface); + } + + if (ECORE_EVENT_KEY_DOWN == type) + { + _e_keyrouter_prepend_to_keylist(ec, wc, ev->keycode, WL_KEYROUTER_MODE_PRESSED); + evtype = WL_KEYBOARD_KEY_STATE_PRESSED; + } + else + { + evtype = WL_KEYBOARD_KEY_STATE_RELEASED; + } + + serial = wl_display_next_serial(krt->cdata->wl.disp); + EINA_LIST_FOREACH(krt->cdata->kbd.resources, l, res) + { + if (res) + { + if (wl_resource_get_client(res) != wc) continue; + + KLDBG("[time: %d] res: %p, serial: %d send a key(%d):%d to wl_client:%p\n", ev->timestamp, res, serial, (ev->keycode)-8, evtype, wc); + wl_keyboard_send_key(res, serial, ev->timestamp, ev->keycode-8, evtype); + } + } +} + + +static Eina_Bool +_event_filter(void *data, void *loop_data EINA_UNUSED, int type, void *event) +{ + (void) data; + (void) type; + (void) event; + + /* Filter only for key down/up event */ + if (ECORE_EVENT_KEY_DOWN == type || ECORE_EVENT_KEY_UP == type) + { + return _e_keyrouter_process_key_event(event, type); + } + + return EINA_TRUE; +} + +static Eina_Bool +_e_keyrouter_init() +{ + krt = E_NEW(E_Keyrouter, 1); + + if (!krt) + { + KLDBG("Failed to allocate memory for krt !\n"); + return EINA_FALSE; + } + + if (!e_comp) + { + KLDBG("Failed to initialize keyrouter module ! (e_comp == NULL)\n"); + goto err; + } + + E_Comp_Data *cdata = e_comp->wl_comp_data; + + if (!cdata) + { + KLDBG("Failed to get wl_comp_data ! (e_comp->wl_comp_data == NULL)\n"); + goto err; + } + + krt->cdata = cdata; + krt->global = wl_global_create(cdata->wl.disp, &wl_keyrouter_interface, 1, krt, _e_keyrouter_cb_bind); + + if (!krt->global) + { + KLDBG("Failed to create global !\n"); + goto err; + } + + /* Get keyname and keycode pair from Tizen Key Layout file */ + _e_keyrouter_query_tizen_key_table(); + +#if 0 + int i = 0; + for (i=0 ; i < krt->numTizenHWKeys ; i++) + { + KLDBG("keycode[%d], keyname[%s] : Enabled to grab\n", krt->TizenHWKeys[i].keycode, krt->TizenHWKeys[i].name); + } +#endif + + /* Add filtering mechanism */ + krt->ef_handler = ecore_event_filter_add(NULL, _event_filter, NULL, NULL); + _e_keyrouter_init_handlers(); + + return EINA_TRUE; + +err: + if (krt && krt->ef_handler) ecore_event_filter_del(krt->ef_handler); + if (krt) E_FREE(krt); + + return EINA_FALSE; +} + +EAPI void * +e_modapi_init(E_Module *m) +{ + return (_e_keyrouter_init() ? m : NULL); +} + +EAPI int +e_modapi_shutdown(E_Module *m EINA_UNUSED) +{ + _e_keyrouter_deinit_handlers(); + /* TODO: free allocated memory */ + + return 1; +} + +EAPI int +e_modapi_save(E_Module *m EINA_UNUSED) +{ + /* Save something to be kept */ + return 1; +} + +/* Function for getting keyname/keycode information from a key layout file */ +static void +_e_keyrouter_query_tizen_key_table(void) +{ + FILE *fp_key_tables = NULL; + char keyname[64] = {0, }; + int key_count = 0; + int key_size = 0; + int keycode = 0; + int i = 0; + + fp_key_tables = fopen(KEYLAYOUT_PATH, "r"); + + if (!fp_key_tables) + { + KLDBG("Failed to read file (%s)\n", KEYLAYOUT_PATH); + return; + } + + //KLDBG("Support Tizen Keymap\n"); + while ( 0 < fscanf(fp_key_tables, "%s %d", keyname, &keycode)) + { + key_count++; + //KLDBG(" - [%s : %d]\n", keyname, keycode); + } + + krt->TizenHWKeys = E_NEW(E_Keyrouter_Tizen_HWKey, key_count); + krt->numTizenHWKeys = key_count; + + fseek(fp_key_tables, 0, SEEK_SET); + + for (i=0; iTizenHWKeys[i].name = (char*)calloc(key_size, sizeof(char)); + + if (!krt->TizenHWKeys[i].name) + { + KLDBG("Failed to allocate memory !\n"); + continue; + } + + strncpy(krt->TizenHWKeys[i].name, keyname, key_size); + + krt->TizenHWKeys[i].keycode = keycode+8; + krt->HardKeys[keycode+8].keycode = keycode+8; + } + + fclose(fp_key_tables); +} + +static void +_e_keyrouter_deinit_handlers(void) +{ + Ecore_Event_Handler *h = NULL; + + if (!krt || !krt->handlers) return; + + EINA_LIST_FREE(krt->handlers, h) + ecore_event_handler_del(h); +} + +static void +_e_keyrouter_init_handlers(void) +{ + E_LIST_HANDLER_APPEND(krt->handlers, E_EVENT_CLIENT_STACK, _e_keyrouter_client_cb_stack, NULL); + E_LIST_HANDLER_APPEND(krt->handlers, E_EVENT_CLIENT_REMOVE, _e_keyrouter_client_cb_remove, NULL); +} + +static Eina_Bool +_e_keyrouter_client_cb_stack(void *data, int type, void *event) +{ + E_Event_Client *ev = event; + E_Client *ec = ev->ec; + + (void) data; + (void) type; + (void) event; + (void) ev; + (void) ec; + + //KLDBG("ec: %p, visibile: %d, focused: %d, take_focus: %d, want_focus: %d, bordername: %s, input_only: %d\n", + // ec, ec->visible, ec->focused, ec->take_focus, ec->want_focus, ec->bordername, ec->input_only); + + krt->isWindowStackChanged = EINA_TRUE; + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_e_keyrouter_client_cb_remove(void *data, int type, void *event) +{ + E_Event_Client *ev = event; + E_Client *ec = ev->ec; + + (void) data; + (void) type; + (void) event; + + //KLDBG("ec: %p, visibile: %d, focused: %d, take_focus: %d, want_focus: %d, bordername: %s, input_only: %d\n", + // ec, ec->visible, ec->focused, ec->take_focus, ec->want_focus, ec->bordername, ec->input_only); + + _e_keyrouter_remove_client_from_list(ec, NULL); + + return ECORE_CALLBACK_PASS_ON; +} + +static void +_e_keyrouter_wl_client_cb_destroy(struct wl_listener *l, void *data) +{ + struct wl_client *client = data; + + KLDBG("Listener(%p) called: wl_client: %p is died\n", l, client); + _e_keyrouter_remove_client_from_list(NULL, client); + + E_FREE(l); + l = NULL; +} diff --git a/src/e_mod_main_wl.h b/src/e_mod_main_wl.h new file mode 100644 index 0000000..ad1f03b --- /dev/null +++ b/src/e_mod_main_wl.h @@ -0,0 +1,96 @@ +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +/* Temporary value of maximum number of HWKeys */ +#define MAX_HWKEYS 512 + +#define CHECK_ERR(val) if (WL_KEYROUTER_ERROR_NONE != val) return; +#define CHECK_ERR_VAL(val) if (WL_KEYROUTER_ERROR_NONE != val) return val; +#define CHECK_NULL(val) if (!val) return; +#define CHECK_NULL_VAL(val) if (!val) return val; + +#define KLDBG(msg, ARG...) DBG("[wl_keyrouter][%s:%d] "msg, __FUNCTION__, __LINE__, ##ARG) +#define WL_KEYGRAB_NOTIFY_WITH_VAL(resource,surface,key,mode,err) \ + wl_keyrouter_send_keygrab_notify(resource, surface, key, mode, err); \ + return + +typedef struct _E_Keyrouter E_Keyrouter; +typedef struct _E_Keyrouter* E_KeyrouterPtr; +typedef struct _E_Keyrouter_Key_List_Node E_Keyrouter_Key_List_Node; +typedef struct _E_Keyrouter_Key_List_Node* E_Keyrouter_Key_List_NodePtr; +typedef struct _E_Keyrouter_Tizen_HWKey E_Keyrouter_Tizen_HWKey; +typedef struct _E_Keyrouter_Grabbed_Key E_Keyrouter_Grabbed_Key; + +#define WL_KEYROUTER_MODE_PRESSED WL_KEYROUTER_MODE_EXCLUSIVE+1 + +struct _E_Keyrouter_Key_List_Node +{ + E_Client *ec; + struct wl_client *wc; + struct _E_Keyrouter_Key_List_Node* next; +}; + +struct _E_Keyrouter_Tizen_HWKey +{ + char *name; + int keycode; +}; + +struct _E_Keyrouter_Grabbed_Key +{ + int keycode; + char* keyname; + + E_Keyrouter_Key_List_Node* excl_ptr; + E_Keyrouter_Key_List_Node* or_excl_ptr; + E_Keyrouter_Key_List_Node* top_ptr; + E_Keyrouter_Key_List_Node* shared_ptr; + E_Keyrouter_Key_List_NodePtr press_ptr; +}; + +struct _E_Keyrouter +{ + E_Comp_Data *cdata; + struct wl_global *global; + Ecore_Event_Filter *ef_handler; + Eina_List *handlers; + + E_Keyrouter_Grabbed_Key HardKeys[MAX_HWKEYS]; + E_Keyrouter_Tizen_HWKey *TizenHWKeys; + + Eina_Bool isWindowStackChanged; + int numTizenHWKeys; +}; + +/* E Module */ +EAPI extern E_Module_Api e_modapi; +EAPI void *e_modapi_init(E_Module *m); +EAPI int e_modapi_shutdown(E_Module *m); +EAPI int e_modapi_save(E_Module *m); + +static Eina_Bool _e_keyrouter_init(); +static void _e_keyrouter_init_handlers(void); +static void _e_keyrouter_deinit_handlers(void); + +static int _e_keyrouter_set_keygrab_in_list(struct wl_resource *surface, struct wl_client *client, uint32_t key, uint32_t mode); +static int _e_keyrouter_find_duplicated_client(E_Client *ec, uint32_t key, uint32_t mode); +static int _e_keyrouter_prepend_to_keylist(E_Client *ec, struct wl_client *wc, uint32_t key, uint32_t mode); +static void _e_keyrouter_remove_from_keylist(E_Client *ec, uint32_t key, uint32_t mode, E_Keyrouter_Key_List_NodePtr prev_node, E_Keyrouter_Key_List_NodePtr key_node); +static void _e_keyrouter_find_and_remove_client_from_list(E_Client *ec, uint32_t key, uint32_t mode); +static void _e_keyrouter_remove_client_from_list(E_Client *ec, struct wl_client *wc); +static void _e_keyrouter_rearray_list_item_to_top(int mode, int arr_idx, E_Keyrouter_Key_List_NodePtr keylistPtr); + +static Eina_Bool _e_keyrouter_process_key_event(void *event, int type); +static Eina_Bool _e_keyrouter_send_key_events(int type, Ecore_Event_Key *ev); +static Eina_Bool _e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *ev); +static Eina_Bool _e_keyrouter_send_key_events_release(int type, Ecore_Event_Key *ev); +static void _e_keyrouter_send_key_event(int type, E_Client *ec, Ecore_Event_Key *ev); +static Eina_Bool _e_keyrouter_is_key_grabbed(int key); +static Eina_Bool _e_keyrouter_check_top_visible_window(E_Comp *c, E_Client *ec_focus, int arr_idx); +static void _e_keyrouter_query_tizen_key_table(void); + +static Eina_Bool _e_keyrouter_client_cb_stack(void *data, int type, void *event); +static Eina_Bool _e_keyrouter_client_cb_remove(void *data, int type, void *event); +static void _e_keyrouter_wl_client_cb_destroy(struct wl_listener *l, void *data); + +#endif