E_API E_Keyrouter_Info e_keyrouter;
E_KeyrouterPtr krt;
+E_API int E_KEYROUTER_EVENT_KEY_LONG = 0;
+E_API int E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS = 0;
+E_API int E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE = 0;
+
E_API E_Keyrouter_Intercept_Hook *
e_keyrouter_intercept_hook_add(E_Keyrouter_Intercept_Hook_Point hookpoint, E_Keyrouter_Intercept_Hook_Cb func, const void *data)
{
return krt->max_tizen_hwkeys;
}
+E_API int
+e_keyrouter_longkey_add(int keycode, double time)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(krt, EINA_FALSE);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(keycode <= krt->max_tizen_hwkeys, EINA_FALSE);
+
+ if (krt->HardKeys[keycode].longkey.enabled == EINA_TRUE)
+ {
+ KLWRN("The %d keycode'long press is already enabled by time: %lf\n", keycode, krt->HardKeys[keycode].longkey.time);
+ return EINA_FALSE;
+ }
+
+ krt->HardKeys[keycode].longkey.enabled = EINA_TRUE;
+ krt->HardKeys[keycode].longkey.time = time;
+
+ KLINF("To enable %d key's longkey function. (time: %lf)\n", keycode, time);
+
+ return EINA_TRUE;
+}
+
+E_API void
+e_keyrouter_longkey_del(int keycode)
+{
+ /* FIXME: If del request is came, during checking long press,
+ How control this behavior?
+ Cancel current long press or not
+ */
+
+ krt->HardKeys[keycode].longkey.enabled = EINA_FALSE;
+ krt->HardKeys[keycode].longkey.time = 0.0;
+
+ KLINF("To disable %d key's longkey function.\n", keycode);
+}
+
+E_API int
+e_keyrouter_composition_key_add(int *keys, int count)
+{
+ Eina_List *l;
+ int *data, *data2;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(krt, EINA_FALSE);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(keys[0] <= krt->max_tizen_hwkeys, EINA_FALSE);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(keys[1] <= krt->max_tizen_hwkeys, EINA_FALSE);
+
+ if (count != 2)
+ {
+ KLWRN("Currently only two key composition is allowed. (%d)\n", count);
+ return EINA_FALSE;
+ }
+
+ EINA_LIST_FOREACH(krt->HardKeys[keys[0]].composition_key_list, l, data)
+ {
+ if (*data == keys[1])
+ {
+ KLWRN("%d and %d key's key composition is already requested.\n", keys[0], keys[1]);
+ return EINA_FALSE;
+ }
+ }
+ EINA_LIST_FOREACH(krt->HardKeys[keys[1]].composition_key_list, l, data)
+ {
+ if (*data == keys[0])
+ {
+ KLERR("%d and %d key's key composition is already requested. (list currupted)\n", keys[0], keys[1]);
+ return EINA_FALSE;
+ }
+ }
+
+ data = E_NEW(int, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
+
+ data2 = E_NEW(int, 1);
+ EINA_SAFETY_ON_NULL_GOTO(data2, failed);
+
+ *data = keys[0];
+ *data2 = keys[1];
+
+ krt->HardKeys[keys[0]].composition_key_list = eina_list_append(krt->HardKeys[keys[0]].composition_key_list, data2);
+ krt->HardKeys[keys[1]].composition_key_list = eina_list_append(krt->HardKeys[keys[1]].composition_key_list, data);
+
+ KLINF("Add %d and %d key composition.\n", keys[0], keys[1]);
+
+ return EINA_TRUE;
+
+failed:
+ if (data) E_FREE(data);
+
+ return EINA_FALSE;
+}
+
+E_API void
+e_keyrouter_composition_key_del(int *keys, int count)
+{
+ /* FIXME: If del request is came, during checking composition key about key press,
+ How control this behavior?
+ Cancel current composition key or not
+ */
+ Eina_List *l, *l_next;
+ int *data;
+
+ if (count != 2)
+ {
+ KLWRN("Currently only two key composition is allowed. (%d)\n", count);
+ return;
+ }
+
+ EINA_LIST_FOREACH_SAFE(krt->HardKeys[keys[0]].composition_key_list, l, l_next, data)
+ {
+ if (*data == keys[1])
+ {
+ krt->HardKeys[keys[0]].composition_key_list = eina_list_remove_list(krt->HardKeys[keys[0]].composition_key_list, l);
+ E_FREE(data);
+ break;
+ }
+ }
+
+ EINA_LIST_FOREACH_SAFE(krt->HardKeys[keys[1]].composition_key_list, l, l_next, data)
+ {
+ if (*data == keys[0])
+ {
+ krt->HardKeys[keys[1]].composition_key_list = eina_list_remove_list(krt->HardKeys[keys[1]].composition_key_list, l);
+ E_FREE(data);
+ break;
+ }
+ }
+
+ KLINF("Delete %d and %d key composition.\n", keys[0], keys[1]);
+}
+
+
E_API int
e_keyrouter_init(void)
{
krt->conf = kconfig;
krt->pictureoff_disabled = !!kconfig->conf->pictureoff_disabled;
+ krt->composition_key.waiting_time = kconfig->conf->composition_key_wait_time;
+
res = e_keyrouter_wl_init();
EINA_SAFETY_ON_FALSE_GOTO(res, err);
e_keyrouter.keygrab_list_get = _e_keyrouter_keygrab_list_get;
e_keyrouter.max_keycode_get = _e_keyrouter_max_keycode_get;
+ if (!E_KEYROUTER_EVENT_KEY_LONG)
+ E_KEYROUTER_EVENT_KEY_LONG = ecore_event_type_new();
+ if (!E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS)
+ E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS = ecore_event_type_new();
+ if (!E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE)
+ E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE = ecore_event_type_new();
+
TRACE_INPUT_END();
return EINA_TRUE;
{
if (krt->HardKeys[i].keyname)
eina_stringshare_del(krt->HardKeys[i].keyname);
+ EINA_LIST_FREE(krt->HardKeys[i].composition_key_list, keycode_data)
+ E_FREE(keycode_data);
}
E_FREE(krt->HardKeys);
EINA_LIST_FREE(krt->ignore_list, keycode_data)
E_FREE(keycode_data);
+ ecore_event_type_flush(E_KEYROUTER_EVENT_KEY_LONG,
+ E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS,
+ E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE);
+
+ E_KEYROUTER_EVENT_KEY_LONG = 0;
+ E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS = 0;
+ E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE = 0;
+
+ if (krt->composition_key.waiting_timer)
+ {
+ ecore_timer_del(krt->composition_key.waiting_timer);
+ krt->composition_key.waiting_timer = NULL;
+ }
+ if (krt->longkey.timer)
+ {
+ ecore_timer_del(krt->longkey.timer);
+ krt->longkey.timer = NULL;
+ }
+
e_keyrouter_wl_shutdown();
E_FREE(krt);
return EINA_TRUE;
}
+static void
+_e_keyrouter_key_free(Ecore_Event_Key *ev)
+{
+ if (!ev) return;
+
+ eina_stringshare_del(ev->keyname);
+ eina_stringshare_del(ev->key);
+ eina_stringshare_del(ev->string);
+ eina_stringshare_del(ev->compose);
+
+ if (ev->data) E_FREE(ev->data);
+ if (ev->dev) ecore_device_unref(ev->dev);
+
+ E_FREE(ev);
+}
+
+static Ecore_Event_Key *
+_e_keyrouter_key_create(char *keyname)
+{
+ Ecore_Event_Key *ev_key;
+ E_Keyrouter_Event_Data *key_data;
+ int keycode;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(keyname, NULL);
+
+ ev_key = E_NEW(Ecore_Event_Key, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev_key, NULL);
+
+ key_data = E_NEW(E_Keyrouter_Event_Data, 1);
+ EINA_SAFETY_ON_NULL_GOTO(key_data, failed);
+
+ keycode = e_keyrouter_util_keycode_get_from_string(keyname);
+ EINA_SAFETY_ON_FALSE_GOTO((0 < keycode && keycode <= krt->max_tizen_hwkeys), failed);
+
+ ev_key->key = (char *)eina_stringshare_add(keyname);
+ ev_key->keyname = (char *)eina_stringshare_add(ev_key->key);
+ ev_key->compose = (char *)eina_stringshare_add(ev_key->key);
+ ev_key->timestamp = (int)(ecore_time_get()*1000);
+ ev_key->same_screen = 1;
+
+ ev_key->window = e_comp->ee_win;
+ ev_key->event_window = e_comp->ee_win;
+ ev_key->root_window = e_comp->ee_win;
+ ev_key->keycode = keycode;
+ ev_key->data = key_data;
+
+ return ev_key;
+
+failed:
+ if (ev_key) E_FREE(ev_key);
+ if (key_data) E_FREE(key_data);
+ return NULL;
+}
+
+static void
+_e_keyrouter_key_send(int type, Ecore_Event_Key *ev, E_Keyrouter_Key_List_NodePtr key_node)
+{
+ Eina_Bool res_hook = EINA_TRUE;
+ E_Keyrouter_Event_Data *key_data = NULL;
+
+ if (key_node->focused)
+ {
+ res_hook = e_keyrouter_intercept_hook_call(E_KEYROUTER_INTERCEPT_HOOK_DELIVER_FOCUS, type, ev);
+ key_data = (E_Keyrouter_Event_Data *)ev->data;
+
+ if (!res_hook || key_data->ignored)
+ {
+ KLINF("This hook is called to notify a current key is cancel. Please check why hook returns FALSE or ignored.\n");
+ }
+ }
+ e_keyrouter_wl_key_send(ev, (type == ECORE_EVENT_KEY_DOWN)?EINA_TRUE:EINA_FALSE,
+ key_node->wc, key_node->surface, key_node->focused);
+}
+
+static void
+_e_keyrouter_key_cancel(int keycode)
+{
+ Ecore_Event_Key *key_cancel, *key_release;
+ Eina_List *l;
+ char *keyname;
+ E_Keyrouter_Key_List_NodePtr key_node_data;
+ int pid = 0;
+ char *pname = NULL, *cmd = NULL;
+
+ key_cancel = _e_keyrouter_key_create("Cancel");
+ EINA_SAFETY_ON_NULL_RETURN(key_cancel);
+
+ keyname = e_keyrouter_util_keyname_get_from_keycode(keycode);
+ key_release = _e_keyrouter_key_create(keyname);
+ EINA_SAFETY_ON_NULL_GOTO(key_release, failed);
+
+ EINA_LIST_FOREACH(krt->HardKeys[keycode].press_ptr, l, key_node_data)
+ {
+ _e_keyrouter_key_send(ECORE_EVENT_KEY_DOWN, key_cancel, key_node_data);
+ _e_keyrouter_key_send(ECORE_EVENT_KEY_UP, key_release, key_node_data);
+ _e_keyrouter_key_send(ECORE_EVENT_KEY_UP, key_cancel, key_node_data);
+
+ pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+ cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+ pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+ KLINF("CANCEL : => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
+ key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
+ if(pname) E_FREE(pname);
+ if(cmd) E_FREE(cmd);
+ }
+
+ _e_keyrouter_key_free(key_cancel);
+ _e_keyrouter_key_free(key_release);
+
+ return;
+
+failed:
+ if (key_cancel) _e_keyrouter_key_free(key_cancel);
+}
+
+
+static Eina_Bool
+_e_keyrouter_long_timer(void *data)
+{
+ E_Keyrouter_Event_Key_Long *ev;
+
+ ev = E_NEW(E_Keyrouter_Event_Key_Long, 1);
+ if (!ev)
+ {
+ krt->longkey.timer = NULL;
+ krt->longkey.key = 0;
+
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ ev->keycode = krt->longkey.key;
+
+ _e_keyrouter_key_cancel(krt->longkey.key);
+ ecore_event_add(E_KEYROUTER_EVENT_KEY_LONG, ev, NULL, NULL);
+
+ KLINF("LONGKEY : %s(%d) long press event is generated.\n",
+ e_keyrouter_util_keyname_get_from_keycode(krt->longkey.key), krt->longkey.key);
+
+ krt->longkey.timer = NULL;
+
+ /* Cancel a longkey to prevent irregal operation */
+ if (krt->composition_key.waiting_timer)
+ {
+ ecore_timer_del(krt->composition_key.waiting_timer);
+ krt->composition_key.waiting_timer = NULL;
+ krt->composition_key.key[0] = 0;
+ krt->composition_key.key[1] = 0;
+ }
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_e_keyrouter_long_check(int type, Ecore_Event_Key *ev)
+{
+ if (type == ECORE_EVENT_KEY_DOWN)
+ {
+ if (krt->longkey.timer || krt->longkey.key)
+ {
+ KLDBG("Already long pressed key(%d) is exist\n", krt->longkey.key);
+ }
+ else if (krt->HardKeys[ev->keycode].longkey.enabled)
+ {
+ krt->longkey.timer = ecore_timer_add(krt->HardKeys[ev->keycode].longkey.time, _e_keyrouter_long_timer, NULL);
+ krt->longkey.key = ev->keycode;
+ }
+ }
+ else
+ {
+ if (!krt->longkey.timer)
+ {
+ /* Already process a long press key. So ignore a long pressed key's release event */
+ if (krt->longkey.key && krt->longkey.key == ev->keycode)
+ {
+ krt->longkey.key = 0;
+ return ECORE_CALLBACK_DONE;
+ }
+ /* just a short press key event */
+ return ECORE_CALLBACK_PASS_ON;
+ }
+
+ /* Current key event is a short press, so cancel a long press timer. */
+ if (krt->longkey.key == ev->keycode)
+ {
+ ecore_timer_del(krt->longkey.timer);
+ krt->longkey.timer = NULL;
+ krt->longkey.key = 0;
+ }
+ }
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_e_keyrouter_composition_key_event(Eina_Bool pressed)
+{
+ E_Keyrouter_Event_Key_Composition *ev = NULL;
+
+ ev = E_NEW(E_Keyrouter_Event_Key_Composition, 1);
+ EINA_SAFETY_ON_NULL_RETURN(ev);
+
+ ev->keys[0] = krt->composition_key.key[0];
+ ev->keys[1] = krt->composition_key.key[1];
+
+ ev->timestamp = (unsigned int)(ecore_time_get()*1000);
+
+ KLINF("COMPOSITION_KEY : %s(%d) and %s(%d) composition key %s event is generated (time: %d).\n",
+ e_keyrouter_util_keyname_get_from_keycode(ev->keys[0]), ev->keys[0],
+ e_keyrouter_util_keyname_get_from_keycode(ev->keys[1]), ev->keys[1],
+ pressed?"press":"release", ev->timestamp);
+
+ if (pressed)
+ ecore_event_add(E_KEYROUTER_EVENT_KEY_COMPOSITION_PRESS, ev, NULL, NULL);
+ else
+ ecore_event_add(E_KEYROUTER_EVENT_KEY_COMPOSITION_RELEASE, ev, NULL, NULL);
+}
+
+static Eina_Bool
+_e_keyrouter_composition_key_timer(void *data)
+{
+ krt->composition_key.key[0] = 0;
+ krt->composition_key.key[1] = 0;
+
+ krt->composition_key.waiting_timer = NULL;
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_e_keyrouter_composition_key_check(int type, Ecore_Event_Key *ev)
+{
+ Eina_List *l;
+ int *wait_key_data;
+
+ if (type == ECORE_EVENT_KEY_DOWN)
+ {
+ if (krt->composition_key.waiting_timer)
+ {
+ /* Find modkey */
+ EINA_LIST_FOREACH(krt->HardKeys[krt->composition_key.key[0]].composition_key_list, l, wait_key_data)
+ {
+ if (*wait_key_data == ev->keycode)
+ {
+ krt->composition_key.key[1] = ev->keycode;
+
+ ecore_timer_del(krt->composition_key.waiting_timer);
+ krt->composition_key.waiting_timer = NULL;
+
+ /* Cancel a longkey to prevent irregal operation */
+ if (krt->longkey.timer)
+ {
+ ecore_timer_del(krt->longkey.timer);
+ krt->longkey.timer = NULL;
+ krt->longkey.key = 0;
+ }
+
+ _e_keyrouter_key_cancel(krt->composition_key.key[0]);
+ _e_keyrouter_composition_key_event(EINA_TRUE);
+
+ return ECORE_CALLBACK_DONE;
+ }
+ }
+
+ /* Not modkey is pressed, cancel current modkey process */
+ if (krt->composition_key.waiting_timer)
+ {
+ ecore_timer_del(krt->composition_key.waiting_timer);
+ krt->composition_key.waiting_timer = NULL;
+ krt->composition_key.key[0] = 0;
+ krt->composition_key.key[1] = 0;
+ }
+ }
+ else if (!krt->composition_key.key[0] && !krt->composition_key.key[1])
+ {
+ if (eina_list_count(krt->HardKeys[ev->keycode].composition_key_list) > 0)
+ {
+ krt->composition_key.key[0] = ev->keycode;
+ krt->composition_key.waiting_timer = ecore_timer_add(krt->composition_key.waiting_time, _e_keyrouter_composition_key_timer, NULL);
+ }
+ }
+ }
+ else
+ {
+ if (!krt->composition_key.waiting_timer)
+ {
+ /* Already send modkey press and modkey release event is came. */
+ if ((krt->composition_key.key[0] == ev->keycode) ||
+ (krt->composition_key.key[1] == ev->keycode))
+ {
+ /* send modkey release event */
+ if (krt->composition_key.key[0] && krt->composition_key.key[1])
+ {
+ _e_keyrouter_composition_key_event(EINA_FALSE);
+ }
+
+ if (krt->composition_key.key[0] == ev->keycode)
+ {
+ krt->composition_key.key[0] = 0;
+ }
+ else
+ {
+ krt->composition_key.key[1] = 0;
+ }
+ return ECORE_CALLBACK_DONE;
+ }
+ /* Modkey is not yet pressed */
+ return ECORE_CALLBACK_PASS_ON;
+ }
+
+ /* Not modkey, just key short press */
+ if (krt->composition_key.key[0] == ev->keycode)
+ {
+ ecore_timer_del(krt->composition_key.waiting_timer);
+ krt->composition_key.waiting_timer = NULL;
+ krt->composition_key.key[0] = 0;
+
+ return ECORE_CALLBACK_PASS_ON;
+ }
+ }
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+
/* Function for checking the existing grab for a key and sending key event(s) */
Eina_Bool
e_keyrouter_event_process(void *event, int type)
static void
_e_keyrouter_send_key_events(int type, Ecore_Event_Key *ev)
{
+ int pid = 0, keycode = 0;
+ char *pname = NULL, *cmd = NULL;
+ E_Keyrouter_Key_List_NodePtr key_node_data;
+ Eina_List *l = NULL;
+
+ keycode = ev->keycode;
+
+ if (krt->isPictureOffEnabled == 1)
+ {
+ EINA_LIST_FOREACH(krt->HardKeys[keycode].pic_off_ptr, l, key_node_data)
+ {
+ if (key_node_data)
+ {
+ _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, key_node_data->focused, TIZEN_KEYROUTER_MODE_SHARED);
+
+ pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
+ cmd = e_keyrouter_util_cmd_get_from_pid(pid);
+ pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
+ KLINF("PICTURE OFF : %s(%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
+ ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keycode, key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
+
+ if(pname) E_FREE(pname);
+ if(cmd) E_FREE(cmd);
+ }
+ }
+ return;
+ }
+
+ if (!_e_keyrouter_composition_key_check(type, ev))
+ {
+ KLINF("Ignore %s(%d) key %s. This key is already processed for composition key.\n", ev->keyname, ev->keycode, ((ECORE_EVENT_KEY_DOWN == type) ? "down" : "up"));
+ return;
+ }
+
+ if (!_e_keyrouter_long_check(type, ev))
+ {
+ if (type == ECORE_EVENT_KEY_UP)
+ KLINF("Ignore %s(%d) key up. This key is already processed for long press.\n", ev->keyname, ev->keycode);
+ return;
+ }
+
+
if (ECORE_EVENT_KEY_DOWN == type)
{
_e_keyrouter_send_key_events_press(type, ev);
}
- else
+ else
{
_e_keyrouter_send_key_events_release(type, ev);
}
ec_focus = e_client_focused_get();
surface_focus = e_keyrouter_util_get_surface_from_eclient(ec_focus);
- if (krt->isPictureOffEnabled == 1)
- {
- EINA_LIST_FOREACH(krt->HardKeys[keycode].pic_off_ptr, l, key_node_data)
- {
- if (key_node_data)
- {
- _e_keyrouter_send_key_event(type, key_node_data->surface, key_node_data->wc, ev, key_node_data->focused, TIZEN_KEYROUTER_MODE_SHARED);
-
- pid = e_keyrouter_util_get_pid(key_node_data->wc, key_node_data->surface);
- cmd = e_keyrouter_util_cmd_get_from_pid(pid);
- pname = e_keyrouter_util_process_name_get_from_cmd(cmd);
- KLINF("PICTURE OFF : %s(%d) => wl_surface (%p) wl_client (%p) (pid: %d) (pname: %s)",
- ((ECORE_EVENT_KEY_DOWN == type) ? "Down" : "Up"), ev->keycode, key_node_data->surface, key_node_data->wc, pid, pname ?: "Unknown");
- if(pname) E_FREE(pname);
- if(cmd) E_FREE(cmd);
- }
- }
- return;
- }
if (!_e_keyrouter_is_key_grabbed(ev->keycode))
{
_e_keyrouter_send_key_events_focus(type, surface_focus, ev, &delivered_surface);