Dispatching key events 24/169824/7 accepted/tizen/unified/20180405.005220 submit/tizen/20180403.101617 submit/tizen/20180404.045219 submit/tizen/20180404.084838
authorLukasz Wlazly <l.wlazly@partner.samsung.com>
Thu, 8 Feb 2018 13:59:57 +0000 (14:59 +0100)
committerLukasz Wlazly <l.wlazly@partner.samsung.com>
Mon, 12 Feb 2018 13:55:25 +0000 (14:55 +0100)
E-mod can dispatch key events via dbus method call.
This approach enables synchronous dispatching key ecore events.

Change-Id: I7fb11d4eb93ed1bec71da6dd38dfb427ffcafc3d

src/Makefile.am
src/e_dispatch_gesture_event.c
src/e_dispatch_key_event.c [new file with mode: 0644]
src/e_dispatch_key_event.h [new file with mode: 0644]
src/e_mod_main.c
src/e_mod_utils.c
src/e_mod_utils.h

index c50946b..edcd686 100644 (file)
@@ -12,7 +12,8 @@ module_la_SOURCES      = \
        e_dispatch_gesture_event.c \
        e_dispatch_rotation_event.c \
        e_universal_switch.c \
-       e_mod_utils.c
+       e_mod_utils.c \
+       e_dispatch_key_event.c
 
 module_la_LIBADD       =
 module_la_CFLAGS       = @ENLIGHTENMENT_CFLAGS@
index 8df31f5..bba0996 100644 (file)
@@ -26,28 +26,6 @@ static Eina_Bool _on_hold_timer(void *data);
 static Eina_Bool _on_gesture_sequence_timer(void *data);
 static void _on_terminate_gesture_sequence(GestureCommand *cmd);
 
-static Ecore_Device * _get_device()
-{
-   const Eina_List *dev_list = NULL;
-   const Eina_List *l;
-   Ecore_Device *dev = NULL;
-   const char *identifier;
-
-   dev_list = ecore_device_list();
-   if (!dev_list) return NULL;
-   EINA_LIST_FOREACH(dev_list, l, dev)
-     {
-        if (!dev) continue;
-        identifier = ecore_device_identifier_get(dev);
-        if (!identifier) continue;
-
-        //FIXME: Find right way to get device class
-        if (ecore_device_class_get(dev) == ECORE_DEVICE_CLASS_TOUCH)
-          return dev;
-     }
-   return NULL;
-}
-
 static void _dispatch_mouse_move_event(int x, int y, int device)
 {
    Ecore_Event_Mouse_Move *ev;
diff --git a/src/e_dispatch_key_event.c b/src/e_dispatch_key_event.c
new file mode 100644 (file)
index 0000000..953fd97
--- /dev/null
@@ -0,0 +1,126 @@
+#include "e_dispatch_key_event.h"
+
+#include "e.h"
+#include "e_mod_utils.h"
+#include "e_screen_reader_private.h"
+
+static Eina_Bool during_event = EINA_FALSE;
+static double time_between_presses = 0.01;
+
+typedef struct _KeyEventData {
+   KeyEventInfo info;
+   int keycode;
+   Eldbus_Message *reply;
+   Eldbus_Connection *conn;
+} KeyEventData;
+
+static Ecore_Event_Key *
+_create_key_event(KeyEventData *ked)
+{
+   Ecore_Event_Key *ev = calloc(1, sizeof(Ecore_Event_Key));
+   if (!ev)
+      {
+         ERROR("Malloc error");
+         eldbus_connection_send(ked->conn, ked->reply, NULL, NULL, -1);
+         return NULL;
+      }
+
+   ev->keyname = strdup(ked->info.keyname);
+   ev->key = strdup(ked->info.keyname);
+   ev->string = strdup(ked->info.keyname);
+   ev->compose = strdup(ked->info.keyname);
+   ev->window = e_comp->ee_win;
+   ev->event_window = e_comp->ee_win;
+   ev->root_window = e_comp->ee_win;
+   ev->same_screen = 1;
+   ev->dev = _get_device();
+   ev->keycode = ked->keycode;
+
+   return ev;
+}
+
+static void _ecore_deleter(void *data, void *func_data)
+{
+   Ecore_Event_Key *ev = func_data;
+
+   free((char *)ev->keyname);
+   free((char *)ev->key);
+   free((char *)ev->string);
+   free((char *)ev->compose);
+   free(ev);
+}
+
+static Eina_Bool _finalize_event(KeyEventData *ked)
+{
+   eldbus_connection_send(ked->conn, ked->reply, NULL, NULL, -1);
+   free(ked->info.keyname);
+   free(ked);
+   during_event = EINA_FALSE;
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool _generate_key_up_event(void *data);
+
+static Eina_Bool _generate_key_down_event(void *data)
+{
+   KeyEventData *ked = data;
+
+   if (ked->info.multiplicity == 0)
+      return _finalize_event(ked);
+
+   --ked->info.multiplicity;
+
+   Ecore_Event_Key *ev = _create_key_event(ked);
+   ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, _ecore_deleter, NULL);
+   ecore_timer_add(ked->info.hold_time, _generate_key_up_event, ked);
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool _generate_key_up_event(void *data)
+{
+   KeyEventData *ked = data;
+
+   Ecore_Event_Key *ev = _create_key_event(ked);
+   ecore_event_add(ECORE_EVENT_KEY_UP, ev, _ecore_deleter, NULL);
+   ecore_timer_add(time_between_presses, _generate_key_down_event, ked);
+
+   return EINA_FALSE;
+}
+
+static Eldbus_Message *
+_check_event_data(KeyEventInfo *kei, const Eldbus_Message *msg)
+{
+   if (kei->multiplicity < 1)
+      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid multiplicity value, expected: > 1");
+
+   if (kei->hold_time < 0.0)
+      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Invalid hold_time value, expected: >= 0.0");
+
+   return NULL;
+}
+
+Eldbus_Message *
+_e_dispatch_key_event(KeyEventInfo kei, Eldbus_Connection *conn, const Eldbus_Message *msg)
+{
+   if (during_event)
+      return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error.Failed", "Previous call is being processed.");
+
+   Eldbus_Message *error_msg = _check_event_data(&kei, msg);
+   if (error_msg)
+      return error_msg;
+
+   KeyEventData *ked = (KeyEventData *)malloc(sizeof(KeyEventData));
+   ked->info.keyname = strdup(kei.keyname);
+   ked->info.multiplicity = kei.multiplicity;
+   ked->info.hold_time = kei.hold_time;
+   ked->keycode = _get_keycode_from_string(kei.keyname);
+   ked->reply = eldbus_message_method_return_new(msg);
+   ked->conn = conn;
+
+   during_event = EINA_TRUE;
+   _generate_key_down_event(ked);
+
+   return NULL;
+}
diff --git a/src/e_dispatch_key_event.h b/src/e_dispatch_key_event.h
new file mode 100644 (file)
index 0000000..990b80a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef E_DISPATCH_KEY_EVENT_H
+#define E_DISPATCH_KEY_EVENT_H
+
+#include "e.h"
+
+typedef struct _KeyEventInfo {
+   char *keyname;
+   int multiplicity;
+   double hold_time;
+} KeyEventInfo;
+
+Eldbus_Message *_e_dispatch_key_event(KeyEventInfo kei, Eldbus_Connection *conn, const Eldbus_Message *msg);
+
+#endif
index 0eb33a0..1c62170 100644 (file)
@@ -6,6 +6,7 @@
 #include <vconf.h>
 #include <e_dispatch_gesture_event.h>
 #include <e_dispatch_rotation_event.h>
+#include <e_dispatch_key_event.h>
 #include "e_universal_switch.h"
 
 #define E_A11Y_SERVICE_BUS_NAME "org.enlightenment.wm-screen-reader"
@@ -46,6 +47,7 @@ static Eldbus_Message *_object_needs_scroll_gesture(const Eldbus_Service_Interfa
 static Eldbus_Message *_dispatch_drag_event(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
 static Eldbus_Message *_dispatch_pinch_event(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
 static Eldbus_Message *_dispatch_rotation_event(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
+static Eldbus_Message *_dispatch_key_event(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg);
 
 static const Eldbus_Method methods[] = {
       { "ScreenReaderEnabled", ELDBUS_ARGS({"b", "bool"}), ELDBUS_ARGS({"b", "bool"}),
@@ -84,6 +86,9 @@ static const Eldbus_Method methods[] = {
       { "DispatchRotationEvent", ELDBUS_ARGS({"i", "int"}), NULL,
         _dispatch_rotation_event
       },
+      { "DispatchKeyEvent", ELDBUS_ARGS({"s", "string"}, {"i", "int"}, {"d", "double"}), NULL,
+        _dispatch_key_event
+      },
       { }
 };
 
@@ -455,6 +460,20 @@ _dispatch_rotation_event(const Eldbus_Service_Interface *iface, const Eldbus_Mes
    return eldbus_message_method_return_new(msg);
 }
 
+static Eldbus_Message *
+_dispatch_key_event(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
+{
+   KeyEventInfo kei;
+   if (eldbus_message_arguments_get(msg, "sid", &kei.keyname, &kei.multiplicity, &kei.hold_time))
+     {
+        return _e_dispatch_key_event(kei, conn, msg);
+     }
+   else
+     ERROR("eldbus_message_arguments_get() error\n");
+
+   return eldbus_message_method_return_new(msg);
+}
+
 static int
 _fetch_a11y_bus_address(void)
 {
index 265664e..6731532 100644 (file)
@@ -49,3 +49,51 @@ void _transform_coordinates(int *ax, int *ay)
           ERROR("Invalid angle");
     }
 }
+
+Ecore_Device * _get_device()
+{
+   const Eina_List *dev_list = ecore_device_list();
+   if (!dev_list) return NULL;
+
+   const Eina_List *l;
+   Ecore_Device *dev = NULL;
+   EINA_LIST_FOREACH(dev_list, l, dev)
+     {
+        if (!dev) continue;
+        const char *identifier = ecore_device_identifier_get(dev);
+        if (!identifier) continue;
+
+        //FIXME: Find right way to get device class (there could be more than one touch device in the future)
+        if (ecore_device_class_get(dev) == ECORE_DEVICE_CLASS_TOUCH)
+          return dev;
+     }
+   return NULL;
+}
+
+typedef struct _keycode_map_entry{
+        xkb_keysym_t keysym;
+        xkb_keycode_t keycode;
+} keycode_map_entry;
+
+static void
+_find_keycode(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
+{
+   keycode_map_entry* pair = (keycode_map_entry *)data;
+   const xkb_keysym_t *syms_out = NULL;
+   int nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out);
+
+   if (nsyms && syms_out && *syms_out == pair->keysym)
+     {
+        pair->keycode = key;
+     }
+}
+
+int _get_keycode_from_string(const char *key)
+{
+   xkb_keysym_t keysym = xkb_keysym_from_name(key, XKB_KEYSYM_NO_FLAGS);
+   struct xkb_keymap *keymap = e_comp_wl->xkb.keymap;
+   keycode_map_entry pair = {keysym, 0};
+   xkb_keymap_key_for_each(keymap, _find_keycode, &pair);
+
+   return pair.keycode;
+}
index 0ca6ff4..26b5f59 100644 (file)
@@ -1,7 +1,11 @@
 #ifndef E_MOD_UTILS_H
 #define E_MOD_UTILS_H
 
+#include "e.h"
+
 int _get_window_angle(void);
 void _transform_coordinates(int *ax, int *ay);
+Ecore_Device * _get_device();
+int _get_keycode_from_string(const char *key);
 
 #endif