From: JengHyun Kang Date: Tue, 3 Apr 2018 11:02:38 +0000 (+0900) Subject: e_keyrouter: take keyrouter functions to enlightenment's core X-Git-Tag: accepted/tizen/unified/20180416.213825~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4abd03ecdd95788b034ed039257eb5c335380a98;p=platform%2Fupstream%2Fenlightenment.git e_keyrouter: take keyrouter functions to enlightenment's core - To send keys through keyrouter's policy Change-Id: I2c864c708c46347e61ccbc420b6f5455feb84efe --- diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index 0544650..62d6ff9 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -124,6 +124,7 @@ src/bin/e_process.h \ src/bin/e_privilege.h \ src/bin/e_security.h \ src/bin/e_keyrouter.h \ +src/bin/e_keyrouter_private.h \ src/bin/e_gesture.h \ src/bin/e_input.h @@ -226,6 +227,10 @@ src/bin/e_policy_wl_display.c \ src/bin/e_process.c \ src/bin/e_privilege.c \ src/bin/e_security.c \ +src/bin/e_keyrouter_events.c \ +src/bin/e_keyrouter_list.c \ +src/bin/e_keyrouter_conf.c \ +src/bin/e_keyrouter_wl.c \ src/bin/e_keyrouter.c \ src/bin/e_gesture.c \ src/bin/e_input_private.h \ diff --git a/src/bin/e_comp_canvas.c b/src/bin/e_comp_canvas.c index acdfd60..638ac85 100644 --- a/src/bin/e_comp_canvas.c +++ b/src/bin/e_comp_canvas.c @@ -63,20 +63,6 @@ _e_comp_canvas_cb_mouse_wheel(void *d EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Obj ; } -static Eina_Bool -_e_comp_cb_key_down(void *data EINA_UNUSED, int ev_type EINA_UNUSED, Ecore_Event_Key *ev) -{ - e_screensaver_notidle(); - return !e_comp_wl_key_down(ev); -} - -static Eina_Bool -_e_comp_cb_key_up(void *data EINA_UNUSED, int ev_type EINA_UNUSED, Ecore_Event_Key *ev) -{ - e_screensaver_notidle(); - return !e_comp_wl_key_up(ev); -} - //////////////////////////////////// static Eina_Bool @@ -199,8 +185,6 @@ e_comp_canvas_init(int w, int h) E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_ADD, _e_comp_cb_zone_change, NULL); E_LIST_HANDLER_APPEND(handlers, E_EVENT_ZONE_DEL, _e_comp_cb_zone_change, NULL); E_LIST_HANDLER_APPEND(handlers, E_EVENT_COMPOSITOR_ENABLE, _e_comp_cb_compositor_enabled, NULL); - E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_KEY_DOWN, _e_comp_cb_key_down, NULL); - E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_KEY_UP, _e_comp_cb_key_up, NULL); ecore_evas_callback_pre_render_set(e_comp->ee, _e_comp_canvas_prerender); ecore_evas_callback_resize_set(e_comp->ee, _e_comp_canvas_resize); diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c index 49b4a8c..40b56ee 100644 --- a/src/bin/e_comp_wl.c +++ b/src/bin/e_comp_wl.c @@ -59,8 +59,6 @@ static Eina_Bool need_send_motion = EINA_TRUE; static int _e_comp_wl_hooks_delete = 0; static int _e_comp_wl_hooks_walking = 0; -static Eina_Hash *_last_keydev_hash = NULL; - static Eina_Inlist *_e_comp_wl_hooks[] = { [E_COMP_WL_HOOK_SHELL_SURFACE_READY] = NULL, @@ -4724,52 +4722,6 @@ _e_comp_wl_gl_shutdown(void) e_comp_wl->wl.gl = NULL; } -static void -_e_comp_wl_client_cb_destroy(struct wl_listener *l, void *data) -{ - struct wl_client *client = (struct wl_client *)data; - - eina_hash_del_by_key(_last_keydev_hash, client); - - wl_list_remove(&l->link); - E_FREE(l); -} - -static void -_e_comp_wl_client_destroy_listener_add(struct wl_client *client) -{ - struct wl_listener *destroy_listener; - - EINA_SAFETY_ON_NULL_RETURN(client); - destroy_listener = wl_client_get_destroy_listener(client, _e_comp_wl_client_cb_destroy); - if (destroy_listener) return; - - destroy_listener = E_NEW(struct wl_listener, 1); - EINA_SAFETY_ON_NULL_RETURN(destroy_listener); - - destroy_listener->notify = _e_comp_wl_client_cb_destroy; - wl_client_add_destroy_listener(client, destroy_listener); -} - -static Eina_Bool -_e_comp_wl_keydev_hash_free(const Eina_Hash *hash, const void *key, void *data, void *fdata) -{ - struct wl_listener *destroy_listener; - struct wl_client *wc; - - wc = (struct wl_client *)key; - - destroy_listener = wl_client_get_destroy_listener(wc, _e_comp_wl_client_cb_destroy); - - if (destroy_listener) - { - wl_list_remove(&destroy_listener->link); - E_FREE(destroy_listener); - } - - return EINA_TRUE; -} - /* public functions */ /** @@ -4827,7 +4779,6 @@ e_comp_wl_init(void) E_LIST_HOOK_APPEND(hooks, E_CLIENT_HOOK_UNICONIFY, _e_comp_wl_client_cb_uniconify, NULL); E_EVENT_WAYLAND_GLOBAL_ADD = ecore_event_type_new(); - _last_keydev_hash = eina_hash_pointer_new(NULL); TRACE_DS_END(); return EINA_TRUE; @@ -4868,9 +4819,6 @@ e_comp_wl_shutdown(void) #endif e_comp_wl_remote_surface_shutdown(); - eina_hash_foreach(_last_keydev_hash, _e_comp_wl_keydev_hash_free, NULL); - eina_hash_free(_last_keydev_hash); - e_pixmap_shutdown(); e_comp_wl_shell_shutdown(); @@ -5382,13 +5330,12 @@ e_comp_wl_output_remove(const char *id) } static void -_e_comp_wl_key_send(Ecore_Event_Key *ev, enum wl_keyboard_key_state state, Eina_List *key_list, Eina_Bool focused) +_e_comp_wl_key_send(Ecore_Event_Key *ev, enum wl_keyboard_key_state state, Eina_List *key_list, E_Client *ec) { struct wl_resource *res; Eina_List *l; uint32_t serial, keycode; - struct wl_client *wc; - Ecore_Device *last_dev; + struct wl_client *wc = NULL; E_Comp_Config *comp_conf = NULL; keycode = (ev->keycode - 8); @@ -5397,23 +5344,15 @@ _e_comp_wl_key_send(Ecore_Event_Key *ev, enum wl_keyboard_key_state state, Eina_ comp_conf = e_comp_config_get(); + if (ec && ec->comp_data && ec->comp_data->surface) + wc = wl_resource_get_client(ec->comp_data->surface); + EINA_LIST_FOREACH(key_list, l, res) { - wc = wl_resource_get_client(res); - if (!focused && wc != ev->data) continue; + if (wl_resource_get_client(res) != wc) continue; + TRACE_INPUT_BEGIN(_e_comp_wl_key_send); - last_dev = eina_hash_find(_last_keydev_hash, wc); - if (!last_dev) - { - _e_comp_wl_client_destroy_listener_add(wc); - eina_hash_direct_add(_last_keydev_hash, wc, ev->dev); - _e_comp_wl_send_event_device(ev->data, ev->timestamp, ev->dev, serial); - } - else if (last_dev != ev->dev) - { - eina_hash_modify(_last_keydev_hash, wc, ev->dev); - _e_comp_wl_send_event_device(ev->data, ev->timestamp, ev->dev, serial); - } + _e_comp_wl_send_event_device(ev->data, ev->timestamp, ev->dev, serial); if (comp_conf && comp_conf->input_log_enable) INF("[Server] Key %s (time: %d)\n", (state ? "Down" : "Up"), ev->timestamp); @@ -5428,7 +5367,6 @@ EINTERN Eina_Bool e_comp_wl_key_down(Ecore_Event_Key *ev) { E_Client *ec = NULL; - struct wl_client *wc = NULL; uint32_t keycode; E_Comp_Wl_Key_Data *end, *k; @@ -5453,60 +5391,6 @@ e_comp_wl_key_down(Ecore_Event_Key *ev) } #endif - ec = e_client_focused_get(); - if (ec && ec->comp_data && ec->comp_data->surface) - wc = wl_resource_get_client(ec->comp_data->surface); - - if (ev->data) - { - if ((wc != ev->data) && (ev->data != (void *)0x1)) - { - _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_PRESSED, e_comp_wl->kbd.resources, EINA_FALSE); - } - else - { - ec = NULL; - end = (E_Comp_Wl_Key_Data *)e_comp_wl->kbd.routed_keys.data + (e_comp_wl->kbd.routed_keys.size / sizeof(*k)); - - for (k = e_comp_wl->kbd.routed_keys.data; k < end; k++) - { - /* ignore server-generated key repeats */ - if (k->key == keycode) - { - return EINA_FALSE; - } - } - - if (ev->data == (void *)0x1) return EINA_FALSE; - - if ((!e_client_action_get()) && (!e_comp->input_key_grabs)) - { - ec = e_client_focused_get(); - if (ec && ec->comp_data && ec->comp_data->surface && e_comp_wl->kbd.focused) - { - _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_PRESSED, e_comp_wl->kbd.focused, EINA_TRUE); - - /* A key only sent to clients is added to the list */ - e_comp_wl->kbd.routed_keys.size = (const char *)end - (const char *)e_comp_wl->kbd.routed_keys.data; - if (!(k = wl_array_add(&e_comp_wl->kbd.routed_keys, sizeof(*k)))) - { - DBG("wl_array_add: Out of memory\n"); - return EINA_FALSE; - } - k->key = keycode; - k->dev = ev->dev; - } - } - - /* update modifier state */ - e_comp_wl_input_keyboard_state_update(keycode, EINA_TRUE); - } - - return !!ec; - } - - ec = NULL; - end = (E_Comp_Wl_Key_Data *)e_comp_wl->kbd.keys.data + (e_comp_wl->kbd.keys.size / sizeof(*k)); for (k = e_comp_wl->kbd.keys.data; k < end; k++) @@ -5523,8 +5407,7 @@ e_comp_wl_key_down(Ecore_Event_Key *ev) ec = e_client_focused_get(); if (ec && ec->comp_data && ec->comp_data->surface && e_comp_wl->kbd.focused) { - ev->data = wc; - _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_PRESSED, e_comp_wl->kbd.focused, EINA_TRUE); + _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_PRESSED, e_comp_wl->kbd.focused, ec); /* A key only sent to clients is added to the list */ e_comp_wl->kbd.keys.size = (const char *)end - (const char *)e_comp_wl->kbd.keys.data; @@ -5548,7 +5431,6 @@ EINTERN Eina_Bool e_comp_wl_key_up(Ecore_Event_Key *ev) { E_Client *ec = NULL; - struct wl_client *wc = NULL; uint32_t keycode, delivered_key; E_Comp_Wl_Key_Data *end, *k; @@ -5565,52 +5447,6 @@ e_comp_wl_key_up(Ecore_Event_Key *ev) return EINA_FALSE; } - ec = e_client_focused_get(); - - if (ec && ec->comp_data && ec->comp_data->surface) - wc = wl_resource_get_client(ec->comp_data->surface); - - if (ev->data) - { - end = (E_Comp_Wl_Key_Data *)e_comp_wl->kbd.routed_keys.data + (e_comp_wl->kbd.routed_keys.size / sizeof(*k)); - for (k = e_comp_wl->kbd.routed_keys.data; k < end; k++) - { - if (k->key == keycode) - { - *k = *--end; - delivered_key = 1; - } - } - e_comp_wl->kbd.routed_keys.size = - (const char *)end - (const char *)e_comp_wl->kbd.routed_keys.data; - - if (wc != ev->data) - { - _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_RELEASED, e_comp_wl->kbd.resources, EINA_FALSE); - } - else - { - ec = NULL; - - if ((delivered_key) || - ((!e_client_action_get()) && (!e_comp->input_key_grabs))) - { - ec = e_client_focused_get(); - - if (e_comp_wl->kbd.focused) - { - _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_RELEASED, e_comp_wl->kbd.focused, EINA_FALSE); - } - } - - /* update modifier state */ - e_comp_wl_input_keyboard_state_update(keycode, EINA_FALSE); - } - return !!ec; - } - - ec = NULL; - end = (E_Comp_Wl_Key_Data *)e_comp_wl->kbd.keys.data + (e_comp_wl->kbd.keys.size / sizeof(*k)); for (k = e_comp_wl->kbd.keys.data; k < end; k++) { @@ -5632,8 +5468,7 @@ e_comp_wl_key_up(Ecore_Event_Key *ev) if (e_comp_wl->kbd.focused) { - ev->data = wc; - _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_RELEASED, e_comp_wl->kbd.focused, EINA_TRUE); + _e_comp_wl_key_send(ev, WL_KEYBOARD_KEY_STATE_RELEASED, e_comp_wl->kbd.focused, ec); } } @@ -5644,6 +5479,23 @@ e_comp_wl_key_up(Ecore_Event_Key *ev) } E_API Eina_Bool +e_comp_wl_key_process(Ecore_Event_Key *ev, int type) +{ + Eina_Bool res = EINA_FALSE; + + if (type == ECORE_EVENT_KEY_DOWN) + { + res = e_comp_wl_key_down(ev); + } + else if (type == ECORE_EVENT_KEY_UP) + { + res = e_comp_wl_key_up(ev); + } + + return res; +} + +E_API Eina_Bool e_comp_wl_evas_handle_mouse_button(E_Client *ec, uint32_t timestamp, uint32_t button_id, uint32_t state) { Eina_List *l; diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h index 12985d7..9c6ca39 100644 --- a/src/bin/e_comp_wl.h +++ b/src/bin/e_comp_wl.h @@ -586,6 +586,7 @@ EINTERN Eina_Bool e_comp_wl_mouse_in_send(E_Client *ec, int x, int y, Ecore_Devi EINTERN Eina_Bool e_comp_wl_mouse_out_send(E_Client *ec, Ecore_Device *dev, uint32_t time); EINTERN void e_comp_wl_mouse_in_renew(E_Client *ec, int buttons, int x, int y, void *data, Evas_Modifier *modifiers, Evas_Lock *locks, unsigned int timestamp, Evas_Event_Flags event_flags, Evas_Device *dev, Evas_Object *event_src); EINTERN void e_comp_wl_mouse_out_renew(E_Client *ec, int buttons, int x, int y, void *data, Evas_Modifier *modifiers, Evas_Lock *locks, unsigned int timestamp, Evas_Event_Flags event_flags, Evas_Device *dev, Evas_Object *event_src); +E_API Eina_Bool e_comp_wl_key_process(Ecore_Event_Key *ev, int type); EINTERN Eina_Bool e_comp_wl_cursor_hide(E_Client *ec); diff --git a/src/bin/e_keyrouter.c b/src/bin/e_keyrouter.c index 9deb5bf..12e8744 100644 --- a/src/bin/e_keyrouter.c +++ b/src/bin/e_keyrouter.c @@ -1,5 +1,6 @@ #include "e.h" #include "e_keyrouter.h" +#include "e_keyrouter_private.h" static int _e_keyrouter_intercept_hooks_delete = 0; static int _e_keyrouter_intercept_hooks_walking = 0; @@ -10,7 +11,10 @@ static Eina_Inlist *_e_keyrouter_intercept_hooks[] = [E_KEYROUTER_INTERCEPT_HOOK_DELIVER_FOCUS] = NULL, }; +int _keyrouter_log_dom = -1; + E_API E_Keyrouter_Info e_keyrouter; +E_KeyrouterPtr krt; 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) @@ -75,3 +79,440 @@ e_keyrouter_intercept_hook_call(E_Keyrouter_Intercept_Hook_Point hookpoint, int return res; } + +static void +_e_keyrouter_keygrab_status_print(FILE *log_fl, Eina_List *list) +{ + Eina_List *l; + E_Keyrouter_Key_List_NodePtr kdata; + int pid; + char *cmd; + + EINA_LIST_FOREACH(list, l, kdata) + { + pid = e_keyrouter_util_get_pid(kdata->wc, kdata->surface); + cmd = e_keyrouter_util_cmd_get_from_pid(pid); + fprintf(log_fl, " [surface: %p, client: %p, pid: %d(%s)]\n", kdata->surface, kdata->wc, pid, cmd ?: "Unknown"); + if(cmd) E_FREE(cmd); + if (kdata->surface) + { + fprintf(log_fl, " -- Surface Information --\n"); + fprintf(log_fl, " = client: %p\n", wl_resource_get_client(kdata->surface)); + fprintf(log_fl, " = resource: %s(%d)\n", wl_resource_get_class(kdata->surface), wl_resource_get_id(kdata->surface)); + } + else + { + fprintf(log_fl, " -- Client Information --\n"); + fprintf(log_fl, " = connected fd: %d\n", wl_client_get_fd(kdata->wc)); + } + } +} + +static void +_e_keyrouter_info_print(void *data, const char *log_path) +{ + char *keyname; + int i; + FILE *log_fl; + + log_fl = fopen(log_path, "a"); + if (!log_fl) + { + KLERR("failed: open file(%s)", log_path); + return; + } + + setvbuf(log_fl, NULL, _IOLBF, 512); + + fprintf(log_fl, "\n===== Keyrouter Information =====\n"); + fprintf(log_fl, " ----- Grabbable Keys -----\n"); + for (i = 8; i <= krt->max_tizen_hwkeys; i++) + { + if (!krt->HardKeys[i].keycode) continue; + + keyname = e_keyrouter_util_keyname_get_from_keycode(i); + + fprintf(log_fl, " Key [%3d], Keyname: %s\n", i, keyname); + + free(keyname); + keyname = NULL; + } + fprintf(log_fl, " ----- End -----\n\n"); + + fclose(log_fl); + log_fl = NULL; +} + +static void +_e_keyrouter_keygrab_print(void *data, const char *log_path) +{ + Eina_List *l; + E_Keyrouter_Key_List_NodePtr kdata; + E_Client *ec_focus; + struct wl_resource *surface_focus; + struct wl_client *wc_focus; + int pid_focus, pid, i; + char *cmd_focus, *cmd, *keyname; + FILE *log_fl; + + (void) data; + + log_fl = fopen(log_path, "a"); + if (!log_fl) + { + KLERR("failed: open file(%s)", log_path); + return; + } + + setvbuf(log_fl, NULL, _IOLBF, 512); + + fprintf(log_fl, "\n===== Keygrab Status =====\n"); + + ec_focus = e_client_focused_get(); + fprintf(log_fl, " ----- Focus Window Info -----\n"); + if (ec_focus) + { + surface_focus = e_keyrouter_util_get_surface_from_eclient(ec_focus); + wc_focus = wl_resource_get_client(surface_focus); + pid_focus = e_keyrouter_util_get_pid(NULL, surface_focus); + cmd_focus = e_keyrouter_util_cmd_get_from_pid(pid_focus); + + fprintf(log_fl, " Focus Client: E_Client: %p\n", ec_focus); + fprintf(log_fl, " Surface: %p, Client: %p\n", surface_focus, wc_focus); + fprintf(log_fl, " pid: %d, cmd: %s\n", pid_focus, cmd_focus ?: "Unknown"); + if(cmd_focus) E_FREE(cmd_focus); + } + else + { + fprintf(log_fl, " No Focus Client\n"); + } + fprintf(log_fl, " ----- End -----\n\n"); + + fprintf(log_fl, " ----- Grabbed keys Info -----\n\n"); + for (i = 8; i <= krt->max_tizen_hwkeys; i++) + { + if (!krt->HardKeys[i].keycode) continue; + if (!krt->HardKeys[i].excl_ptr && + !krt->HardKeys[i].or_excl_ptr && + !krt->HardKeys[i].top_ptr && + !krt->HardKeys[i].shared_ptr) + continue; + + keyname = e_keyrouter_util_keyname_get_from_keycode(i); + + fprintf(log_fl, " [ Keycode: %d, Keyname: %s ]\n", i, keyname); + + free(keyname); + keyname = NULL; + + if (krt->HardKeys[i].excl_ptr) + { + fprintf(log_fl, " == Exclusive Grab ==\n"); + EINA_LIST_FOREACH(krt->HardKeys[i].excl_ptr, l, kdata) + { + pid = e_keyrouter_util_get_pid(kdata->wc, kdata->surface); + cmd = e_keyrouter_util_cmd_get_from_pid(pid); + fprintf(log_fl, " [surface: %p, client: %p, pid: %d(%s)]\n", kdata->surface, kdata->wc, pid, cmd ?: "Unknown"); + if(cmd) E_FREE(cmd); + if (kdata->surface) + { + fprintf(log_fl, " -- Surface Information --\n"); + fprintf(log_fl, " = wl_client: %p\n", wl_resource_get_client(kdata->surface)); + fprintf(log_fl, " = resource: %s(%d)\n", wl_resource_get_class(kdata->surface), wl_resource_get_id(kdata->surface)); + } + else + { + fprintf(log_fl, " -- Client Information --\n"); + fprintf(log_fl, " = connected fd: %d\n", wl_client_get_fd(kdata->wc)); + } + } + } + + if (krt->HardKeys[i].or_excl_ptr) + { + fprintf(log_fl, " == Overidable Exclusive Grab ==\n"); + _e_keyrouter_keygrab_status_print(log_fl, krt->HardKeys[i].or_excl_ptr); + } + + if (krt->HardKeys[i].top_ptr) + { + fprintf(log_fl, " == Top Position Grab ==\n"); + _e_keyrouter_keygrab_status_print(log_fl, krt->HardKeys[i].top_ptr); + } + + if (krt->HardKeys[i].shared_ptr) + { + fprintf(log_fl, " == Shared Grab ==\n"); + _e_keyrouter_keygrab_status_print(log_fl, krt->HardKeys[i].shared_ptr); + } + + fprintf(log_fl, "\n"); + } + + fprintf(log_fl, " ----- End -----\n\n"); + + fclose(log_fl); + log_fl = NULL; +} + +static Eina_Bool +_e_keyrouter_cb_key_down(void *data, int type, void *event) +{ + Ecore_Event_Key *ev; + Eina_Bool res = ECORE_CALLBACK_PASS_ON; + + EINA_SAFETY_ON_NULL_RETURN_VAL(event, ECORE_CALLBACK_PASS_ON); + + ev = (Ecore_Event_Key *)event; + + TRACE_INPUT_BEGIN(_e_keyrouter_cb_key_down:KEY_PRESS(%d), ev->keycode); + TRACE_INPUT_END(); + + res = e_keyrouter_event_process(event, type); + + return res; +} + +static Eina_Bool +_e_keyrouter_cb_key_up(void *data, int type, void *event) +{ + Ecore_Event_Key *ev; + Eina_Bool res = ECORE_CALLBACK_PASS_ON; + + EINA_SAFETY_ON_NULL_RETURN_VAL(event, ECORE_CALLBACK_PASS_ON); + + ev = (Ecore_Event_Key *)event; + + TRACE_INPUT_BEGIN(_e_keyrouter_cb_key_down:KEY_RELEASE(%d), ev->keycode); + TRACE_INPUT_END(); + + res = e_keyrouter_event_process(event, type); + + return res; +} + +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", + // 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) ev; + (void) ec; + + /* FIXME: Remove this callback or do something others. + * It was moved to _e_keyrouter_wl_surface_cb_destroy() where it had here. + */ + + return ECORE_CALLBACK_PASS_ON; +} + +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); + E_LIST_HANDLER_APPEND(krt->handlers, ECORE_EVENT_KEY_DOWN, _e_keyrouter_cb_key_down, NULL); + E_LIST_HANDLER_APPEND(krt->handlers, ECORE_EVENT_KEY_UP, _e_keyrouter_cb_key_up, NULL); + + e_info_server_hook_set("keyrouter", _e_keyrouter_info_print, NULL); + e_info_server_hook_set("keygrab", _e_keyrouter_keygrab_print, NULL); +} + +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); + + e_info_server_hook_set("keyrouter", NULL, NULL); + e_info_server_hook_set("keygrab", NULL, NULL); +} + +static Eina_Bool +_e_keyrouter_query_tizen_key_table(void) +{ + E_Keyrouter_Conf_Edd *kconf = krt->conf->conf; + Eina_List *l; + E_Keyrouter_Tizen_HWKey *data; + int res; + struct xkb_rule_names names={0,}; + + /* TODO: Make struct in HardKeys to pointer. + If a key is defined, allocate memory to pointer, + that makes to save unnecessary memory */ + krt->HardKeys = E_NEW(E_Keyrouter_Grabbed_Key, kconf->max_keycode + 1); + EINA_SAFETY_ON_NULL_RETURN_VAL(krt->HardKeys, EINA_FALSE); + + krt->numTizenHWKeys = kconf->num_keycode; + krt->max_tizen_hwkeys = kconf->max_keycode; + + EINA_LIST_FOREACH(kconf->KeyList, l, data) + { + if (!data) continue; + + if (0 > data->keycode || krt->max_tizen_hwkeys < data->keycode) + { + KLWRN("Given keycode(%d) is invalid. It must be bigger than zero, smaller than the maximum value(%d) or equal to it.", data->keycode, kconf->max_keycode); + continue; + } + + KLINF("[jeon] keycode: %d, name: %s, no_priv: %d, repeat: %d\n", data->keycode, data->name, data->no_privcheck, data->repeat); + + krt->HardKeys[data->keycode].keycode = data->keycode; + krt->HardKeys[data->keycode].keyname = (char *)eina_stringshare_add(data->name); + krt->HardKeys[data->keycode].no_privcheck = data->no_privcheck ? EINA_TRUE : EINA_FALSE; + krt->HardKeys[data->keycode].repeat = data->repeat ? EINA_TRUE : EINA_FALSE; + + if (e_comp_wl_input_keymap_cache_file_use_get() == EINA_FALSE) + { + if (krt->HardKeys[data->keycode].repeat == EINA_FALSE) + { + res = xkb_keymap_key_set_repeats(e_comp_wl->xkb.keymap, data->keycode, 0); + if (!res) + { + KLWRN("Failed to set repeat key(%d), value(%d)", data->keycode, 0); + } + } + } + } + + if (e_comp_wl_input_keymap_cache_file_use_get() == EINA_FALSE) + { + KLINF("Server create a new cache file: %s", e_comp_wl_input_keymap_path_get(names)); + res = unlink(e_comp_wl_input_keymap_path_get(names)); + + e_comp_wl_input_keymap_set(NULL, NULL, NULL, NULL, NULL, xkb_context_ref(e_comp_wl->xkb.context), xkb_keymap_ref(e_comp_wl->xkb.keymap)); + } + else + KLINF("Currently cache file is exist. Do not change it."); + + return EINA_TRUE; +} + +static void * +_e_keyrouter_keygrab_list_get(void) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(krt, NULL); + return krt->HardKeys; +} + +static int +_e_keyrouter_max_keycode_get(void) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(krt, 0); + return krt->max_tizen_hwkeys; +} + +E_API int +e_keyrouter_init(void) +{ + E_Keyrouter_Config_Data *kconfig = NULL; + Eina_Bool res = EINA_FALSE; + + TRACE_INPUT_BEGIN(e_keyrouter_init); + + EINA_SAFETY_ON_NULL_GOTO(e_comp, err); + + _keyrouter_log_dom = eina_log_domain_register("e-keyrouter", EINA_COLOR_RED); + EINA_SAFETY_ON_FALSE_GOTO(_keyrouter_log_dom >= 0, err); + eina_log_domain_level_set("e-keyrouter", EINA_LOG_LEVEL_INFO); + + krt = E_NEW(E_Keyrouter, 1); + EINA_SAFETY_ON_NULL_GOTO(krt, err); + + kconfig = E_NEW(E_Keyrouter_Config_Data, 1); + EINA_SAFETY_ON_NULL_GOTO(kconfig, err); + + e_keyrouter_conf_init(kconfig); + EINA_SAFETY_ON_NULL_GOTO(kconfig->conf, err); + krt->conf = kconfig; + krt->pictureoff_disabled = !!kconfig->conf->pictureoff_disabled; + + res = e_keyrouter_wl_init(); + EINA_SAFETY_ON_FALSE_GOTO(res, err); + + /* Get keyname and keycode pair from Tizen Key Layout file */ + res = _e_keyrouter_query_tizen_key_table(); + EINA_SAFETY_ON_FALSE_GOTO(res, err); + + //ecore handler add for power callback registration +// if (!krt->pictureoff_disabled) +// ecore_idle_enterer_add(_e_keyrouter_cb_idler, NULL); + _e_keyrouter_init_handlers(); + + e_keyrouter.keygrab_list_get = _e_keyrouter_keygrab_list_get; + e_keyrouter.max_keycode_get = _e_keyrouter_max_keycode_get; + + TRACE_INPUT_END(); + return EINA_TRUE; + +err: + if (kconfig) + { + e_keyrouter_conf_deinit(kconfig); + E_FREE(kconfig); + } + _e_keyrouter_deinit_handlers(); + e_keyrouter_wl_shutdown(); + eina_log_domain_unregister(_keyrouter_log_dom); + _keyrouter_log_dom = -1; + if (krt) E_FREE(krt); + + TRACE_INPUT_END(); + return EINA_FALSE; +} + +E_API int +e_keyrouter_shutdown(void) +{ + int i; + E_Keyrouter_Config_Data *kconfig = krt->conf; + + e_keyrouter_conf_deinit(kconfig); + E_FREE(kconfig); + + _e_keyrouter_deinit_handlers(); + + for (i = 0; i < krt->max_tizen_hwkeys+1; i++) + { + if (krt->HardKeys[i].keyname) + eina_stringshare_del(krt->HardKeys[i].keyname); + } + E_FREE(krt->HardKeys); + + e_keyrouter_wl_shutdown(); + + E_FREE(krt); + /* TODO: free allocated memory */ + + eina_log_domain_unregister(_keyrouter_log_dom); + + return EINA_TRUE; +} diff --git a/src/bin/e_keyrouter.h b/src/bin/e_keyrouter.h index 66cecb3..fe54f88 100644 --- a/src/bin/e_keyrouter.h +++ b/src/bin/e_keyrouter.h @@ -79,7 +79,6 @@ struct _E_Keyrouter_Grabbed_Key Eina_List *top_ptr; Eina_List *shared_ptr; Eina_List *press_ptr; - E_Keyrouter_Key_List_Node *registered_ptr; Eina_List *pic_off_ptr; }; @@ -87,6 +86,10 @@ E_API E_Keyrouter_Intercept_Hook *e_keyrouter_intercept_hook_add(E_Keyrouter_Int 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); +E_API int e_keyrouter_init(void); +E_API int e_keyrouter_shutdown(void); + + #endif #endif diff --git a/src/bin/e_keyrouter_conf.c b/src/bin/e_keyrouter_conf.c new file mode 100644 index 0000000..4de89da --- /dev/null +++ b/src/bin/e_keyrouter_conf.c @@ -0,0 +1,55 @@ +#include "e_keyrouter_private.h" + +void +e_keyrouter_conf_init(E_Keyrouter_Config_Data *kconfig) +{ + kconfig->conf_hwkeys_edd= E_CONFIG_DD_NEW("E_Keyrouter_Config_Key", + E_Keyrouter_Tizen_HWKey); +#undef T +#undef D +#define T E_Keyrouter_Tizen_HWKey +#define D kconfig->conf_hwkeys_edd + E_CONFIG_VAL(D, T, name, STR); + E_CONFIG_VAL(D, T, keycode, INT); + E_CONFIG_VAL(D, T, no_privcheck, INT); + E_CONFIG_VAL(D, T, repeat, INT); + + kconfig->conf_edd = E_CONFIG_DD_NEW("Keyrouter_Config", E_Keyrouter_Conf_Edd); +#undef T +#undef D +#define T E_Keyrouter_Conf_Edd +#define D kconfig->conf_edd + 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_LIST(D, T, KeyList, kconfig->conf_hwkeys_edd); + +#undef T +#undef D + kconfig->conf = e_config_domain_load("module.keyrouter", kconfig->conf_edd); + + if (!kconfig->conf) + { + KLDBG("Failed to find module.keyrouter config file."); + } +} + +void +e_keyrouter_conf_deinit(E_Keyrouter_Config_Data *kconfig) +{ + E_Keyrouter_Tizen_HWKey *kdata; + + if (kconfig->conf) + { + EINA_LIST_FREE(kconfig->conf->KeyList, kdata) + { + eina_stringshare_del(kdata->name); + free(kdata); + } + free(kconfig->conf); + } + + E_CONFIG_DD_FREE(kconfig->conf_hwkeys_edd); + E_CONFIG_DD_FREE(kconfig->conf_edd); +} + diff --git a/src/bin/e_keyrouter_events.c b/src/bin/e_keyrouter_events.c new file mode 100644 index 0000000..208c59c --- /dev/null +++ b/src/bin/e_keyrouter_events.c @@ -0,0 +1,572 @@ +#include "e_keyrouter_private.h" + +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 Eina_Bool _e_keyrouter_send_key_event(int type, struct wl_resource *surface, struct wl_client *wc, Ecore_Event_Key *ev, Eina_Bool focused, unsigned int mode); + +static Eina_Bool _e_keyrouter_send_key_events_focus(int type, struct wl_resource *surface, Ecore_Event_Key *ev, struct wl_resource **delivered_surface); + +static Eina_Bool _e_keyrouter_is_key_grabbed(int key); +static Eina_Bool _e_keyrouter_check_top_visible_window(E_Client *ec_focus, int arr_idx); + +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_TRUE; + } + + return EINA_FALSE; +} + +static Eina_Bool +_e_keyrouter_event_routed_key_check(Ecore_Event_Key *ev, int type) +{ + if (ev->data) + { + KLDBG("data is exist send to compositor: %p", ev->data); + return EINA_FALSE; + } + + if (ev->modifiers != 0) + { + KLDBG("Modifier key delivered to Focus window : Key %s(%d)", ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keycode); + return EINA_FALSE; + } + + if (krt->max_tizen_hwkeys < ev->keycode) + { + KLWRN("The key(%d) is too larger to process keyrouting: Invalid keycode", ev->keycode); + return EINA_FALSE; + } + + if (!krt->HardKeys[ev->keycode].keycode) return EINA_FALSE; + + return EINA_TRUE; +} + +/* Function for checking the existing grab for a key and sending key event(s) */ +Eina_Bool +e_keyrouter_event_process(void *event, int type) +{ + Eina_Bool res = EINA_FALSE; + Ecore_Event_Key *ev = event; + + KLDBG("[%s] keyname: %s, key: %s, keycode: %d", (type == ECORE_EVENT_KEY_DOWN) ? "KEY_PRESS" : "KEY_RELEASE", ev->keyname, ev->key, ev->keycode); + + e_screensaver_notidle(); + + if (!_e_keyrouter_event_routed_key_check(event, type)) + { + goto finish; + } + + if (!e_keyrouter_intercept_hook_call(E_KEYROUTER_INTERCEPT_HOOK_BEFORE_KEYROUTING, type, ev)) + { + goto finish; + } + + if ((ECORE_EVENT_KEY_UP == type) && (!krt->HardKeys[ev->keycode].press_ptr)) + { + KLDBG("The release key(%d) isn't a processed by keyrouter!", ev->keycode); + goto finish; + } + + //KLDBG("The key(%d) is going to be sent to the proper wl client(s) !", ev->keycode); + KLDBG("[%s] keyname: %s, key: %s, keycode: %d", (type == ECORE_EVENT_KEY_DOWN) ? "KEY_PRESS" : "KEY_RELEASE", ev->keyname, ev->key, ev->keycode); + res = _e_keyrouter_send_key_events(type, ev); + if (res) return EINA_FALSE; + +finish: + res = e_comp_wl_key_process(event, type); + 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) +{ + int pid = 0; + char *pname = NULL, *cmd = NULL; + E_Keyrouter_Key_List_NodePtr key_node_data; + Eina_Bool res = EINA_TRUE, ret = EINA_TRUE; + + /* Deliver release clean up pressed key list */ + EINA_LIST_FREE(krt->HardKeys[ev->keycode].press_ptr, key_node_data) + { + if (key_node_data->status == E_KRT_CSTAT_ALIVE) + { + res = _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, + key_node_data->focused, TIZEN_KEYROUTER_MODE_PRESSED); + + 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("Release Pair : %s(%s:%d)(Focus: %d)(Status: %d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, key_node_data->focused, + key_node_data->status, key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown"); + if(pname) E_FREE(pname); + if(cmd) E_FREE(cmd); + } + else + { + if (key_node_data->focused == EINA_TRUE) + { + res = EINA_FALSE; + if (key_node_data->status == E_KRT_CSTAT_DEAD) + { + ev->data = key_node_data->wc; + } + else + { + ev->data = (void *)0x1; + } + } + KLINF("Release Pair : %s(%s:%d)(Focus: %d)(Status: %d) => wl_surface (%p) wl_client (%p) process is ungrabbed / dead", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, key_node_data->focused, + key_node_data->status, key_node_data->surface, key_node_data->wc); + } + + E_FREE(key_node_data); + if (res == EINA_FALSE) ret = EINA_FALSE; + } + krt->HardKeys[ev->keycode].press_ptr = NULL; + + return ret; +} + +static Eina_Bool +_e_keyrouter_send_key_events_press(int type, Ecore_Event_Key *ev) +{ + unsigned int keycode = ev->keycode; + struct wl_resource *surface_focus = NULL; + E_Client *ec_focus = NULL; + struct wl_resource *delivered_surface = NULL; + Eina_Bool res = EINA_TRUE; + int pid = 0; + char *pname = NULL, *cmd = NULL; + + E_Keyrouter_Key_List_NodePtr key_node_data; + Eina_List *l = NULL; + + 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) + { + res = _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 res; + } + if (!_e_keyrouter_is_key_grabbed(ev->keycode)) + { + return res; + } + + EINA_LIST_FOREACH(krt->HardKeys[keycode].excl_ptr, l, key_node_data) + { + if (key_node_data) + { + res = _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, + key_node_data->focused, TIZEN_KEYROUTER_MODE_EXCLUSIVE); + + 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("EXCLUSIVE : %s(%s:%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, + key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown"); + if(pname) E_FREE(pname); + if(cmd) E_FREE(cmd); + return res; + } + } + + EINA_LIST_FOREACH(krt->HardKeys[keycode].or_excl_ptr, l, key_node_data) + { + if (key_node_data) + { + res = _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, + key_node_data->focused, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE); + + 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("OVERRIDABLE_EXCLUSIVE : %s(%s:%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, + key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown"); + if(pname) E_FREE(pname); + if(cmd) E_FREE(cmd); + + return res; + } + } + + // Top position grab must need a focus surface. + if (surface_focus) + { + EINA_LIST_FOREACH(krt->HardKeys[keycode].top_ptr, l, key_node_data) + { + if (key_node_data) + { + if ((EINA_FALSE == krt->isWindowStackChanged) && (surface_focus == key_node_data->surface)) + { + 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); + + res = _e_keyrouter_send_key_event(type, key_node_data->surface, NULL, ev, key_node_data->focused, + TIZEN_KEYROUTER_MODE_TOPMOST); + KLINF("TOPMOST (TOP_POSITION) : %s (%s:%d) => wl_surface (%p) (pid: %d) (pname: %s)", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, + key_node_data->surface, pid, pname ?: "Unknown"); + + if(pname) E_FREE(pname); + if(cmd) E_FREE(cmd); + return res; + } + krt->isWindowStackChanged = EINA_FALSE; + + if (_e_keyrouter_check_top_visible_window(ec_focus, keycode)) + { + E_Keyrouter_Key_List_NodePtr top_key_node_data = eina_list_data_get(krt->HardKeys[keycode].top_ptr); + pid = e_keyrouter_util_get_pid(top_key_node_data->wc, top_key_node_data->surface); + cmd = e_keyrouter_util_cmd_get_from_pid(pid); + pname = e_keyrouter_util_process_name_get_from_cmd(cmd); + + res = _e_keyrouter_send_key_event(type, top_key_node_data->surface, NULL, ev, top_key_node_data->focused, + TIZEN_KEYROUTER_MODE_TOPMOST); + KLINF("TOPMOST (TOP_POSITION) : %s (%s:%d) => wl_surface (%p) (pid: %d) (pname: %s)", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, + top_key_node_data->surface, pid, pname ?: "Unknown"); + + if(pname) E_FREE(pname); + if(cmd) E_FREE(cmd); + return res; + } + break; + } + } + goto need_shared; + } + + if (krt->HardKeys[keycode].shared_ptr) + { +need_shared: + res = _e_keyrouter_send_key_events_focus(type, surface_focus, ev, &delivered_surface); + if (delivered_surface) + { + res = e_keyrouter_wl_add_surface_destroy_listener(delivered_surface); + if (res != TIZEN_KEYROUTER_ERROR_NONE) + { + KLWRN("Failed to add wl_surface to destroy listener (res: %d)", res); + } + } + EINA_LIST_FOREACH(krt->HardKeys[keycode].shared_ptr, l, key_node_data) + { + if (key_node_data) + { + if (delivered_surface && key_node_data->surface == delivered_surface) + { + // Check for already delivered surface + // do not deliver double events in this case. + continue; + } + else + { + _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("SHARED : %s(%s:%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown"); + if(pname) E_FREE(pname); + if(cmd) E_FREE(cmd); + } + } + } + return res; + } + + return EINA_FALSE; +} + +static Eina_Bool +_e_keyrouter_send_key_events_focus(int type, struct wl_resource *surface_focus, Ecore_Event_Key *ev, struct wl_resource **delivered_surface) +{ + Eina_Bool res = EINA_TRUE; + int pid = 0; + char *pname = NULL, *cmd = NULL; + + if (!e_keyrouter_intercept_hook_call(E_KEYROUTER_INTERCEPT_HOOK_DELIVER_FOCUS, type, ev)) + { + if (ev->data) + { + *delivered_surface = ev->data; + ev->data = wl_resource_get_client(ev->data); + } + return res; + } + + pid = e_keyrouter_util_get_pid(NULL, surface_focus); + cmd = e_keyrouter_util_cmd_get_from_pid(pid); + pname = e_keyrouter_util_process_name_get_from_cmd(cmd); + + res = _e_keyrouter_send_key_event(type, surface_focus, NULL,ev, EINA_TRUE, TIZEN_KEYROUTER_MODE_SHARED); + KLINF("FOCUS DIRECT : %s(%s:%d) => wl_surface (%p) (pid: %d) (pname: %s)", + ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keyname, ev->keycode, surface_focus, pid, pname ?: "Unknown"); + *delivered_surface = surface_focus; + if(pname) E_FREE(pname); + if(cmd) E_FREE(cmd); + return res; +} + +static Eina_Bool +_e_keyrouter_check_top_visible_window(E_Client *ec_focus, int arr_idx) +{ + E_Client *ec_top = NULL; + Eina_List *l = NULL, *l_next = NULL; + E_Keyrouter_Key_List_NodePtr key_node_data = NULL; + + ec_top = e_client_top_get(); + + while (ec_top) + { + if (!ec_top->visible && ec_top == ec_focus) + { + KLDBG("Top e_client (%p) is invisible(%d) but focus client", ec_top, ec_top->visible); + return EINA_FALSE; + } + if (!ec_top->visible) + { + ec_top = e_client_below_get(ec_top); + continue; + } + + /* TODO: Check this client is located inside a display boundary */ + + EINA_LIST_FOREACH_SAFE(krt->HardKeys[arr_idx].top_ptr, l, l_next, key_node_data) + { + if (key_node_data) + { + if (ec_top == wl_resource_get_user_data(key_node_data->surface)) + { + krt->HardKeys[arr_idx].top_ptr = eina_list_promote_list(krt->HardKeys[arr_idx].top_ptr, l); + KLDBG("Move a client(e_client: %p, wl_surface: %p) to first index of list(key: %d)", + ec_top, key_node_data->surface, arr_idx); + return EINA_TRUE; + } + } + } + + if (ec_top == ec_focus) + { + KLDBG("The e_client(%p) is a focus client", ec_top); + return EINA_FALSE; + } + + ec_top = e_client_below_get(ec_top); + } + return EINA_FALSE; +} + +/* Function for sending key event to wl_client(s) */ +static Eina_Bool +_e_keyrouter_send_key_event(int type, struct wl_resource *surface, struct wl_client *wc, Ecore_Event_Key *ev, Eina_Bool focused, unsigned int mode) +{ + struct wl_client *wc_send; + Eina_Bool pressed = EINA_FALSE; + + if (surface == NULL) wc_send = wc; + else wc_send = wl_resource_get_client(surface); + + if (!wc_send) + { + KLWRN("wl_surface: %p or wl_client: %p returns null wayland client", surface, wc); + return EINA_FALSE; + } + + if (ECORE_EVENT_KEY_DOWN == type) + { + pressed = EINA_TRUE; + e_keyrouter_prepend_to_keylist(surface, wc, ev->keycode, TIZEN_KEYROUTER_MODE_PRESSED, focused); + } + + e_keyrouter_wl_key_send(ev, pressed, wc_send, surface, focused); + + return EINA_TRUE; +} + +struct wl_resource * +e_keyrouter_util_get_surface_from_eclient(E_Client *client) +{ + if (!client || !client->comp_data) return NULL; + + return client->comp_data->wl_surface; +} + +int +e_keyrouter_util_get_pid(struct wl_client *client, struct wl_resource *surface) +{ + pid_t pid = 0; + uid_t uid = 0; + gid_t gid = 0; + struct wl_client *cur_client = NULL; + + if (client) cur_client = client; + else if (surface) cur_client = wl_resource_get_client(surface); + EINA_SAFETY_ON_NULL_RETURN_VAL(cur_client, 0); + + wl_client_get_credentials(cur_client, &pid, &uid, &gid); + + return pid; +} + +char * +e_keyrouter_util_cmd_get_from_pid(int pid) +{ + Eina_List *l; + E_Comp_Connected_Client_Info *cdata; + + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL); + + EINA_LIST_FOREACH(e_comp->connected_clients, l, cdata) + { + if (cdata->pid == pid) return strdup(cdata->name); + } + + return NULL; +} + +typedef struct _keycode_map{ + xkb_keysym_t keysym; + xkb_keycode_t keycode; +}keycode_map; + +static void +find_keycode(struct xkb_keymap *keymap, xkb_keycode_t key, void *data) +{ + keycode_map *found_keycodes = (keycode_map *)data; + xkb_keysym_t keysym = found_keycodes->keysym; + int nsyms = 0; + const xkb_keysym_t *syms_out = NULL; + + nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out); + if (nsyms && syms_out) + { + if (*syms_out == keysym) + { + found_keycodes->keycode = key; + } + } +} + +int +_e_keyrouter_keycode_get_from_keysym(struct xkb_keymap *keymap, xkb_keysym_t keysym) +{ + keycode_map found_keycodes = {0,}; + found_keycodes.keysym = keysym; + xkb_keymap_key_for_each(keymap, find_keycode, &found_keycodes); + + return found_keycodes.keycode; +} + +int +e_keyrouter_util_keycode_get_from_string(char * name) +{ + struct xkb_keymap *keymap = NULL; + xkb_keysym_t keysym = 0x0; + int keycode = 0; + + keymap = e_comp_wl->xkb.keymap; + EINA_SAFETY_ON_NULL_GOTO(keymap, finish); + + keysym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS); + EINA_SAFETY_ON_FALSE_GOTO(keysym != XKB_KEY_NoSymbol, finish); + + keycode = _e_keyrouter_keycode_get_from_keysym(keymap, keysym); + + KLDBG("request name: %s, return value: %d", name, keycode); + + return keycode; + +finish: + return 0; +} + +char * +e_keyrouter_util_keyname_get_from_keycode(int keycode) +{ + struct xkb_state *state; + xkb_keysym_t sym = XKB_KEY_NoSymbol; + char name[256] = {0, }; + + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_wl->xkb.state, NULL); + + state = e_comp_wl->xkb.state; + sym = xkb_state_key_get_one_sym(state, keycode); + xkb_keysym_get_name(sym, name, sizeof(name)); + + return strdup(name); +} + +char * +e_keyrouter_util_process_name_get_from_cmd(char *cmd) +{ + int len, i; + char pbuf = '\0'; + char *pname = NULL; + if (cmd) + { + len = strlen(cmd); + for (i = 0; i < len; i++) + { + pbuf = cmd[len - i - 1]; + if (pbuf == '/') + { + pname = &cmd[len - i]; + return strdup(pname); + } + } + } + return NULL; +} + diff --git a/src/bin/e_keyrouter_list.c b/src/bin/e_keyrouter_list.c new file mode 100644 index 0000000..61a6444 --- /dev/null +++ b/src/bin/e_keyrouter_list.c @@ -0,0 +1,543 @@ +#include "e_keyrouter_private.h" + +static int _e_keyrouter_find_duplicated_client(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode); +static Eina_Bool _e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, int key, int mode); +static Eina_List **_e_keyrouter_get_list(int mode, int key); + +/* add a new key grab info to the list */ +int +e_keyrouter_set_keygrab_in_list(struct wl_resource *surface, struct wl_client *client, uint32_t key, uint32_t mode) +{ + int res = TIZEN_KEYROUTER_ERROR_NONE; + + EINA_SAFETY_ON_FALSE_RETURN_VAL + (((mode == TIZEN_KEYROUTER_MODE_EXCLUSIVE) || + (mode == TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE) || + (mode == TIZEN_KEYROUTER_MODE_TOPMOST) || + (mode == TIZEN_KEYROUTER_MODE_SHARED)), + TIZEN_KEYROUTER_ERROR_INVALID_MODE); + + if (mode == TIZEN_KEYROUTER_MODE_EXCLUSIVE) + { + EINA_SAFETY_ON_TRUE_RETURN_VAL + ((krt->HardKeys[key].excl_ptr != NULL), + TIZEN_KEYROUTER_ERROR_GRABBED_ALREADY); + } + + if (mode == TIZEN_KEYROUTER_MODE_TOPMOST) + { + EINA_SAFETY_ON_NULL_RETURN_VAL + (surface, TIZEN_KEYROUTER_ERROR_INVALID_SURFACE); + } + + res = e_keyrouter_prepend_to_keylist(surface, + surface ? NULL : client, + key, + mode, + EINA_FALSE); + + EINA_SAFETY_ON_FALSE_RETURN_VAL(res == TIZEN_KEYROUTER_ERROR_NONE, res); + + return res; +} + +/* Function for checking whether the key has been grabbed already by the same wl_surface or not */ +static int +_e_keyrouter_find_duplicated_client(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode) +{ + Eina_List *keylist_ptr = NULL, *l = NULL; + E_Keyrouter_Key_List_NodePtr key_node_data = NULL; + + switch(mode) + { + case TIZEN_KEYROUTER_MODE_EXCLUSIVE: + return TIZEN_KEYROUTER_ERROR_NONE; + + case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + keylist_ptr = krt->HardKeys[key].or_excl_ptr; + break; + + case TIZEN_KEYROUTER_MODE_TOPMOST: + keylist_ptr = krt->HardKeys[key].top_ptr; + break; + + case TIZEN_KEYROUTER_MODE_SHARED: + keylist_ptr = krt->HardKeys[key].shared_ptr; + break; + + case TIZEN_KEYROUTER_MODE_PRESSED: + keylist_ptr = krt->HardKeys[key].press_ptr; + break; + + case TIZEN_KEYROUTER_MODE_PICTURE_OFF: + keylist_ptr = krt->HardKeys[key].pic_off_ptr; + break; + default: + KLWRN("Unknown key(%d) and grab mode(%d)", key, mode); + return TIZEN_KEYROUTER_ERROR_INVALID_MODE; + } + + EINA_LIST_FOREACH(keylist_ptr, l, key_node_data) + { + if (!key_node_data) continue; + + if (surface) + { + if (key_node_data->surface == surface) + { + KLDBG("The key(%d) is already grabbed same mode(%s) on the same wl_surface %p", + key, e_keyrouter_mode_to_string(mode), surface); + return TIZEN_KEYROUTER_ERROR_GRABBED_ALREADY; + } + } + else + { + if (key_node_data->wc == wc) + { + KLDBG("The key(%d) is already grabbed same mode(%s) on the same wl_client %p", + key, e_keyrouter_mode_to_string(mode), wc); + return TIZEN_KEYROUTER_ERROR_GRABBED_ALREADY; + } + } + } + + return TIZEN_KEYROUTER_ERROR_NONE; +} + +static Eina_Bool +_e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, int key, int mode) +{ + Eina_List **list = NULL; + Eina_List *l = NULL, *l_next = NULL; + E_Keyrouter_Key_List_NodePtr key_node_data = NULL; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(((!surface) && (!wc)), EINA_FALSE); + + list = _e_keyrouter_get_list(mode, key); + EINA_SAFETY_ON_NULL_RETURN_VAL(list, EINA_FALSE); + + EINA_LIST_FOREACH_SAFE(*list, l, l_next, key_node_data) + { + if (!key_node_data) continue; + + if ((surface) && (surface == key_node_data->surface)) return EINA_TRUE; + else if ((wc == key_node_data->wc)) return EINA_TRUE; + } + + return EINA_FALSE; +} + + +/* Function for prepending a new key grab information in the keyrouting list */ +int +e_keyrouter_prepend_to_keylist(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode, Eina_Bool focused) +{ + int res = TIZEN_KEYROUTER_ERROR_NONE; + + res = _e_keyrouter_find_duplicated_client(surface, wc, key, mode); + CHECK_ERR_VAL(res); + + E_Keyrouter_Key_List_NodePtr new_keyptr = E_NEW(E_Keyrouter_Key_List_Node, 1); + + if (!new_keyptr) + { + KLERR("Failled to allocate memory for new_keyptr"); + return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES; + } + + new_keyptr->surface = surface; + new_keyptr->wc = wc; + new_keyptr->focused = focused; + new_keyptr->status = E_KRT_CSTAT_ALIVE; + + switch(mode) + { + case TIZEN_KEYROUTER_MODE_EXCLUSIVE: + krt->HardKeys[key].excl_ptr = eina_list_prepend(krt->HardKeys[key].excl_ptr, new_keyptr); + break; + + case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: + krt->HardKeys[key].or_excl_ptr= eina_list_prepend(krt->HardKeys[key].or_excl_ptr, new_keyptr); + break; + + case TIZEN_KEYROUTER_MODE_TOPMOST: + krt->HardKeys[key].top_ptr = eina_list_prepend(krt->HardKeys[key].top_ptr, new_keyptr); + break; + + case TIZEN_KEYROUTER_MODE_SHARED: + krt->HardKeys[key].shared_ptr= eina_list_prepend(krt->HardKeys[key].shared_ptr, new_keyptr); + break; + + case TIZEN_KEYROUTER_MODE_PRESSED: + krt->HardKeys[key].press_ptr = eina_list_prepend(krt->HardKeys[key].press_ptr, new_keyptr); + break; + + case TIZEN_KEYROUTER_MODE_PICTURE_OFF: + krt->HardKeys[key].pic_off_ptr = eina_list_prepend(krt->HardKeys[key].pic_off_ptr, new_keyptr); + break; + + default: + KLWRN("Unknown key(%d) and grab mode(%d)", key, mode); + E_FREE(new_keyptr); + return TIZEN_KEYROUTER_ERROR_INVALID_MODE; + } + + if (TIZEN_KEYROUTER_MODE_PRESSED != mode) + { + if (surface) + { + e_keyrouter_wl_add_surface_destroy_listener(surface); + /* TODO: if failed add surface_destory_listener, remove keygrabs */ + } + else if (wc) + { + e_keyrouter_wl_add_client_destroy_listener(wc); + /* TODO: if failed add client_destory_listener, remove keygrabs */ + } + } + + return TIZEN_KEYROUTER_ERROR_NONE; +} + +/* remove key grab info from the list */ +void +e_keyrouter_find_and_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode) +{ + Eina_List **list = NULL; + Eina_List *l = NULL, *l_next = NULL; + E_Keyrouter_Key_List_NodePtr key_node_data = NULL; + + list = _e_keyrouter_get_list(mode, key); + EINA_SAFETY_ON_NULL_RETURN(list); + + EINA_LIST_FOREACH_SAFE(*list, l, l_next, key_node_data) + { + if (!key_node_data) continue; + + if (surface) + { + if (surface == key_node_data->surface) + { + if (mode == TIZEN_KEYROUTER_MODE_PRESSED) + { + key_node_data->status = E_KRT_CSTAT_UNGRAB; + } + else + { + *list = eina_list_remove_list(*list, l); + E_FREE(key_node_data); + } + KLDBG("Remove a %s Mode Grabbed key(%d) by surface(%p)", e_keyrouter_mode_to_string(mode), key, surface); + } + } + else if ((wc == key_node_data->wc)) + { + if (mode == TIZEN_KEYROUTER_MODE_PRESSED) + { + key_node_data->status = E_KRT_CSTAT_UNGRAB; + } + else + { + *list = eina_list_remove_list(*list, l); + E_FREE(key_node_data); + } + KLDBG("Remove a %s Mode Grabbed key(%d) by wc(%p)", e_keyrouter_mode_to_string(mode), key, wc); + } + } +} + +void +e_keyrouter_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc) +{ + int i = 0; + Eina_List *l = NULL, *l_next = NULL; + E_Keyrouter_Key_List_NodePtr key_node_data = NULL; + + EINA_SAFETY_ON_TRUE_RETURN(((!surface) && (!wc))); + + for (i = 0; i < krt->max_tizen_hwkeys; i++) + { + if (0 == krt->HardKeys[i].keycode) continue; + + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].excl_ptr, l, l_next, key_node_data) + { + if (!key_node_data) continue; + + if (surface) + { + if (surface == key_node_data->surface) + { + krt->HardKeys[i].excl_ptr = eina_list_remove_list(krt->HardKeys[i].excl_ptr, l); + E_FREE(key_node_data); + KLDBG("Remove a Exclusive Mode Grabbed key(%d) by wl_surface(%p)", i, surface); + } + } + else if ((wc == key_node_data->wc)) + { + krt->HardKeys[i].excl_ptr = eina_list_remove_list(krt->HardKeys[i].excl_ptr, l); + E_FREE(key_node_data); + KLDBG("Remove a Exclusive Mode Grabbed key(%d) by wl_client(%p)", i, wc); + } + } + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].or_excl_ptr, l, l_next, key_node_data) + { + if (!key_node_data) continue; + + if (surface) + { + if (surface == key_node_data->surface) + { + krt->HardKeys[i].or_excl_ptr = eina_list_remove_list(krt->HardKeys[i].or_excl_ptr, l); + E_FREE(key_node_data); + KLDBG("Remove a Overridable_Exclusive Mode Grabbed key(%d) by wl_surface(%p)", i, surface); + } + } + else if ((wc == key_node_data->wc)) + { + krt->HardKeys[i].or_excl_ptr = eina_list_remove_list(krt->HardKeys[i].or_excl_ptr, l); + E_FREE(key_node_data); + KLDBG("Remove a Overridable_Exclusive Mode Grabbed key(%d) by wl_client(%p)", i, wc); + } + } + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].top_ptr, l, l_next, key_node_data) + { + if (!key_node_data) continue; + + if (surface) + { + if (surface == key_node_data->surface) + { + krt->HardKeys[i].top_ptr = eina_list_remove_list(krt->HardKeys[i].top_ptr, l); + E_FREE(key_node_data); + KLDBG("Remove a Topmost Mode Grabbed key(%d) by wl_surface(%p)", i, surface); + } + } + else if ((wc == key_node_data->wc)) + { + krt->HardKeys[i].top_ptr = eina_list_remove_list(krt->HardKeys[i].top_ptr, l); + E_FREE(key_node_data); + KLDBG("Remove a Topmost Mode Grabbed key(%d) by wl_client(%p)", i, wc); + } + } + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].shared_ptr, l, l_next, key_node_data) + { + if (!key_node_data) continue; + + if (surface) + { + if (surface == key_node_data->surface) + { + krt->HardKeys[i].shared_ptr = eina_list_remove_list(krt->HardKeys[i].shared_ptr, l); + E_FREE(key_node_data); + KLDBG("Remove a Shared Mode Grabbed key(%d) by wl_surface(%p)", i, surface); + } + } + else if ((wc == key_node_data->wc)) + { + krt->HardKeys[i].shared_ptr = eina_list_remove_list(krt->HardKeys[i].shared_ptr, l); + E_FREE(key_node_data); + KLDBG("Remove a Shared Mode Grabbed key(%d) by wl_client(%p)", i, wc); + } + } + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].press_ptr, l, l_next, key_node_data) + { + if (!key_node_data) continue; + + if (surface) + { + if (surface == key_node_data->surface) + { + key_node_data->status = E_KRT_CSTAT_DEAD; + KLDBG("Remove a Pressed key(%d) by wl_surface(%p)", i, surface); + key_node_data->wc = wl_resource_get_client(surface); + } + } + else if ((wc == key_node_data->wc)) + { + key_node_data->status = E_KRT_CSTAT_DEAD; + KLDBG("Remove a Pressed key(%d) by wl_client(%p)", i, wc); + } + } + EINA_LIST_FOREACH_SAFE(krt->HardKeys[i].pic_off_ptr, l, l_next, key_node_data) + { + if (!key_node_data) continue; + if (surface) + { + if (surface == key_node_data->surface) + { + krt->HardKeys[i].pic_off_ptr = eina_list_remove_list(krt->HardKeys[i].pic_off_ptr, l); + E_FREE(key_node_data); + } + } + else if ( wc == key_node_data->wc) + { + krt->HardKeys[i].pic_off_ptr = eina_list_remove_list(krt->HardKeys[i].pic_off_ptr, l); + E_FREE(key_node_data); + } + } + } +} + +int +e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key) +{ + int mode = TIZEN_KEYROUTER_MODE_NONE; + Eina_Bool found = EINA_FALSE; + + mode = TIZEN_KEYROUTER_MODE_EXCLUSIVE; + found = _e_keyrouter_find_key_in_list(surface, wc, key, mode); + if (found) goto finish; + + mode = TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE; + found = _e_keyrouter_find_key_in_list(surface, wc, key, mode); + if (found) goto finish; + + mode = TIZEN_KEYROUTER_MODE_TOPMOST; + found = _e_keyrouter_find_key_in_list(surface, wc, key, mode); + if (found) goto finish; + + mode = TIZEN_KEYROUTER_MODE_SHARED; + found = _e_keyrouter_find_key_in_list(surface, wc, key, mode); + if (found) goto finish; + + KLDBG("%d key is not grabbed by (wl_surface: %p, wl_client: %p)", key, surface, wc); + return TIZEN_KEYROUTER_MODE_NONE; + +finish: + KLDBG("Find %d key grabbed by (wl_surface: %p, wl_client: %p) in %s mode", + key, surface, wc, e_keyrouter_mode_to_string(mode)); + return mode; +} + +const char * +e_keyrouter_mode_to_string(uint32_t mode) +{ + const char *str = NULL; + + switch (mode) + { + case TIZEN_KEYROUTER_MODE_EXCLUSIVE: str = "Exclusive"; break; + case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: str = "Overridable_Exclusive"; break; + case TIZEN_KEYROUTER_MODE_TOPMOST: str = "Topmost"; break; + case TIZEN_KEYROUTER_MODE_SHARED: str = "Shared"; break; + case TIZEN_KEYROUTER_MODE_PRESSED: str = "Pressed"; break; + default: str = "UnknownMode"; break; + } + + return str; +} + +static Eina_List ** +_e_keyrouter_get_list(int mode, int key) +{ + Eina_List **list = NULL; + + switch (mode) + { + case TIZEN_KEYROUTER_MODE_EXCLUSIVE: list = &krt->HardKeys[key].excl_ptr; break; + case TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: list = &krt->HardKeys[key].or_excl_ptr; break; + case TIZEN_KEYROUTER_MODE_TOPMOST: list = &krt->HardKeys[key].top_ptr; break; + case TIZEN_KEYROUTER_MODE_SHARED: list = &krt->HardKeys[key].shared_ptr; break; + case TIZEN_KEYROUTER_MODE_PRESSED: list = &krt->HardKeys[key].press_ptr; break; + default: break; + } + + return list; +} + + +int +e_keyrouter_keygrab_set(struct wl_client *client, struct wl_resource *surface, int key, int mode) +{ + int res=0; + +#ifdef HAVE_CYNARA + if (EINA_FALSE == e_keyrouter_wl_util_do_privilege_check(client, mode, key)) + { + KLINF("No permission for %d grab mode ! (key=%d)", mode, key); + return TIZEN_KEYROUTER_ERROR_NO_PERMISSION; + } +#endif + + if (!surface) + { + /* Regarding topmost mode, a client must request to grab a key with a valid surface. */ + if (mode == TIZEN_KEYROUTER_MODE_TOPMOST) + { + KLWRN("Invalid surface for %d grab mode ! (key=%d)", mode, key); + + return TIZEN_KEYROUTER_ERROR_INVALID_SURFACE; + } + } + + /* Check the given key range */ + if (krt->max_tizen_hwkeys < key) + { + KLWRN("Invalid range of key ! (keycode:%d)", key); + return TIZEN_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) + { + KLWRN("Invalid key ! Disabled to grab ! (keycode:%d)", key); + return TIZEN_KEYROUTER_ERROR_INVALID_KEY; + } + + /* Check whether the request key can be grabbed or not */ + res = e_keyrouter_set_keygrab_in_list(surface, client, key, mode); + + return res; +} + +int +e_keyrouter_keygrab_unset(struct wl_client *client, struct wl_resource *surface, int key) +{ + /* Ungrab top position grabs first. This grab mode do not need privilege */ + if (!surface) + e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_TOPMOST); + else + e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_TOPMOST); + +#ifdef HAVE_CYNARA + if (EINA_FALSE == e_keyrouter_wl_util_do_privilege_check(client, TIZEN_KEYROUTER_MODE_NONE, key)) + { + goto finish; + } +#endif + + if (!surface) + { + /* EXCLUSIVE grab */ + e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_EXCLUSIVE); + + /* OVERRIDABLE_EXCLUSIVE grab */ + e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE); + + /* SHARED grab */ + e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_SHARED); + + /* Press List */ + e_keyrouter_find_and_remove_client_from_list(NULL, client, key, TIZEN_KEYROUTER_MODE_PRESSED); + } + else + { + /* EXCLUSIVE grab */ + e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_EXCLUSIVE); + + /* OVERRIDABLE_EXCLUSIVE grab */ + e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE); + + /* SHARED grab */ + e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_SHARED); + + /* Press List */ + e_keyrouter_find_and_remove_client_from_list(surface, client, key, TIZEN_KEYROUTER_MODE_PRESSED); + } + +finish: + e_keyrouter_keycancel_send(client, surface, key); + + return TIZEN_KEYROUTER_ERROR_NONE; +} diff --git a/src/bin/e_keyrouter_private.h b/src/bin/e_keyrouter_private.h new file mode 100644 index 0000000..9de7dbd --- /dev/null +++ b/src/bin/e_keyrouter_private.h @@ -0,0 +1,119 @@ +#include "e.h" +#include "e_keyrouter.h" +#ifdef HAVE_CYNARA +#include +#include +#include +#include +#endif +#include + +#define CHECK_ERR(val) if (TIZEN_KEYROUTER_ERROR_NONE != val) return; +#define CHECK_ERR_VAL(val) if (TIZEN_KEYROUTER_ERROR_NONE != val) return val; +#define CHECK_NULL(val) if (!val) return; +#define CHECK_NULL_VAL(val) if (!val) return val; + +#define KLERR(msg, ARG...) ERR(msg, ##ARG) +#define KLWRN(msg, ARG...) WRN(msg, ##ARG) +#define KLINF(msg, ARG...) INF(msg, ##ARG) +#define KLDBG(msg, ARG...) DBG(msg, ##ARG) + +typedef struct _E_Keyrouter E_Keyrouter; +typedef struct _E_Keyrouter* E_KeyrouterPtr; +typedef struct _E_Keyrouter_Grab_Request E_Keyrouter_Grab_Request; +typedef struct _E_Keyrouter_Ungrab_Request E_Keyrouter_Ungrab_Request; + +typedef struct _E_Keyrouter_Conf_Edd E_Keyrouter_Conf_Edd; +typedef struct _E_Keyrouter_Config_Data E_Keyrouter_Config_Data; + +#define TIZEN_KEYROUTER_MODE_PRESSED TIZEN_KEYROUTER_MODE_REGISTERED+1 +#define TIZEN_KEYROUTER_MODE_PICTURE_OFF TIZEN_KEYROUTER_MODE_REGISTERED+2 + +typedef unsigned long Time; + +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 +}; + +struct _E_Keyrouter_Config_Data +{ + E_Config_DD *conf_edd; + E_Config_DD *conf_hwkeys_edd; + E_Keyrouter_Conf_Edd *conf; +}; + +struct _E_Keyrouter +{ + struct wl_global *global; + Ecore_Event_Filter *ef_handler; + Eina_List *handlers; + Eina_List *resources; + + E_Keyrouter_Config_Data *conf; + + E_Keyrouter_Grabbed_Key *HardKeys; + Eina_List *grab_surface_list; + Eina_List *grab_client_list; + + Eina_Bool isWindowStackChanged; + int numTizenHWKeys; + int max_tizen_hwkeys; +#ifdef HAVE_CYNARA + cynara *p_cynara; +#endif + int isPictureOffEnabled; + Eina_Bool pictureoff_disabled; +}; + +struct _E_Keyrouter_Grab_Request { + int key; + int mode; + int err; +}; + +struct _E_Keyrouter_Ungrab_Request { + int key; + int err; +}; + +int e_keyrouter_set_keygrab_in_list(struct wl_resource *surface, struct wl_client *client, uint32_t key, uint32_t mode); +int e_keyrouter_prepend_to_keylist(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode, Eina_Bool focused); +void e_keyrouter_find_and_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key, uint32_t mode); +void e_keyrouter_remove_client_from_list(struct wl_resource *surface, struct wl_client *wc); +int e_keyrouter_find_key_in_list(struct wl_resource *surface, struct wl_client *wc, uint32_t key); + +Eina_Bool e_keyrouter_process_key_event(void *event, int type); + +struct wl_resource *e_keyrouter_util_get_surface_from_eclient(E_Client *client); +int e_keyrouter_util_get_pid(struct wl_client *client, struct wl_resource *surface); +char *e_keyrouter_util_cmd_get_from_pid(int pid); +int e_keyrouter_util_keycode_get_from_string(char *name); +char *e_keyrouter_util_keyname_get_from_keycode(int keycode); +char *e_keyrouter_util_process_name_get_from_cmd(char *cmd); +const char *e_keyrouter_mode_to_string(uint32_t mode); + +void e_keyrouter_conf_init(E_Keyrouter_Config_Data *kconfig); +void e_keyrouter_conf_deinit(E_Keyrouter_Config_Data *kconfig); +int e_keyrouter_cb_picture_off(const int option, void *data); + +Eina_Bool e_keyrouter_wl_init(void); +void e_keyrouter_wl_shutdown(void); +int e_keyrouter_wl_add_client_destroy_listener(struct wl_client *client); +int e_keyrouter_wl_add_surface_destroy_listener(struct wl_resource *surface); +#ifdef HAVE_CYNARA +Eina_Bool e_keyrouter_wl_util_do_privilege_check(struct wl_client *client, uint32_t mode, uint32_t keycode); +#endif + +int e_keyrouter_keygrab_set(struct wl_client *client, struct wl_resource *surface, int key, int mode); +int e_keyrouter_keygrab_unset(struct wl_client *client, struct wl_resource *surface, int key); + +Eina_Bool e_keyrouter_event_process(void *event, int type); + +Eina_Bool e_keyrouter_wl_key_send(Ecore_Event_Key *ev, Eina_Bool pressed, struct wl_client *client, struct wl_resource *surface, Eina_Bool focused); +void e_keyrouter_keycancel_send(struct wl_client *client, struct wl_resource *surface, unsigned int key); diff --git a/src/bin/e_keyrouter_wl.c b/src/bin/e_keyrouter_wl.c new file mode 100644 index 0000000..40cb6d0 --- /dev/null +++ b/src/bin/e_keyrouter_wl.c @@ -0,0 +1,625 @@ +#include "e_keyrouter_private.h" + +static void +_e_keyrouter_wl_key_send(Ecore_Event_Key *ev, enum wl_keyboard_key_state state, Eina_List *key_list, Eina_Bool focused, struct wl_client *client, struct wl_resource *surface) +{ + struct wl_resource *res; + Eina_List *l; + uint32_t serial, keycode; + struct wl_client *wc; + E_Comp_Config *comp_conf = NULL; + + keycode = (ev->keycode - 8); + + serial = wl_display_next_serial(e_comp_wl->wl.disp); + + comp_conf = e_comp_config_get(); + + EINA_LIST_FOREACH(key_list, l, res) + { + wc = wl_resource_get_client(res); + if (!focused && wc != client) continue; + TRACE_INPUT_BEGIN(_e_comp_wl_key_send); +// _e_comp_wl_send_event_device(client, ev->timestamp, ev->dev, serial); + + if (comp_conf && comp_conf->input_log_enable) + INF("[Server] Routed Key %s (time: %d)\n", (state ? "Down" : "Up"), ev->timestamp); + + wl_keyboard_send_key(res, serial, ev->timestamp, + keycode, state); + TRACE_INPUT_END(); + } +} + +Eina_Bool +e_keyrouter_wl_key_send(Ecore_Event_Key *ev, Eina_Bool pressed, struct wl_client *client, struct wl_resource *surface, Eina_Bool focused) +{ + E_Client *ec = NULL; + struct wl_client *wc = NULL; + uint32_t keycode; + enum wl_keyboard_key_state state; + + if ((e_comp->comp_type != E_PIXMAP_TYPE_WL) || (ev->window != e_comp->ee_win)) + { + return EINA_FALSE; + } + + keycode = (ev->keycode - 8); + if (!(e_comp_wl = e_comp->wl_comp_data)) + { + return EINA_FALSE; + } + +#ifndef E_RELEASE_BUILD + if ((ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) && + ((ev->modifiers & ECORE_EVENT_MODIFIER_ALT) || + (ev->modifiers & ECORE_EVENT_MODIFIER_ALTGR)) && + eina_streq(ev->key, "BackSpace")) + { + exit(0); + } +#endif + + if (pressed) state = WL_KEYBOARD_KEY_STATE_PRESSED; + else state = WL_KEYBOARD_KEY_STATE_RELEASED; + + if (!focused) + { + _e_keyrouter_wl_key_send(ev, state, e_comp_wl->kbd.resources, EINA_FALSE, client, surface); + return EINA_FALSE; + } + + if ((!e_client_action_get()) && (!e_comp->input_key_grabs)) + { + ec = e_client_focused_get(); + if (ec && ec->comp_data && ec->comp_data->surface) + { + if (e_comp_wl->kbd.focused) + { + wc = wl_resource_get_client(ec->comp_data->surface); + _e_keyrouter_wl_key_send(ev, state, e_comp_wl->kbd.focused, EINA_TRUE, wc, surface); + } + + /* update modifier state */ + e_comp_wl_input_keyboard_state_update(keycode, pressed); + } + } + return !!ec; +} + +void +e_keyrouter_keycancel_send(struct wl_client *client, struct wl_resource *surface, unsigned int key) +{ + Eina_List *l; + struct wl_resource *resource = NULL; + struct wl_client *wc = NULL; + E_Keyrouter_Key_List_NodePtr data; + + if (surface) wc = wl_resource_get_client(surface); + else wc = client; + + EINA_SAFETY_ON_NULL_RETURN(wc); + + EINA_LIST_FOREACH(krt->HardKeys[key].press_ptr, l, data) + { + if (surface) + { + if (surface == data->surface) + { + EINA_LIST_FOREACH(krt->resources, l, resource) + { + if (wl_resource_get_client(resource) != wc) continue; + + tizen_keyrouter_send_key_cancel(resource, key-8); + } + } + } + else if (client == data->wc) + { + EINA_LIST_FOREACH(krt->resources, l, resource) + { + if (wl_resource_get_client(resource) != wc) continue; + + tizen_keyrouter_send_key_cancel(resource, key-8); + } + } + } +} + +static int +_e_keyrouter_wl_array_length(const struct wl_array *array) +{ + int *data = NULL; + int count = 0; + + wl_array_for_each(data, array) + { + count++; + } + + return count; +} + +/* tizen_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) +{ + int res = 0; + + TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_set); + + res = e_keyrouter_keygrab_set(client, surface, key, mode); + + TRACE_INPUT_END(); + + if (res == TIZEN_KEYROUTER_ERROR_NONE) + { + if (mode == TIZEN_KEYROUTER_MODE_EXCLUSIVE) + { + KLINF("Success to %d key %s grab request (wl_client: %p, wl_surface: %p, pid: %d)", key, e_keyrouter_mode_to_string(mode), + client, surface, e_keyrouter_util_get_pid(client, surface)); + } + else + { + KLDBG("Success to %d key %s grab request (wl_client: %p, wl_surface: %p, pid: %d)", key, e_keyrouter_mode_to_string(mode), + client, surface, e_keyrouter_util_get_pid(client, surface)); + } + } + else + KLINF("Failed to %d key %s grab request (wl_client: %p, wl_surface: %p, pid: %d): res: %d", key, e_keyrouter_mode_to_string(mode), + client, surface, e_keyrouter_util_get_pid(client, surface), res); + tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, res); +} + +/* tizen_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) +{ + int res = 0; + + TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_unset); + + res = e_keyrouter_keygrab_unset(client, surface, key); + + TRACE_INPUT_END(); + + if (res == TIZEN_KEYROUTER_ERROR_NONE) + KLDBG("Success to %d key ungrab request (wl_client: %p, wl_surface: %p, pid: %d)", key, client, surface, + e_keyrouter_util_get_pid(client, surface)); + else + KLINF("Failed to %d key ungrab request (wl_client: %p, wl_surface: %p, pid: %d): res: %d", key, client, surface, + e_keyrouter_util_get_pid(client, surface), res); + tizen_keyrouter_send_keygrab_notify(resource, surface, key, TIZEN_KEYROUTER_MODE_NONE, res); +} + +/* tizen_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; + int mode = TIZEN_KEYROUTER_MODE_NONE; + + TRACE_INPUT_BEGIN(_e_keyrouter_cb_get_keygrab_status); + mode = e_keyrouter_find_key_in_list(surface, client, key); + + TRACE_INPUT_END(); + tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, TIZEN_KEYROUTER_ERROR_NONE); +} + +static void +_e_keyrouter_cb_keygrab_set_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, struct wl_array *grab_list) +{ + E_Keyrouter_Grab_Request *grab_request = NULL; + int res = TIZEN_KEYROUTER_ERROR_NONE; + int array_len = 0; + + TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_set_list); + + array_len = _e_keyrouter_wl_array_length(grab_list); + + if (0 != (array_len % 3)) + { + /* FIX ME: Which way is effectively to notify invalid pair to client */ + KLWRN("Invalid keycode and grab mode pair. Check arguments in a list"); + TRACE_INPUT_END(); + tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL); + return; + } + + wl_array_for_each(grab_request, grab_list) + { + res = e_keyrouter_keygrab_set(client, surface, grab_request->key, grab_request->mode); + grab_request->err = res; + if (res == TIZEN_KEYROUTER_ERROR_NONE) + KLDBG("Success to %d key %s grab using list(wl_client: %p, wl_surface: %p, pid: %d)", + grab_request->key, e_keyrouter_mode_to_string(grab_request->mode), + client, surface, e_keyrouter_util_get_pid(client, surface)); + else + KLINF("Failed to %d key %s grab using list(wl_client: %p, wl_surface: %p, pid: %d): res: %d", + grab_request->key, e_keyrouter_mode_to_string(grab_request->mode), + client, surface, e_keyrouter_util_get_pid(client, surface), grab_request->err); + } + + + TRACE_INPUT_END(); + tizen_keyrouter_send_keygrab_notify_list(resource, surface, grab_list); +} + +static void +_e_keyrouter_cb_keygrab_unset_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, struct wl_array *ungrab_list) +{ + E_Keyrouter_Ungrab_Request *ungrab_request = NULL; + int res = TIZEN_KEYROUTER_ERROR_NONE; + int array_len = 0; + + TRACE_INPUT_BEGIN(_e_keyrouter_cb_keygrab_unset_list); + + array_len = _e_keyrouter_wl_array_length(ungrab_list); + + if (0 != (array_len % 2)) + { + /* FIX ME: Which way is effectively to notify invalid pair to client */ + KLWRN("Invalid keycode and error pair. Check arguments in a list"); + TRACE_INPUT_END(); + tizen_keyrouter_send_keygrab_notify_list(resource, surface, ungrab_list); + return; + } + + wl_array_for_each(ungrab_request, ungrab_list) + { + res = e_keyrouter_keygrab_unset(client, surface, ungrab_request->key); + ungrab_request->err = res; + if (res == TIZEN_KEYROUTER_ERROR_NONE) + KLDBG("Success to ungrab using list: %d key (wl_client: %p, wl_surface: %p, pid: %d)", + ungrab_request->key, client, surface, e_keyrouter_util_get_pid(client, surface)); + else + KLINF("Failed to ungrab using list: %d key (wl_client: %p, wl_surface: %p, pid: %d): res: %d", + ungrab_request->key, client, surface, e_keyrouter_util_get_pid(client, surface), ungrab_request->err); + } + + TRACE_INPUT_END(); + tizen_keyrouter_send_keygrab_notify_list(resource, surface, ungrab_list); +} + +static void +_e_keyrouter_cb_keygrab_get_list(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface) +{ + (void) client; + + tizen_keyrouter_send_getgrab_notify_list(resource, surface, NULL); +} + +static void +_e_keyrouter_cb_set_register_none_key(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t data) +{ + (void) client; + (void) data; + + tizen_keyrouter_send_set_register_none_key_notify(resource, NULL, 0); +} + +static void +_e_keyrouter_cb_get_keyregister_status(struct wl_client *client, struct wl_resource *resource, uint32_t key) +{ + (void) client; + (void) key; + + tizen_keyrouter_send_keyregister_notify(resource, (int)EINA_FALSE); +} + +static void +_e_keyrouter_cb_set_input_config(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *surface EINA_UNUSED, uint32_t config_mode EINA_UNUSED, uint32_t value EINA_UNUSED) +{ + tizen_keyrouter_send_set_input_config_notify(resource, 0); +} + +static void +_e_keyrouter_cb_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct tizen_keyrouter_interface _e_keyrouter_implementation = { + _e_keyrouter_cb_keygrab_set, + _e_keyrouter_cb_keygrab_unset, + _e_keyrouter_cb_get_keygrab_status, + _e_keyrouter_cb_keygrab_set_list, + _e_keyrouter_cb_keygrab_unset_list, + _e_keyrouter_cb_keygrab_get_list, + _e_keyrouter_cb_set_register_none_key, + _e_keyrouter_cb_get_keyregister_status, + _e_keyrouter_cb_set_input_config, + _e_keyrouter_cb_destroy, +}; + +static void +_e_keyrouter_cb_unbind(struct wl_resource *resource) +{ + krt->resources = eina_list_remove(krt->resources, resource); +} + +/* tizen_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, &tizen_keyrouter_interface, version, id); + + KLDBG("wl_resource_create(...,&tizen_keyrouter_interface,...)"); + + if (!resource) + { + KLERR("Failed to create resource ! (version :%d, id:%d)", version, id); + wl_client_post_no_memory(client); + return; + } + + krt->resources = eina_list_append(krt->resources, resource); + + wl_resource_set_implementation(resource, &_e_keyrouter_implementation, krt_instance, _e_keyrouter_cb_unbind); +} + +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", l, client); + e_keyrouter_remove_client_from_list(NULL, client); + + wl_list_remove(&l->link); + E_FREE(l); + + krt->grab_client_list = eina_list_remove(krt->grab_client_list, client); +} + +static void +_e_keyrouter_wl_surface_cb_destroy(struct wl_listener *l, void *data) +{ + struct wl_resource *surface = (struct wl_resource *)data; + + KLDBG("Listener(%p) called: surface: %p is died", l, surface); + e_keyrouter_remove_client_from_list(surface, NULL); + + wl_list_remove(&l->link); + E_FREE(l); + + krt->grab_surface_list = eina_list_remove(krt->grab_surface_list, surface); +} + +int +e_keyrouter_wl_add_client_destroy_listener(struct wl_client *client) +{ + struct wl_listener *destroy_listener = NULL; + Eina_List *l; + struct wl_client *wc_data; + + if (!client) return TIZEN_KEYROUTER_ERROR_NONE; + + EINA_LIST_FOREACH(krt->grab_client_list, l, wc_data) + { + if (wc_data) + { + if (wc_data == client) + { + return TIZEN_KEYROUTER_ERROR_NONE; + } + } + } + + destroy_listener = E_NEW(struct wl_listener, 1); + + if (!destroy_listener) + { + KLERR("Failed to allocate memory for wl_client destroy listener !"); + return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES; + } + + destroy_listener->notify = _e_keyrouter_wl_client_cb_destroy; + wl_client_add_destroy_listener(client, destroy_listener); + krt->grab_client_list = eina_list_append(krt->grab_client_list, client); + + return TIZEN_KEYROUTER_ERROR_NONE; +} + +/* Function for registering wl_surface destroy listener */ +int +e_keyrouter_wl_add_surface_destroy_listener(struct wl_resource *surface) +{ + struct wl_listener *destroy_listener = NULL; + Eina_List *l; + struct wl_resource *surface_data; + + if (!surface) return TIZEN_KEYROUTER_ERROR_NONE; + + EINA_LIST_FOREACH(krt->grab_surface_list, l, surface_data) + { + if (surface_data) + { + if (surface_data == surface) + { + return TIZEN_KEYROUTER_ERROR_NONE; + } + } + } + + destroy_listener = E_NEW(struct wl_listener, 1); + + if (!destroy_listener) + { + KLERR("Failed to allocate memory for wl_surface destroy listener !"); + return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES; + } + + destroy_listener->notify = _e_keyrouter_wl_surface_cb_destroy; + wl_resource_add_destroy_listener(surface, destroy_listener); + krt->grab_surface_list = eina_list_append(krt->grab_surface_list, surface); + + return TIZEN_KEYROUTER_ERROR_NONE; +} + +#ifdef HAVE_CYNARA +static void +_e_keyrouter_wl_util_cynara_log(const char *func_name, int err) +{ +#define CYNARA_BUFSIZE 128 + char buf[CYNARA_BUFSIZE] = "\0"; + int ret; + + ret = cynara_strerror(err, buf, CYNARA_BUFSIZE); + if (ret != CYNARA_API_SUCCESS) + { + KLWRN("Failed to cynara_strerror: %d (error log about %s: %d)", ret, func_name, err); + return; + } + KLWRN("%s is failed: %s", func_name, buf); +} + +Eina_Bool +e_keyrouter_wl_util_do_privilege_check(struct wl_client *client, uint32_t mode, uint32_t keycode) +{ + int ret, retry_cnt=0, len=0; + char *clientSmack=NULL, *client_session=NULL, uid2[16]={0, }; + Eina_Bool res = EINA_FALSE; + Eina_List *l; + struct wl_client *wc_data; + static Eina_Bool retried = EINA_FALSE; + pid_t pid = 0; + uid_t uid = 0; + gid_t gid = 0; + + /* Top position grab is always allowed. This mode do not need privilege.*/ + if (mode == TIZEN_KEYROUTER_MODE_TOPMOST) + return EINA_TRUE; + + if (krt->HardKeys[keycode].no_privcheck == EINA_TRUE) + return EINA_TRUE; + + if (!client) return EINA_FALSE; + + /* If initialize cynara is failed, allow keygrabs regardless of the previlege permition. */ + if (krt->p_cynara == NULL) + { + if (retried == EINA_FALSE) + { + retried = EINA_TRUE; + for(retry_cnt = 0; retry_cnt < 5; retry_cnt++) + { + KLDBG("Retry cynara initialize: %d", retry_cnt+1); + ret = cynara_initialize(&krt->p_cynara, NULL); + if (EINA_UNLIKELY(CYNARA_API_SUCCESS != ret)) + { + _e_keyrouter_wl_util_cynara_log("cynara_initialize", ret); + krt->p_cynara = NULL; + } + else + { + KLDBG("Success cynara initialize to try %d times", retry_cnt+1); + break; + } + } + } + return EINA_TRUE; + } + + EINA_LIST_FOREACH(krt->grab_client_list, l, wc_data) + { + if (wc_data == client) + { + res = EINA_TRUE; + goto finish; + } + } + + wl_client_get_credentials(client, &pid, &uid, &gid); + + len = smack_new_label_from_process((int)pid, &clientSmack); + if (len <= 0) goto finish; + + snprintf(uid2, 15, "%d", (int)uid); + client_session = cynara_session_from_pid(pid); + + ret = cynara_check(krt->p_cynara, clientSmack, client_session, uid2, "http://tizen.org/privilege/keygrab"); + if (CYNARA_API_ACCESS_ALLOWED == ret) + { + res = EINA_TRUE; + } + else + { + KLINF("Fail to check cynara, error : %d (pid : %d)", ret, pid); + } +finish: + if (client_session) E_FREE(client_session); + if (clientSmack) E_FREE(clientSmack); + + return res; +} +#endif + +Eina_Bool +e_keyrouter_wl_init(void) +{ + int ret; + + EINA_SAFETY_ON_NULL_RETURN_VAL(krt, EINA_FALSE); + + krt->global = wl_global_create(e_comp_wl->wl.disp, &tizen_keyrouter_interface, 1, krt, _e_keyrouter_cb_bind); + EINA_SAFETY_ON_NULL_RETURN_VAL(krt->global, EINA_FALSE); + +#ifdef HAVE_CYNARA + ret = cynara_initialize(&krt->p_cynara, NULL); + if (EINA_UNLIKELY(CYNARA_API_SUCCESS != ret)) + { + _e_keyrouter_wl_util_cynara_log("cynara_initialize", ret); + krt->p_cynara = NULL; + } +#endif + + return EINA_TRUE; +} + +void +e_keyrouter_wl_shutdown(void) +{ + Eina_List *l, *l_next; + struct wl_resource *resource; + struct wl_client *client; + struct wl_listener *destroy_listener; + + EINA_SAFETY_ON_NULL_RETURN(krt); + + EINA_LIST_FOREACH_SAFE(krt->grab_client_list, l, l_next, client) + { + destroy_listener = wl_client_get_destroy_listener(client, _e_keyrouter_wl_client_cb_destroy); + if (destroy_listener) + { + wl_list_remove(&destroy_listener->link); + E_FREE(destroy_listener); + } + krt->grab_client_list = eina_list_remove(krt->grab_client_list, client); + } + EINA_LIST_FOREACH_SAFE(krt->grab_surface_list, l, l_next, resource) + { + destroy_listener = wl_resource_get_destroy_listener(resource, _e_keyrouter_wl_surface_cb_destroy); + if (destroy_listener) + { + wl_list_remove(&destroy_listener->link); + E_FREE(destroy_listener); + } + krt->grab_surface_list = eina_list_remove(krt->grab_surface_list, client); + } + + EINA_LIST_FREE(krt->resources, resource) + wl_resource_destroy(resource); + + if (krt->global) wl_global_destroy(krt->global); + +#ifdef HAVE_CYNARA + if (krt->p_cynara) cynara_finish(krt->p_cynara); +#endif +} diff --git a/src/bin/e_main.c b/src/bin/e_main.c index 56f91e0..a8f95a6 100644 --- a/src/bin/e_main.c +++ b/src/bin/e_main.c @@ -677,6 +677,15 @@ main(int argc, char **argv) _e_main_shutdown_push(_e_main_screens_shutdown); TRACE_DS_END(); + TSB("E_Keyrouter Init"); + if (!e_keyrouter_init()) + { + e_error_message_show(_("Enlightenment cannot set up its keyrouting system.\n")); + goto failed; + } + TSE("E_Keyrouter Init Done"); + _e_main_shutdown_push(e_keyrouter_shutdown); + if (e_config->eom_enable) { TSB("Eom Init");