e_input: add essential implementation which doesn't have ecore drm backend dependency 20/153120/2
authorSung-Jin Park <sj76.park@samsung.com>
Wed, 27 Sep 2017 10:03:33 +0000 (19:03 +0900)
committerSung-Jin Park <sj76.park@samsung.com>
Thu, 28 Sep 2017 05:35:36 +0000 (14:35 +0900)
Change-Id: I6c2bff37534cf716ec42d3269136fe9f915da102
Signed-off-by: Sung-Jin Park <sj76.park@samsung.com>
configure.ac
packaging/enlightenment.spec
src/bin/Makefile.mk
src/bin/e_includes.h
src/bin/e_input.c [new file with mode: 0644]
src/bin/e_input.h [new file with mode: 0644]
src/bin/e_input_device.c [new file with mode: 0644]
src/bin/e_input_evdev.c [new file with mode: 0644]
src/bin/e_input_inputs.c [new file with mode: 0644]
src/bin/e_input_private.h [new file with mode: 0644]

index 09480cd..d0c0f2e 100755 (executable)
@@ -292,6 +292,8 @@ e_requires="\
   eldbus >= $efl_version \
   eio >= $efl_version \
   eo >= $efl_version \
+  eeze >= $efl_version \
+  libinput \
   libtbm \
   libtdm >= "1.0.0" \
   "
@@ -525,6 +527,8 @@ fi
 
 AM_CONDITIONAL([HAVE_SYSTEMD], [test "x${have_systemd}" = "xyes"])
 
+#libinput
+PKG_CHECK_MODULES([LIBINPUT], [libinput])
 
 #capi-system-device
 PKG_CHECK_MODULES([CAPI_SYSTEM_DEVICE],
@@ -594,6 +598,7 @@ eina >= ${efl_version} \
 eldbus >= ${efl_version} \
 eio >= ${efl_version} \
 eo >= ${efl_version} \
+eeze >= ${efl_version} \
 "
 
 e_libs="$E_LIBS $fnmatch_libs $execinfo_libs"
index b141efe..bcec1ff 100755 (executable)
@@ -27,6 +27,7 @@ BuildRequires:  pkgconfig(eet)
 BuildRequires:  pkgconfig(eina)
 BuildRequires:  pkgconfig(eio)
 BuildRequires:  pkgconfig(evas)
+BuildRequires:  pkgconfig(eeze)
 BuildRequires:  pkgconfig(libtbm)
 BuildRequires:  pkgconfig(ttrace)
 BuildRequires:  pkgconfig(wayland-server)
@@ -50,6 +51,7 @@ BuildRequires:  pkgconfig(cynara-creds-socket)
 BuildRequires:  pkgconfig(libsmack)
 BuildRequires:  pkgconfig(pixman-1)
 BuildRequires:  systemd-devel
+BuildRequires:  pkgconfig(libinput)
 Requires:       libwayland-extension-server
 %if "%{LIBGOMP}" == "use"
 Requires:       libgomp
index 9cd63fa..d5192ca 100644 (file)
@@ -119,7 +119,8 @@ src/bin/e_process.h \
 src/bin/e_privilege.h \
 src/bin/e_security.h \
 src/bin/e_keyrouter.h \
-src/bin/e_gesture.h
+src/bin/e_gesture.h \
+src/bin/e_input.h
 
 enlightenment_src = \
 src/bin/e_actions.c \
@@ -217,7 +218,12 @@ src/bin/e_process.c \
 src/bin/e_privilege.c \
 src/bin/e_security.c \
 src/bin/e_keyrouter.c \
-src/bin/e_gesture.c
+src/bin/e_gesture.c \
+src/bin/e_input_private.h \
+src/bin/e_input.c \
+src/bin/e_input_inputs.c \
+src/bin/e_input_device.c \
+src/bin/e_input_evdev.c
 
 src_bin_enlightenment_CPPFLAGS = $(E_CPPFLAGS) -DEFL_BETA_API_SUPPORT -DEFL_EO_API_SUPPORT -DE_LOGGING=1 @WAYLAND_CFLAGS@ $(TTRACE_CFLAGS) $(DLOG_CFLAGS) $(PIXMAN_CFLAGS) $(POLICY_CFLAGS) @TIZEN_REMOTE_SURFACE_CFLAGS@
 if HAVE_LIBGOMP
@@ -232,6 +238,7 @@ endif
 if HAVE_SYSTEMD
 src_bin_enlightenment_CPPFLAGS += @SYSTEMD_CFLAGS@
 endif
+src_bin_enlightenment_CPPFLAGS += @LIBINPUT_CFLAGS@
 
 src_bin_enlightenment_SOURCES = \
 src/bin/e_main.c \
@@ -251,6 +258,7 @@ endif
 if HAVE_SYSTEMD
 src_bin_enlightenment_LDFLAGS += @SYSTEMD_LIBS@
 endif
+src_bin_enlightenment_LDFLAGS += @LIBINPUT_LIBS@
 
 src_bin_enlightenment_info_SOURCES = \
 src/bin/e.h \
index cb78128..bdb1a46 100644 (file)
@@ -74,3 +74,4 @@
 #include "e_main.h"
 #include "e_keyrouter.h"
 #include "e_gesture.h"
+#include "e_input.h"
diff --git a/src/bin/e_input.c b/src/bin/e_input.c
new file mode 100644 (file)
index 0000000..830a1d0
--- /dev/null
@@ -0,0 +1,125 @@
+#include "e.h"
+#include "e_input_private.h"
+#include <Ecore_Input_Evas.h>
+
+int _e_input_init_count;
+int _e_input_log_dom = -1;
+
+E_API int E_INPUT_EVENT_INPUT_DEVICE_ADD = -1;
+E_API int E_INPUT_EVENT_INPUT_DEVICE_DEL = -1;
+E_API int E_INPUT_EVENT_SEAT_ADD = -1;
+E_API int E_EVENT_INPUT_ENABLED = -1;
+E_API int E_EVENT_INPUT_DISABLED = -1;
+
+E_API E_Input *e_input = NULL;
+
+EINTERN int
+e_input_init(Ecore_Evas *ee)
+{
+   E_Input_Device *dev;
+
+   if (++_e_input_init_count != 1) return _e_input_init_count;
+
+   if (!eina_init()) goto eina_err;
+   if (!ecore_init()) goto ecore_err;
+   if (!ecore_event_init()) goto ecore_event_err;
+   if (!eeze_init()) goto eeze_err;
+   if (!ecore_event_evas_init()) goto ecore_event_evas_err;
+
+   _e_input_log_dom = eina_log_domain_register("e_input", EINA_COLOR_GREEN);
+   if (!_e_input_log_dom)
+     {
+        EINA_LOG_ERR("Could not create logging domain for E_Input");
+        goto log_err;
+     }
+
+   E_INPUT_EVENT_INPUT_DEVICE_ADD = ecore_event_type_new();
+   E_INPUT_EVENT_INPUT_DEVICE_DEL = ecore_event_type_new();
+   E_INPUT_EVENT_SEAT_ADD = ecore_event_type_new();
+   E_EVENT_INPUT_ENABLED = ecore_event_type_new();
+   E_EVENT_INPUT_DISABLED = ecore_event_type_new();
+
+   ecore_event_add(E_EVENT_INPUT_ENABLED, NULL, NULL, NULL);
+
+   ecore_evas_input_event_register_with_multi(ee);
+   ecore_evas_input_event_register_with_multi2(ee);
+
+   if (!e_input)
+     {
+        e_input = (E_Input *)calloc(1, sizeof(E_Input));
+     }
+
+   if (!e_input)
+     {
+        EINA_LOG_ERR("Failed to alloc memory for e_input\n");
+        goto log_err;
+     }
+
+   dev = e_input_device_open();
+
+   if (!dev)
+     {
+        EINA_LOG_ERR("Failed to open device\n");
+        goto log_err;
+     }
+
+   e_input->window = ecore_evas_window_get(ee);
+   e_input_device_window_set(dev, e_input->window);
+
+   if (!e_input_device_input_backend_create(dev, "libinput_udev"))
+     {
+        EINA_LOG_ERR("Failed to create device\n");
+        goto device_create_err;
+     }
+
+   e_input->dev = dev;
+
+   return _e_input_init_count;
+
+device_create_err:
+   e_input_device_close(dev);
+
+log_err:
+   ecore_event_evas_shutdown();
+
+ecore_event_evas_err:
+   eeze_shutdown();
+
+eeze_err:
+   ecore_event_shutdown();
+
+ecore_event_err:
+   ecore_shutdown();
+
+ecore_err:
+   eina_shutdown();
+
+eina_err:
+   return --_e_input_init_count;
+}
+
+EINTERN int
+e_input_shutdown(void)
+{
+   if (_e_input_init_count < 1) return 0;
+   if (--_e_input_init_count != 0) return _e_input_init_count;
+
+   ecore_event_add(E_EVENT_INPUT_DISABLED, NULL, NULL, NULL);
+
+   E_INPUT_EVENT_INPUT_DEVICE_ADD = -1;
+   E_INPUT_EVENT_INPUT_DEVICE_DEL = -1;
+   E_INPUT_EVENT_SEAT_ADD = -1;
+   E_EVENT_INPUT_ENABLED = -1;
+   E_EVENT_INPUT_DISABLED = -1;
+
+   e_input_device_close(e_input->dev);
+   free(e_input);
+
+   ecore_event_evas_shutdown();
+   eeze_shutdown();
+   ecore_event_shutdown();
+   ecore_shutdown();
+   eina_shutdown();
+
+   return _e_input_init_count;
+}
diff --git a/src/bin/e_input.h b/src/bin/e_input.h
new file mode 100644 (file)
index 0000000..6ee85f7
--- /dev/null
@@ -0,0 +1,106 @@
+#ifdef E_TYPEDEFS
+
+typedef struct _E_Input E_Input;
+
+E_API extern int E_INPUT_EVENT_INPUT_DEVICE_ADD;
+E_API extern int E_INPUT_EVENT_INPUT_DEVICE_DEL;
+E_API extern int E_INPUT_EVENT_SEAT_ADD;
+E_API extern int E_EVENT_INPUT_ENABLED;
+E_API extern int E_EVENT_INPUT_DISABLED;
+
+#else
+
+#ifndef E_INPUT_H
+#define E_INPUT_H
+
+#define E_INPUT_TYPE (int)0xE0b0beaf
+
+#include <xkbcommon/xkbcommon.h>
+
+typedef enum _E_Input_Seat_Capabilities
+{
+   E_INPUT_SEAT_POINTER = (1 << 0),
+   E_INPUT_SEAT_KEYBOARD = (1 << 1),
+   E_INPUT_SEAT_TOUCH = (1 << 2),
+} E_Input_Seat_Capabilities;
+
+struct _E_Input_Event_Input_Device_Add
+{
+   const char *name; /* descriptive device name */
+   const char *sysname; /* system name of the input device */
+   const char *seatname; /* logical name of the seat */
+   E_Input_Seat_Capabilities caps; /* capabilities on a device */
+};
+
+struct _E_Input_Event_Input_Device_Del
+{
+   const char *name; /* descriptive device name */
+   const char *sysname; /* system name of the input device */
+   const char *seatname; /* logical name of the seat */
+   E_Input_Seat_Capabilities caps; /* capabilities on a device */
+};
+
+typedef struct _E_Input_Device E_Input_Device;
+typedef struct _E_Input_Backend E_Input_Backend;
+typedef struct _E_Input_Evdev E_Input_Evdev;
+typedef struct _E_Input_Seat E_Input_Seat;
+
+typedef struct _E_Input_Event_Input_Device_Add E_Input_Event_Input_Device_Add;
+typedef struct _E_Input_Event_Input_Device_Del E_Input_Event_Input_Device_Del;
+
+struct _E_Input
+{
+   Ecore_Window window;
+   E_Input_Device *dev;
+};
+
+struct _E_Input_Device
+{
+   const char *seat;
+
+   Eina_List *seats;
+   Eina_List *inputs;
+   Eina_Hash *fd_hash;
+
+   struct xkb_context *xkb_ctx;
+   int window;
+   Eina_Bool left_handed : 1;
+};
+
+EINTERN int e_input_init(Ecore_Evas *ee);
+EINTERN int e_input_shutdown(void);
+
+EINTERN E_Input_Device *e_input_device_open(void);
+EINTERN Eina_Bool e_input_device_close(E_Input_Device *dev);
+EINTERN void e_input_device_keyboard_cached_context_set(struct xkb_context *ctx);
+EINTERN void e_input_device_keyboard_cached_keymap_set(struct xkb_keymap *map);
+EINTERN Eina_Bool e_input_device_input_backend_create(E_Input_Device *dev, const char *backend);
+EINTERN Eina_Bool e_input_device_input_create_libinput_udev(E_Input_Device *dev);
+EINTERN Eina_Bool e_input_device_input_create_libinput_path(E_Input_Device *dev);
+EINTERN void e_input_device_window_set(E_Input_Device *dev, unsigned int window);
+EINTERN void e_input_device_pointer_xy_get(E_Input_Device *dev, int *x, int *y);
+EINTERN Eina_Bool e_input_device_pointer_left_handed_set(E_Input_Device *dev, Eina_Bool left_handed);
+EINTERN Eina_Bool e_input_device_pointer_rotation_set(E_Input_Device *dev, int rotation);
+EINTERN Eina_Bool e_input_device_touch_rotation_set(E_Input_Device *dev, unsigned int rotation);
+EINTERN void e_input_device_rotation_set(E_Input_Device *dev, unsigned int rotation);
+EINTERN Eina_Bool e_input_device_touch_transformation_set(E_Input_Device *dev, int offset_x, int offset_y, int w, int h);
+
+EINTERN Eina_Bool e_input_enable_input(E_Input_Backend *input);
+EINTERN void e_input_disable_input(E_Input_Backend *input);
+
+EINTERN void e_input_evdev_axis_size_set(E_Input_Evdev *edev, int w, int h);
+EINTERN const char *e_input_evdev_sysname_get(E_Input_Evdev *evdev);
+EINTERN Eina_Bool e_input_evdev_key_remap_enable(E_Input_Evdev *edev, Eina_Bool enable);
+EINTERN Eina_Bool e_input_evdev_key_remap_set(E_Input_Evdev *edev, int *from_keys, int *to_keys, int num);
+EINTERN Eina_Bool e_input_evdev_touch_calibration_set(E_Input_Evdev *edev, float matrix[6]);
+
+E_API const Eina_List *e_input_devices_get(void);
+E_API void e_input_device_pointer_warp(E_Input_Device *dev, int x, int y);
+
+E_API const char *e_input_evdev_name_get(E_Input_Evdev *evdev);
+E_API Eina_List *e_input_seat_evdev_list_get(E_Input_Seat *seat);
+E_API int e_input_evdev_wheel_click_angle_get(E_Input_Evdev *dev);
+E_API Ecore_Device *e_input_evdev_get_ecore_device(const char *path, Ecore_Device_Class clas);
+
+#endif
+#endif
diff --git a/src/bin/e_input_device.c b/src/bin/e_input_device.c
new file mode 100644 (file)
index 0000000..6eb7f28
--- /dev/null
@@ -0,0 +1,874 @@
+#include "e.h"
+#include "e_input_private.h"
+
+/* e_input_device private variable */
+static Eina_List *einput_devices;
+static E_Input_Device *e_input_device_default = NULL;
+
+static int
+_device_open_no_pending(const char *device, int flags)
+{
+   int fd = -1;
+   struct stat s;
+
+   fd = open(device, flags | O_CLOEXEC);
+
+   if (fd < 0) return fd;
+   if (fstat(fd, &s) == -1)
+     {
+        close(fd);
+        return -1;
+     }
+
+   return fd;
+}
+
+static void
+_device_close(const char *device, int fd)
+{
+   if (fd >= 0)
+     close(fd);
+}
+
+/* local functions */
+static int
+_e_input_device_cb_open_restricted(const char *path, int flags, void *data)
+{
+   E_Input_Backend *input;
+   int fd = -1;
+
+   if (!(input = data)) return -1;
+
+   /* try to open the device */
+   fd = _device_open_no_pending(path, flags);
+
+   if (fd < 0)
+     {
+        ERR("Could not open device");
+        return -1;
+     }
+
+   if (input->dev->fd_hash)
+     eina_hash_add(input->dev->fd_hash, path, (void *)(intptr_t)fd);
+
+   return fd;
+}
+
+static void
+_e_input_device_cb_close_restricted(int fd, void *data)
+{
+   E_Input_Backend *input;
+   E_Input_Seat *seat;
+   E_Input_Evdev *edev;
+   Eina_List *l, *ll;
+
+   if (!(input = data)) return;
+
+   EINA_LIST_FOREACH(input->dev->seats, l, seat)
+     {
+        EINA_LIST_FOREACH(seat->devices, ll, edev)
+          {
+             if (edev->fd == fd)
+               {
+                  _device_close(edev->path, fd);
+
+                  /* re-initialize fd after closing */
+                  edev->fd = -1;
+                  return;
+               }
+          }
+     }
+
+   if (fd >= 0) close(fd);
+}
+
+const struct libinput_interface _input_interface =
+{
+   _e_input_device_cb_open_restricted,
+   _e_input_device_cb_close_restricted,
+};
+
+static E_Input_Device *
+_e_input_device_default_get(void)
+{
+   return e_input_device_default;
+}
+
+struct xkb_context *
+_e_input_device_cached_context_get(enum xkb_context_flags flags)
+{
+   if (!cached_context)
+     return xkb_context_new(flags);
+   else
+     return xkb_context_ref(cached_context);
+}
+
+struct xkb_keymap *
+_e_input_device_cached_keymap_get(struct xkb_context *ctx,
+                       const struct xkb_rule_names *names,
+                       enum xkb_keymap_compile_flags flags)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
+
+   if (!cached_keymap)
+     return xkb_map_new_from_names(ctx, names, flags);
+   else
+     return xkb_map_ref(cached_keymap);
+}
+
+void
+_e_input_device_cached_context_update(struct xkb_context *ctx)
+{
+   Eina_List *l;
+   E_Input_Device *dev;
+
+   EINA_LIST_FOREACH(einput_devices, l, dev)
+     {
+        xkb_context_unref(dev->xkb_ctx);
+        dev->xkb_ctx = xkb_context_ref(ctx);
+     }
+}
+
+void
+_e_input_device_cached_keymap_update(struct xkb_keymap *map)
+{
+   Eina_List *l, *l2, *l3;
+   E_Input_Device *dev;
+   E_Input_Seat *seat;
+   E_Input_Evdev *edev;
+
+   EINA_LIST_FOREACH(einput_devices, l, dev)
+     EINA_LIST_FOREACH(dev->seats, l2, seat)
+       EINA_LIST_FOREACH(e_input_seat_evdev_list_get(seat), l3, edev)
+         {
+            xkb_keymap_unref(edev->xkb.keymap);
+            edev->xkb.keymap = xkb_keymap_ref(map);
+            xkb_state_unref(edev->xkb.state);
+            edev->xkb.state = xkb_state_new(map);
+         }
+}
+
+EINTERN void
+e_input_device_keyboard_cached_context_set(struct xkb_context *ctx)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ctx);
+
+   if (cached_context == ctx) return;
+
+   if (cached_context)
+     _e_input_device_cached_context_update(ctx);
+
+   cached_context = ctx;
+}
+
+EINTERN void
+e_input_device_keyboard_cached_keymap_set(struct xkb_keymap *map)
+{
+   EINA_SAFETY_ON_NULL_RETURN(map);
+
+   if (cached_keymap == map) return;
+
+   if (cached_keymap)
+      _e_input_device_cached_keymap_update(map);
+
+   cached_keymap = map;
+}
+
+static void
+e_input_device_destroy(E_Input_Device *dev)
+{
+   E_Input_Backend *input;
+   E_Input_Seat *seat;
+   E_Input_Evdev *edev;
+
+   EINA_SAFETY_ON_NULL_RETURN(dev);
+
+   EINA_LIST_FREE(dev->seats, seat)
+     {
+        EINA_LIST_FREE(seat->devices, edev)
+          {
+             if (edev->fd >= 0)
+               close(edev->fd);
+             _e_input_evdev_device_destroy(edev);
+          }
+
+        if (seat->name)
+          eina_stringshare_del(seat->name);
+        free(seat);
+     }
+
+   EINA_LIST_FREE(dev->inputs, input)
+     {
+        if (input->hdlr)
+          ecore_main_fd_handler_del(input->hdlr);
+        if (input->libinput)
+          libinput_unref(input->libinput);
+        free(input);
+     }
+
+   eina_stringshare_del(dev->seat);
+   xkb_context_unref(dev->xkb_ctx);
+   eina_hash_free(dev->fd_hash);
+   dev->fd_hash = NULL;
+
+   if (dev == e_input_device_default)
+     e_input_device_default = NULL;
+
+   free(dev);
+}
+
+static void
+_e_input_device_add_list(E_Input_Device *dev)
+{
+   Eina_List *l;
+   E_Input_Device *dev_data;
+
+   EINA_LIST_FOREACH(einput_devices, l, dev_data)
+     {
+        if (dev_data == dev) return;
+     }
+
+   einput_devices = eina_list_append(einput_devices, dev);
+}
+
+static void
+_e_input_device_remove_list(E_Input_Device *dev)
+{
+   Eina_List *l, *l_next;
+   E_Input_Device *dev_data;
+
+   EINA_LIST_FOREACH_SAFE(einput_devices, l, l_next, dev_data)
+     {
+        if (dev == dev_data)
+          einput_devices = eina_list_remove_list(einput_devices, l);
+     }
+}
+
+EINTERN E_Input_Device *
+e_input_device_open(void)
+{
+   E_Input_Device *dev = NULL;
+
+   dev = (E_Input_Device *)calloc(1, sizeof(E_Input_Device));
+
+   if (!dev)
+     {
+        EINA_LOG_ERR("Failed to alloc memory for E_Input_Device\n");
+        return NULL;
+     }
+
+   dev->seat = eina_stringshare_add("seat0");
+   dev->fd_hash = eina_hash_string_superfast_new(NULL);
+
+   /* try to create xkb context */
+   if (!(dev->xkb_ctx = _e_input_device_cached_context_get(0)))
+     {
+        ERR("Failed to create xkb context: %m");
+        goto err;
+     }
+
+   if (!e_input_device_default)
+     e_input_device_default = dev;
+
+   _e_input_device_add_list(dev);
+
+   return dev;
+
+err:
+   if (dev)
+     {
+        eina_stringshare_del(dev->seat);
+        xkb_context_unref(dev->xkb_ctx);
+        free(dev);
+     }
+
+   return NULL;
+}
+
+EINTERN Eina_Bool
+e_input_device_close(E_Input_Device *dev)
+{
+   /* check for valid device */
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
+
+   _e_input_device_remove_list(dev);
+   e_input_device_destroy(dev);
+
+   return EINA_TRUE;
+}
+
+EINTERN void
+e_input_device_window_set(E_Input_Device *dev, unsigned int window)
+{
+   /* check for valid device */
+   EINA_SAFETY_ON_TRUE_RETURN(!dev);
+
+   /* TODO : Must update window of ecore/evas device when the given window */
+   /*        is not equal to the existing window. */
+
+   dev->window = window;
+}
+
+EINTERN void
+e_input_device_pointer_xy_get(E_Input_Device *dev, int *x, int *y)
+{
+   E_Input_Seat *seat;
+   E_Input_Evdev *edev;
+   Eina_List *l, *ll;
+
+   if (x) *x = 0;
+   if (y) *y = 0;
+
+   if (!dev)
+     dev = _e_input_device_default_get();
+
+   /* check for valid device */
+   EINA_SAFETY_ON_TRUE_RETURN(!dev);
+   EINA_LIST_FOREACH(dev->seats, l, seat)
+     {
+        EINA_LIST_FOREACH(seat->devices, ll, edev)
+          {
+             if (!libinput_device_has_capability(edev->device,
+                                                 LIBINPUT_DEVICE_CAP_POINTER))
+               continue;
+
+             if (x) *x = seat->ptr.dx;
+             if (y) *y = seat->ptr.dy;
+
+             return;
+          }
+     }
+}
+
+E_API void
+e_input_device_pointer_warp(E_Input_Device *dev, int x, int y)
+{
+   E_Input_Seat *seat;
+   E_Input_Evdev *edev;
+   Eina_List *l, *ll;
+
+   if (!dev)
+     dev = _e_input_device_default_get();
+
+   /* check for valid device */
+   EINA_SAFETY_ON_TRUE_RETURN(!dev);
+   EINA_LIST_FOREACH(dev->seats, l, seat)
+     {
+        EINA_LIST_FOREACH(seat->devices, ll, edev)
+          {
+             if (!libinput_device_has_capability(edev->device,
+                                                 LIBINPUT_DEVICE_CAP_POINTER))
+               continue;
+
+             seat->ptr.dx = seat->ptr.ix = x;
+             seat->ptr.dy = seat->ptr.iy = y;
+             _e_input_pointer_motion_post(edev);
+          }
+     }
+}
+
+EINTERN Eina_Bool
+e_input_device_pointer_left_handed_set(E_Input_Device *dev, Eina_Bool left_handed)
+{
+   E_Input_Seat *seat = NULL;
+   E_Input_Evdev *edev = NULL;
+   Eina_List *l = NULL, *l2 = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev->seats, EINA_FALSE);
+
+   if (dev->left_handed == left_handed)
+     return EINA_TRUE;
+   dev->left_handed = left_handed;
+
+   EINA_LIST_FOREACH(dev->seats, l, seat)
+     {
+        EINA_LIST_FOREACH(e_input_seat_evdev_list_get(seat), l2, edev)
+          {
+             if (libinput_device_has_capability(edev->device,
+                                                LIBINPUT_DEVICE_CAP_POINTER))
+               {
+                  if (libinput_device_config_left_handed_set(edev->device, (int)left_handed) !=
+                      LIBINPUT_CONFIG_STATUS_SUCCESS)
+                    {
+                       WRN("Failed to set left hand mode about device: %s\n",
+                           libinput_device_get_name(edev->device));
+                       continue;
+                    }
+               }
+          }
+     }
+   return EINA_TRUE;
+}
+
+
+EINTERN Eina_Bool
+e_input_device_pointer_rotation_set(E_Input_Device *dev, int rotation)
+{
+   E_Input_Seat *seat = NULL;
+   Eina_List *l = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev->seats, EINA_FALSE);
+
+   if ((rotation % 90 != 0) || (rotation / 90 > 3) || (rotation < 0)) return EINA_FALSE;
+
+   EINA_LIST_FOREACH(dev->seats, l, seat)
+     {
+        switch (rotation)
+          {
+           case 90:
+              seat->ptr.swap = EINA_TRUE;
+              seat->ptr.invert_x = EINA_FALSE;
+              seat->ptr.invert_y = EINA_TRUE;
+              break;
+           case 180:
+              seat->ptr.swap = EINA_FALSE;
+              seat->ptr.invert_x = EINA_TRUE;
+              seat->ptr.invert_y = EINA_TRUE;
+              break;
+           case 270:
+              seat->ptr.swap = EINA_TRUE;
+              seat->ptr.invert_x = EINA_TRUE;
+              seat->ptr.invert_y = EINA_FALSE;
+               break;
+           case 0:
+              seat->ptr.swap = EINA_FALSE;
+              seat->ptr.invert_x = EINA_FALSE;
+              seat->ptr.invert_y = EINA_FALSE;
+              break;
+           default:
+              break;
+          }
+     }
+   return EINA_TRUE;
+}
+
+EINTERN void
+e_input_device_rotation_set(E_Input_Device *dev, unsigned int rotation)
+{
+   E_Input_Seat *seat = NULL;
+   E_Input_Evdev *edev = NULL;
+   Eina_List *l = NULL, *l2 = NULL;
+   int temp;
+
+   EINA_SAFETY_ON_NULL_RETURN(dev);
+   EINA_SAFETY_ON_NULL_RETURN(dev->seats);
+
+   EINA_LIST_FOREACH(dev->seats, l, seat)
+     {
+        EINA_LIST_FOREACH(e_input_seat_evdev_list_get(seat), l2, edev)
+          {
+             if (libinput_device_has_capability(edev->device,
+                                      LIBINPUT_DEVICE_CAP_POINTER))
+               {
+                  edev->mouse.minx = edev->mouse.miny = 0;
+                  e_output_size_get(e_comp_screen_primary_output_get(e_comp->e_comp_screen),
+                                       &edev->mouse.maxw, &edev->mouse.maxh);
+
+                  if (rotation == 90 || rotation == 270)
+                    {
+                       temp = edev->mouse.minx;
+                       edev->mouse.minx = edev->mouse.miny;
+                       edev->mouse.miny = temp;
+
+                       temp = edev->mouse.maxw;
+                       edev->mouse.maxw = edev->mouse.maxh;
+                       edev->mouse.maxh = temp;
+                    }
+               }
+          }
+     }
+}
+
+static void
+_e_input_device_touch_matrix_identify(float result[6])
+{
+   result[0] = 1.0;
+   result[1] = 0.0;
+   result[2] = 0.0;
+   result[3] = 0.0;
+   result[4] = 1.0;
+   result[5] = 0.0;
+}
+
+static void
+_e_input_device_touch_matrix_mulifly(float result[6], float m1[6], float m2[6])
+{
+   result[0] = m1[0] * m2 [0] + m1[1] * m2[3];
+   result[1] = m1[0] * m2 [1] + m1[1] * m2[4];
+   result[2] = m1[0] * m2 [2] + m1[1] * m2[5] + m1[2];
+   result[3] = m1[3] * m2 [0] + m1[4] * m2[3];
+   result[4] = m1[3] * m2 [1] + m1[4] * m2[4];
+   result[5] = m1[3] * m2 [2] + m1[4] * m2[5] + m1[5];
+}
+
+static void
+_e_input_device_touch_matrix_rotation_get(float result[6], int degree, float w, float h)
+{
+   if (w == 0.0) w = 1.0;
+   if (h == 0.0) h = 1.0;
+
+   switch (degree)
+     {
+        case 90:
+          result[0] = 0.0;
+          result[1] = -h/w;
+          result[2] = h/w;
+          result[3] = w/h;
+          result[4] = 0.0;
+          result[5] = 0.0;
+          break;
+        case 180:
+          result[0] = -1.0;
+          result[1] = 0.0;
+          result[2] = 1.0;
+          result[3] = 0.0;
+          result[4] = -1.0;
+          result[5] = 1.0;
+          break;
+        case 270:
+          result[0] = 0.0;
+          result[1] = h/w;
+          result[2] = 0.0;
+          result[3] = -w/h;
+          result[4] = 0.0;
+          result[5] = w/h;
+          break;
+        case 0:
+          _e_input_device_touch_matrix_identify(result);
+          break;
+        default:
+          WRN("Please input valid angle(%d)\n", degree);
+     }
+}
+
+static void
+_e_input_device_touch_matrix_translate_get(float result[6], float x, float y, float w, float h, float default_w, float default_h)
+{
+   if (default_w == 0.0) default_w = 1.0;
+   if (default_h == 0.0) default_h = 1.0;
+
+   result[0] = w / default_w;
+   result[4] = h / default_h;
+   result[2] = x / default_w;
+   result[5] = y / default_h;
+}
+
+EINTERN Eina_Bool
+e_input_device_touch_rotation_set(E_Input_Device *dev, unsigned int rotation)
+{
+   E_Input_Seat *seat = NULL;
+   E_Input_Evdev *edev = NULL;
+   Eina_List *l = NULL, *l2 = NULL;
+   float mat_translate[6] = {0.0, }, mat_rotation[6] = {0.0, }, result[6] = {0.0, };
+   float default_w = 0.0, default_h = 0.0;
+   Eina_Bool res = EINA_TRUE;
+   int output_w = 0, output_h = 0;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev->seats, EINA_FALSE);
+
+   e_output_size_get(e_comp_screen_primary_output_get(e_comp->e_comp_screen), &output_w, &output_h);
+   default_w = (float)output_w;
+   default_h = (float)output_h;
+
+   EINA_LIST_FOREACH(dev->seats, l, seat)
+     {
+        EINA_LIST_FOREACH(e_input_seat_evdev_list_get(seat), l2, edev)
+          {
+             if (edev->caps & E_INPUT_SEAT_TOUCH)
+               {
+                  _e_input_device_touch_matrix_identify(mat_translate);
+                  _e_input_device_touch_matrix_identify(mat_rotation);
+                  _e_input_device_touch_matrix_identify(result);
+
+                  if (edev->touch.transform.x || edev->touch.transform.y ||
+                      edev->touch.transform.w || edev->touch.transform.h)
+                    {
+                       _e_input_device_touch_matrix_translate_get(mat_translate,
+                                                                    (float)edev->touch.transform.x,
+                                                                    (float)edev->touch.transform.y,
+                                                                    (float)edev->touch.transform.w,
+                                                                    (float)edev->touch.transform.h,
+                                                                    default_w, default_h);
+
+                    }
+
+                  _e_input_device_touch_matrix_rotation_get(mat_rotation, rotation, default_w, default_h);
+
+                  _e_input_device_touch_matrix_mulifly(result, mat_translate, mat_rotation);
+
+                  if (!e_input_evdev_touch_calibration_set(edev, result))
+                    {
+                       res = EINA_FALSE;
+                       continue;
+                    }
+                  else
+                    {
+                       edev->touch.transform.rotation = rotation;
+                    }
+               }
+          }
+     }
+
+   return res;
+}
+
+EINTERN Eina_Bool
+e_input_device_touch_transformation_set(E_Input_Device *dev, int offset_x, int offset_y, int w, int h)
+{
+   E_Input_Seat *seat = NULL;
+   E_Input_Evdev *edev = NULL;
+   Eina_List *l = NULL, *l2 = NULL;
+   float mat_translate[6] = {0.0, }, mat_rotation[6] = {0.0 }, result[6] = {0.0, };
+   float default_w = 0.0, default_h = 0.0;
+   Eina_Bool res = EINA_TRUE;
+   int output_w = 0, output_h = 0;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev->seats, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL((w == 0) || (h == 0), EINA_FALSE);
+
+   e_output_size_get(e_comp_screen_primary_output_get(e_comp->e_comp_screen), &output_w, &output_h);
+   default_w = (float)output_w;
+   default_h = (float)output_h;
+
+   EINA_LIST_FOREACH(dev->seats, l, seat)
+     {
+        EINA_LIST_FOREACH(e_input_seat_evdev_list_get(seat), l2, edev)
+          {
+             if (edev->caps & E_INPUT_SEAT_TOUCH)
+               {
+                  _e_input_device_touch_matrix_identify(mat_translate);
+                  _e_input_device_touch_matrix_identify(mat_rotation);
+                  _e_input_device_touch_matrix_identify(result);
+
+                  _e_input_device_touch_matrix_translate_get(mat_translate,
+                                                               (float)offset_x, (float)offset_y,
+                                                               (float)w, (float)h, default_w, default_h);
+
+                  if (edev->touch.transform.rotation)
+                    {
+                       _e_input_device_touch_matrix_rotation_get(mat_rotation,
+                                                                   edev->touch.transform.rotation,
+                                                                   default_w, default_h);
+                    }
+
+                  _e_input_device_touch_matrix_mulifly(result, mat_translate, mat_rotation);
+
+                  if (!e_input_evdev_touch_calibration_set(edev, result))
+                    {
+                       res = EINA_FALSE;
+                       continue;
+                    }
+                  else
+                    {
+                       edev->touch.transform.x = offset_x;
+                       edev->touch.transform.y = offset_y;
+                       edev->touch.transform.w = w;
+                       edev->touch.transform.h = h;
+                    }
+               }
+          }
+     }
+   return res;
+}
+
+static void
+e_input_device_libinput_log_handler(struct libinput *libinput EINA_UNUSED,
+                               enum libinput_log_priority priority,
+                               const char *format, va_list args)
+{
+   char buf[1024] = {0,};
+
+   vsnprintf(buf, 1024, format, args);
+   switch (priority)
+     {
+        case LIBINPUT_LOG_PRIORITY_DEBUG:
+           DBG("%s", buf);
+           break;
+        case LIBINPUT_LOG_PRIORITY_INFO:
+           INF("%s", buf);
+           break;
+        case LIBINPUT_LOG_PRIORITY_ERROR:
+           ERR("%s", buf);
+           break;
+        default:
+           break;
+     }
+}
+
+EINTERN Eina_Bool
+e_input_device_input_backend_create(E_Input_Device *dev, const char *backend)
+{
+   Eina_Bool res = EINA_FALSE;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(backend, EINA_FALSE);
+
+   if (!strncmp(backend, "libinput_udev", strlen("libinput_udev")))
+     res = e_input_device_input_create_libinput_udev(dev);
+   else if (!strncmp(backend, "libinput_path", strlen("libinput_path")))
+     res = e_input_device_input_create_libinput_path(dev);
+
+   return res;
+}
+
+/* public functions */
+EINTERN Eina_Bool
+e_input_device_input_create_libinput_udev(E_Input_Device *dev)
+{
+   E_Input_Backend *input;
+   char *env;
+
+   /* check for valid device */
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
+
+   /* try to allocate space for new input structure */
+   if (!(input = calloc(1, sizeof(E_Input_Backend))))
+     {
+        return EINA_FALSE;
+     }
+
+   /* set reference for parent device */
+   input->dev = dev;
+
+   /* try to create libinput context */
+   input->libinput =
+     libinput_udev_create_context(&_input_interface, input, eeze_udev_get());
+   if (!input->libinput)
+     {
+        ERR("Could not create libinput context: %m");
+        goto err;
+     }
+
+   /* set libinput log priority */
+   if ((env = getenv(E_INPUT_ENV_LIBINPUT_LOG_DISABLE)) && (atoi(env) == 1))
+     libinput_log_set_handler(input->libinput, NULL);
+   else if ((env = getenv(E_INPUT_ENV_LIBINPUT_LOG_EINA_LOG)) && (atoi(env) == 1))
+     libinput_log_set_handler(input->libinput, e_input_device_libinput_log_handler);
+
+   libinput_log_set_priority(input->libinput, LIBINPUT_LOG_PRIORITY_INFO);
+
+   /* assign udev seat */
+   if (libinput_udev_assign_seat(input->libinput, dev->seat) != 0)
+     {
+        ERR("Failed to assign seat: %m");
+        goto err;
+     }
+
+   /* process pending events */
+   _input_events_process(input);
+
+   /* enable this input */
+   if (!e_input_enable_input(input))
+     {
+        ERR("Failed to enable input");
+        goto err;
+     }
+
+   /* append this input */
+   dev->inputs = eina_list_append(dev->inputs, input);
+
+   return EINA_TRUE;
+
+err:
+   if (input->libinput) libinput_unref(input->libinput);
+   free(input);
+
+   return EINA_FALSE;
+}
+
+EINTERN Eina_Bool
+e_input_device_input_create_libinput_path(E_Input_Device *dev)
+{
+   E_Input_Backend *input;
+   struct libinput_device *device;
+   int devices_num = 0;
+   char *env;
+   Eina_Stringshare *path;
+
+   /* check for valid device */
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
+
+   if ((env = getenv("PATH_DEVICES_NUM")))
+     devices_num = atoi(env);
+   if (devices_num <= 0 || devices_num >= INT_MAX)
+     {
+        return EINA_TRUE;
+     }
+
+   INF("PATH_DEVICES_NUM : %d", devices_num);
+
+   /* try to allocate space for new input structure */
+   if (!(input = calloc(1, sizeof(E_Input_Backend))))
+     {
+        return EINA_FALSE;
+     }
+
+   /* set reference for parent device */
+   input->dev = dev;
+
+   /* try to create libinput context */
+   input->libinput =
+     libinput_path_create_context(&_input_interface, input);
+   if (!input->libinput)
+     {
+        ERR("Could not create libinput path context: %m");
+        goto err;
+     }
+
+   /* set libinput log priority */
+   if ((env = getenv(E_INPUT_ENV_LIBINPUT_LOG_DISABLE)) && (atoi(env) == 1))
+     libinput_log_set_handler(input->libinput, NULL);
+   else if ((env = getenv(E_INPUT_ENV_LIBINPUT_LOG_EINA_LOG)) && (atoi(env) == 1))
+     libinput_log_set_handler(input->libinput, e_input_device_libinput_log_handler);
+
+   libinput_log_set_priority(input->libinput, LIBINPUT_LOG_PRIORITY_INFO);
+
+   for (int i = 0; i < devices_num; i++)
+     {
+        char buf[1024] = "PATH_DEVICE_";
+        eina_convert_itoa(i + 1, buf + 12);
+        env = getenv(buf);
+        if (env)
+          {
+             path = eina_stringshare_add(env);
+             device = libinput_path_add_device(input->libinput, path);
+             if (!device)
+               ERR("Failed to initialized device %s", path);
+             else
+               INF("libinput_path created input device %s", path);
+          }
+     }
+
+   /* process pending events */
+   _input_events_process(input);
+
+   /* enable this input */
+   if (!e_input_enable_input(input))
+     {
+        ERR("Failed to enable input");
+        goto err;
+     }
+
+   /* append this input */
+   dev->inputs = eina_list_append(dev->inputs, input);
+
+   return EINA_TRUE;
+
+err:
+   if (input->libinput) libinput_unref(input->libinput);
+   free(input);
+
+   return EINA_FALSE;
+}
+
+
+E_API const Eina_List *
+e_input_devices_get(void)
+{
+   return einput_devices;
+}
+
diff --git a/src/bin/e_input_evdev.c b/src/bin/e_input_evdev.c
new file mode 100644 (file)
index 0000000..216c9c1
--- /dev/null
@@ -0,0 +1,1245 @@
+#include "e.h"
+#include "e_input_private.h"
+
+static void  _device_modifiers_update(E_Input_Evdev *edev);
+
+static void
+_device_calibration_set(E_Input_Evdev *edev)
+{
+   const char *sysname;
+   float cal[6];
+   const char *device;
+   Eina_List *devices;
+   const char *vals;
+   enum libinput_config_status status;
+   E_Output *output;
+   int w = 0, h = 0;
+   int temp;
+
+   output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
+   e_output_size_get(output, &w, &h);
+
+   edev->mouse.minx = edev->mouse.miny = 0;
+   edev->mouse.maxw = w;
+   edev->mouse.maxh = h;
+
+   if (libinput_device_has_capability(edev->device, LIBINPUT_DEVICE_CAP_POINTER))
+     {
+        edev->seat->ptr.ix = edev->seat->ptr.dx = w / 2;
+        edev->seat->ptr.iy = edev->seat->ptr.dy = h / 2;
+        edev->mouse.dx = edev->seat->ptr.dx;
+        edev->mouse.dy = edev->seat->ptr.dy;
+
+        if (output->config.rotation == 90 || output->config.rotation == 270)
+          {
+             temp = edev->mouse.minx;
+             edev->mouse.minx = edev->mouse.miny;
+             edev->mouse.miny = temp;
+
+             temp = edev->mouse.maxw;
+             edev->mouse.maxw = edev->mouse.maxh;
+             edev->mouse.maxh = temp;
+          }
+     }
+
+   if ((!libinput_device_config_calibration_has_matrix(edev->device)) ||
+       (libinput_device_config_calibration_get_default_matrix(edev->device, cal) != 0))
+     return;
+
+   sysname = libinput_device_get_sysname(edev->device);
+
+   devices = eeze_udev_find_by_subsystem_sysname("input", sysname);
+   if (eina_list_count(devices) < 1) return;
+
+   EINA_LIST_FREE(devices, device)
+     {
+        vals = eeze_udev_syspath_get_property(device, "WL_CALIBRATION");
+       if ((!vals) ||
+            (sscanf(vals, "%f %f %f %f %f %f",
+                    &cal[0], &cal[1], &cal[2], &cal[3], &cal[4], &cal[5]) != 6))
+          goto cont;
+
+        cal[2] /= w;
+        cal[5] /= h;
+
+        status =
+          libinput_device_config_calibration_set_matrix(edev->device, cal);
+
+        if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
+          ERR("Failed to apply calibration");
+
+cont:
+        eina_stringshare_del(device);
+        continue;
+     }
+}
+
+static void
+_device_configure(E_Input_Evdev *edev)
+{
+   if (libinput_device_config_tap_get_finger_count(edev->device) > 0)
+     {
+        Eina_Bool tap = EINA_FALSE;
+
+        tap = libinput_device_config_tap_get_default_enabled(edev->device);
+        libinput_device_config_tap_set_enabled(edev->device, tap);
+     }
+
+   _device_calibration_set(edev);
+}
+
+static void
+_device_keyboard_setup(E_Input_Evdev *edev)
+{
+   E_Input_Backend *input;
+
+   if ((!edev) || (!edev->seat)) return;
+   if (!(input = edev->seat->input)) return;
+   if (!input->dev->xkb_ctx) return;
+
+   /* create keymap from xkb context */
+   edev->xkb.keymap = _e_input_device_cached_keymap_get(input->dev->xkb_ctx, NULL, 0);
+   if (!edev->xkb.keymap)
+     {
+        ERR("Failed to create keymap: %m");
+        return;
+     }
+
+   /* create xkb state */
+   if (!(edev->xkb.state = xkb_state_new(edev->xkb.keymap)))
+     {
+        ERR("Failed to create xkb state: %m");
+        return;
+     }
+
+   edev->xkb.ctrl_mask =
+     1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_CTRL);
+   edev->xkb.alt_mask =
+     1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_ALT);
+   edev->xkb.shift_mask =
+     1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_SHIFT);
+   edev->xkb.win_mask =
+     1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_LOGO);
+   edev->xkb.scroll_mask =
+     1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_LED_NAME_SCROLL);
+   edev->xkb.num_mask =
+     1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_LED_NAME_NUM);
+   edev->xkb.caps_mask =
+     1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_CAPS);
+   edev->xkb.altgr_mask =
+     1 << xkb_map_mod_get_index(edev->xkb.keymap, "ISO_Level3_Shift");
+}
+
+static int
+_device_keysym_translate(xkb_keysym_t keysym, unsigned int modifiers, char *buffer, int bytes)
+{
+   unsigned long hbytes = 0;
+   unsigned char c;
+
+   if (!keysym) return 0;
+   hbytes = (keysym >> 8);
+
+   if (!(bytes &&
+         ((hbytes == 0) ||
+          ((hbytes == 0xFF) &&
+           (((keysym >= XKB_KEY_BackSpace) && (keysym <= XKB_KEY_Clear)) ||
+            (keysym == XKB_KEY_Return) || (keysym == XKB_KEY_Escape) ||
+            (keysym == XKB_KEY_KP_Space) || (keysym == XKB_KEY_KP_Tab) ||
+            (keysym == XKB_KEY_KP_Enter) ||
+            ((keysym >= XKB_KEY_KP_Multiply) && (keysym <= XKB_KEY_KP_9)) ||
+            (keysym == XKB_KEY_KP_Equal) || (keysym == XKB_KEY_Delete))))))
+     return 0;
+
+   if (keysym == XKB_KEY_KP_Space)
+     c = (XKB_KEY_space & 0x7F);
+   else if (hbytes == 0xFF)
+     c = (keysym & 0x7F);
+   else
+     c = (keysym & 0xFF);
+
+   if (modifiers & ECORE_EVENT_MODIFIER_CTRL)
+     {
+        if (((c >= '@') && (c < '\177')) || c == ' ')
+          c &= 0x1F;
+        else if (c == '2')
+          c = '\000';
+        else if ((c >= '3') && (c <= '7'))
+          c -= ('3' - '\033');
+        else if (c == '8')
+          c = '\177';
+        else if (c == '/')
+          c = '_' & 0x1F;
+     }
+   buffer[0] = c;
+   return 1;
+}
+
+static void
+_device_modifiers_update_device(E_Input_Evdev *edev, E_Input_Evdev *from)
+{
+   xkb_mod_mask_t mask;
+
+   edev->xkb.depressed =
+     xkb_state_serialize_mods(from->xkb.state, XKB_STATE_DEPRESSED);
+   edev->xkb.latched =
+     xkb_state_serialize_mods(from->xkb.state, XKB_STATE_LATCHED);
+   edev->xkb.locked =
+     xkb_state_serialize_mods(from->xkb.state, XKB_STATE_LOCKED);
+   edev->xkb.group =
+     xkb_state_serialize_mods(from->xkb.state, XKB_STATE_EFFECTIVE);
+
+   mask = (edev->xkb.depressed | edev->xkb.latched);
+
+   if (mask & from->xkb.ctrl_mask)
+     edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_CTRL;
+   if (mask & from->xkb.alt_mask)
+     edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_ALT;
+   if (mask & from->xkb.shift_mask)
+     edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
+   if (mask & from->xkb.win_mask)
+     edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_WIN;
+   if (mask & from->xkb.scroll_mask)
+     edev->xkb.modifiers |= ECORE_EVENT_LOCK_SCROLL;
+   if (mask & from->xkb.num_mask)
+     edev->xkb.modifiers |= ECORE_EVENT_LOCK_NUM;
+   if (mask & from->xkb.caps_mask)
+     edev->xkb.modifiers |= ECORE_EVENT_LOCK_CAPS;
+   if (mask & from->xkb.altgr_mask)
+     edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_ALTGR;
+}
+
+static void
+_device_modifiers_update(E_Input_Evdev *edev)
+{
+   edev->xkb.modifiers = 0;
+
+   if (edev->caps & E_INPUT_SEAT_KEYBOARD)
+     _device_modifiers_update_device(edev, edev);
+   else
+     {
+        Eina_List *l;
+        E_Input_Evdev *ed;
+
+        EINA_LIST_FOREACH(edev->seat->devices, l, ed)
+          {
+             if (!(ed->caps & E_INPUT_SEAT_KEYBOARD)) continue;
+             _device_modifiers_update_device(edev, ed);
+          }
+     }
+
+}
+
+static int
+_device_remapped_key_get(E_Input_Evdev *edev, int code)
+{
+   void *ret = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev, code);
+   if (!edev->key_remap_enabled) return code;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev->key_remap_hash, code);
+
+   ret = eina_hash_find(edev->key_remap_hash, &code);
+
+   if (ret) code = (int)(intptr_t)ret;
+
+   return code;
+}
+
+E_API Ecore_Device *
+e_input_evdev_get_ecore_device(const char *path, Ecore_Device_Class clas)
+{
+   const Eina_List *dev_list = NULL;
+   const Eina_List *l;
+   Ecore_Device *dev = NULL;
+   const char *identifier;
+
+   if (!path) return NULL;
+
+   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;
+        if ((ecore_device_class_get(dev) == clas) && !(strcmp(identifier, path)))
+          return dev;
+     }
+   return NULL;
+}
+
+static void
+_device_handle_key(struct libinput_device *device, struct libinput_event_keyboard *event)
+{
+   E_Input_Evdev *edev;
+   E_Input_Backend *input;
+   uint32_t timestamp;
+   uint32_t code, nsyms;
+   const xkb_keysym_t *syms;
+   enum libinput_key_state state;
+   int key_count;
+   xkb_keysym_t sym = XKB_KEY_NoSymbol;
+   char key[256], keyname[256], compose_buffer[256];
+   Ecore_Event_Key *e;
+   char *tmp = NULL, *compose = NULL;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+
+   if (!(input = edev->seat->input))
+     {
+        return;
+     }
+
+   timestamp = libinput_event_keyboard_get_time(event);
+   code = libinput_event_keyboard_get_key(event);
+   code = _device_remapped_key_get(edev, code) + 8;
+   state = libinput_event_keyboard_get_key_state(event);
+   key_count = libinput_event_keyboard_get_seat_key_count(event);
+
+   /* ignore key events that are not seat wide state changes */
+   if (((state == LIBINPUT_KEY_STATE_PRESSED) && (key_count != 1)) ||
+       ((state == LIBINPUT_KEY_STATE_RELEASED) && (key_count != 0)))
+     {
+        return;
+     }
+
+   xkb_state_update_key(edev->xkb.state, code,
+                        (state ? XKB_KEY_DOWN : XKB_KEY_UP));
+
+   /* get the keysym for this code */
+   nsyms = xkb_key_get_syms(edev->xkb.state, code, &syms);
+   if (nsyms == 1) sym = syms[0];
+
+   /* get the keyname for this sym */
+   memset(key, 0, sizeof(key));
+   xkb_keysym_get_name(sym, key, sizeof(key));
+
+   memset(keyname, 0, sizeof(keyname));
+   memcpy(keyname, key, sizeof(keyname));
+
+   if (keyname[0] == '\0')
+     snprintf(keyname, sizeof(keyname), "Keycode-%u", code);
+
+   /* if shift is active, we need to transform the key to lower */
+   if (xkb_state_mod_index_is_active(edev->xkb.state,
+                                     xkb_map_mod_get_index(edev->xkb.keymap,
+                                     XKB_MOD_NAME_SHIFT),
+                                     XKB_STATE_MODS_EFFECTIVE))
+     {
+        if (keyname[0] != '\0')
+          keyname[0] = tolower(keyname[0]);
+     }
+
+   memset(compose_buffer, 0, sizeof(compose_buffer));
+   if (_device_keysym_translate(sym, edev->xkb.modifiers,
+                                compose_buffer, sizeof(compose_buffer)))
+     {
+        compose = eina_str_convert("ISO8859-1", "UTF-8", compose_buffer);
+        if (!compose)
+          {
+             ERR("E Input cannot convert input key string '%s' to UTF-8. "
+                 "Is Eina built with iconv support?", compose_buffer);
+          }
+        else
+          tmp = compose;
+     }
+
+   if (!compose) compose = compose_buffer;
+
+   e = calloc(1, sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
+              ((compose[0] != '\0') ? strlen(compose) : 0) + 3);
+   if (!e)
+     {
+        return;
+     }
+
+   e->keyname = (char *)(e + 1);
+   e->key = e->keyname + strlen(keyname) + 1;
+   e->compose = strlen(compose) ? e->key + strlen(key) + 1 : NULL;
+   e->string = e->compose;
+
+   strncpy((char *)e->keyname, keyname, strlen(keyname));
+   strncpy((char *)e->key, key, strlen(key));
+   if (strlen(compose)) strncpy((char *)e->compose, compose, strlen(compose));
+
+   e->window = (Ecore_Window)input->dev->window;
+   e->event_window = (Ecore_Window)input->dev->window;
+   e->root_window = (Ecore_Window)input->dev->window;
+   e->timestamp = timestamp;
+   e->same_screen = 1;
+   e->keycode = code;
+   e->data = NULL;
+
+   _device_modifiers_update(edev);
+
+   e->modifiers = edev->xkb.modifiers;
+   e->dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_KEYBOARD);
+
+   if (state)
+     ecore_event_add(ECORE_EVENT_KEY_DOWN, e, NULL, NULL);
+   else
+     ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL);
+
+   if (tmp) free(tmp);
+}
+
+static void
+_device_pointer_motion(E_Input_Evdev *edev, struct libinput_event_pointer *event)
+{
+   E_Input_Backend *input;
+   Ecore_Event_Mouse_Move *ev;
+
+   if (!(input = edev->seat->input)) return;
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Move)))) return;
+
+   if (edev->seat->ptr.ix < edev->mouse.minx)
+     edev->seat->ptr.dx = edev->seat->ptr.ix = edev->mouse.minx;
+   else if (edev->seat->ptr.ix >= (edev->mouse.minx + edev->mouse.maxw))
+     edev->seat->ptr.dx = edev->seat->ptr.ix = (edev->mouse.minx + edev->mouse.maxw - 1);
+
+   if (edev->seat->ptr.iy < edev->mouse.miny)
+     edev->seat->ptr.dy = edev->seat->ptr.iy = edev->mouse.miny;
+   else if (edev->seat->ptr.iy >= (edev->mouse.miny + edev->mouse.maxh))
+     edev->seat->ptr.dy = edev->seat->ptr.iy = (edev->mouse.miny + edev->mouse.maxh - 1);
+
+   edev->mouse.dx = edev->seat->ptr.dx;
+   edev->mouse.dy = edev->seat->ptr.dy;
+
+   ev->window = (Ecore_Window)input->dev->window;
+   ev->event_window = (Ecore_Window)input->dev->window;
+   ev->root_window = (Ecore_Window)input->dev->window;
+   if (event) ev->timestamp = libinput_event_pointer_get_time(event);
+   ev->same_screen = 1;
+
+   _device_modifiers_update(edev);
+   ev->modifiers = edev->xkb.modifiers;
+
+   ev->x = edev->seat->ptr.ix;
+   ev->y = edev->seat->ptr.iy;
+   ev->root.x = ev->x;
+   ev->root.y = ev->y;
+
+   ev->multi.device = edev->mt_slot;
+   ev->multi.radius = 1;
+   ev->multi.radius_x = 1;
+   ev->multi.radius_y = 1;
+   ev->multi.pressure = 1.0;
+   ev->multi.angle = 0.0;
+   ev->multi.x = ev->x;
+   ev->multi.y = ev->y;
+   ev->multi.root.x = ev->x;
+   ev->multi.root.y = ev->y;
+   ev->dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_MOUSE);
+
+   ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
+}
+
+void
+_e_input_pointer_motion_post(E_Input_Evdev *edev)
+{
+   _device_pointer_motion(edev, NULL);
+}
+
+static void
+_device_handle_pointer_motion(struct libinput_device *device, struct libinput_event_pointer *event)
+{
+   E_Input_Evdev *edev;
+   double dx, dy, temp;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+
+   dx = libinput_event_pointer_get_dx(event);
+   dy = libinput_event_pointer_get_dy(event);
+
+   if (edev->seat->ptr.swap)
+     {
+         temp = dx;
+         dx = dy;
+         dy = temp;
+     }
+   if (edev->seat->ptr.invert_x)
+     dx *= -1;
+   if (edev->seat->ptr.invert_y)
+     dy *= -1;
+
+   edev->seat->ptr.dx += dx;
+   edev->seat->ptr.dy += dy;
+
+   edev->mouse.dx = edev->seat->ptr.dx;
+   edev->mouse.dy = edev->seat->ptr.dy;
+
+   if (floor(edev->seat->ptr.dx) == edev->seat->ptr.ix &&
+       floor(edev->seat->ptr.dy) == edev->seat->ptr.iy)
+     {
+        return;
+     }
+
+   edev->seat->ptr.ix = edev->seat->ptr.dx;
+   edev->seat->ptr.iy = edev->seat->ptr.dy;
+
+  _device_pointer_motion(edev, event);
+}
+
+static void
+_device_handle_pointer_motion_absolute(struct libinput_device *device, struct libinput_event_pointer *event)
+{
+   E_Input_Evdev *edev;
+   int w = 0, h = 0;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+
+   e_output_size_get(e_comp_screen_primary_output_get(e_comp->e_comp_screen), &w, &h);
+
+   edev->mouse.dx = edev->seat->ptr.dx =
+     libinput_event_pointer_get_absolute_x_transformed(event, w);
+   edev->mouse.dy = edev->seat->ptr.dy =
+     libinput_event_pointer_get_absolute_y_transformed(event, h);
+
+   if (floor(edev->seat->ptr.dx) == edev->seat->ptr.ix &&
+       floor(edev->seat->ptr.dy) == edev->seat->ptr.iy)
+     {
+        return;
+     }
+
+   edev->seat->ptr.ix = edev->seat->ptr.dx;
+   edev->seat->ptr.iy = edev->seat->ptr.dy;
+   _device_pointer_motion(edev, event);
+}
+
+static void
+_device_handle_button(struct libinput_device *device, struct libinput_event_pointer *event)
+{
+   E_Input_Evdev *edev;
+   E_Input_Backend *input;
+   Ecore_Event_Mouse_Button *ev;
+   enum libinput_button_state state;
+   uint32_t button, timestamp;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+   if (!(input = edev->seat->input))
+     {
+        return;
+     }
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Button))))
+     {
+        return;
+     }
+
+   state = libinput_event_pointer_get_button_state(event);
+   button = libinput_event_pointer_get_button(event);
+   timestamp = libinput_event_pointer_get_time(event);
+
+   button = ((button & 0x00F) + 1);
+   if (button == 3) button = 2;
+   else if (button == 2) button = 3;
+
+   ev->window = (Ecore_Window)input->dev->window;
+   ev->event_window = (Ecore_Window)input->dev->window;
+   ev->root_window = (Ecore_Window)input->dev->window;
+   ev->timestamp = timestamp;
+   ev->same_screen = 1;
+
+   _device_modifiers_update(edev);
+   ev->modifiers = edev->xkb.modifiers;
+
+   ev->x = edev->seat->ptr.ix;
+   ev->y = edev->seat->ptr.iy;
+   ev->root.x = ev->x;
+   ev->root.y = ev->y;
+
+   ev->multi.device = edev->mt_slot;
+   ev->multi.radius = 1;
+   ev->multi.radius_x = 1;
+   ev->multi.radius_y = 1;
+   ev->multi.pressure = 1.0;
+   ev->multi.angle = 0.0;
+   ev->multi.x = ev->x;
+   ev->multi.y = ev->y;
+   ev->multi.root.x = ev->x;
+   ev->multi.root.y = ev->y;
+   ev->dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_MOUSE);
+
+   if (state)
+     {
+        unsigned int current;
+
+        current = timestamp;
+        edev->mouse.did_double = EINA_FALSE;
+        edev->mouse.did_triple = EINA_FALSE;
+
+        if (((current - edev->mouse.prev) <= edev->mouse.threshold) &&
+            (button == edev->mouse.prev_button))
+          {
+             edev->mouse.did_double = EINA_TRUE;
+             if (((current - edev->mouse.last) <= (2 * edev->mouse.threshold)) &&
+                 (button == edev->mouse.last_button))
+               {
+                  edev->mouse.did_triple = EINA_TRUE;
+                  edev->mouse.prev = 0;
+                  edev->mouse.last = 0;
+                  current = 0;
+               }
+          }
+
+        edev->mouse.last = edev->mouse.prev;
+        edev->mouse.prev = current;
+        edev->mouse.last_button = edev->mouse.prev_button;
+        edev->mouse.prev_button = button;
+     }
+
+   ev->buttons = button;
+
+   if (edev->mouse.did_double)
+     ev->double_click = 1;
+   if (edev->mouse.did_triple)
+     ev->triple_click = 1;
+
+   if (state)
+     ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
+   else
+     ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
+}
+
+static void
+_device_handle_axis(struct libinput_device *device, struct libinput_event_pointer *event)
+{
+   E_Input_Evdev *edev;
+   E_Input_Backend *input;
+   Ecore_Event_Mouse_Wheel *ev;
+   uint32_t timestamp;
+   enum libinput_pointer_axis axis;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+   if (!(input = edev->seat->input))
+     {
+        return;
+     }
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Wheel))))
+     {
+        return;
+     }
+
+   timestamp = libinput_event_pointer_get_time(event);
+
+   ev->window = (Ecore_Window)input->dev->window;
+   ev->event_window = (Ecore_Window)input->dev->window;
+   ev->root_window = (Ecore_Window)input->dev->window;
+   ev->timestamp = timestamp;
+   ev->same_screen = 1;
+
+   _device_modifiers_update(edev);
+   ev->modifiers = edev->xkb.modifiers;
+
+   ev->x = edev->seat->ptr.ix;
+   ev->y = edev->seat->ptr.iy;
+   ev->root.x = ev->x;
+   ev->root.y = ev->y;
+   ev->dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_MOUSE);
+
+   axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
+   if (libinput_event_pointer_has_axis(event, axis))
+     ev->z = libinput_event_pointer_get_axis_value(event, axis);
+
+   axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
+   if (libinput_event_pointer_has_axis(event, axis))
+     {
+        ev->direction = 1;
+        ev->z = libinput_event_pointer_get_axis_value(event, axis);
+     }
+
+   ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL);
+}
+
+static void
+_device_handle_touch_event_send(E_Input_Evdev *edev, struct libinput_event_touch *event, int state)
+{
+   E_Input_Backend *input;
+   Ecore_Event_Mouse_Button *ev;
+   uint32_t timestamp, button = 0;
+
+   if (!edev) return;
+   if (!(input = edev->seat->input)) return;
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)))) return;
+
+   timestamp = libinput_event_touch_get_time(event);
+
+   ev->window = (Ecore_Window)input->dev->window;
+   ev->event_window = (Ecore_Window)input->dev->window;
+   ev->root_window = (Ecore_Window)input->dev->window;
+   ev->timestamp = timestamp;
+   ev->same_screen = 1;
+
+   _device_modifiers_update(edev);
+   ev->modifiers = edev->xkb.modifiers;
+
+   ev->x = edev->seat->ptr.ix;
+   ev->y = edev->seat->ptr.iy;
+   ev->root.x = ev->x;
+   ev->root.y = ev->y;
+
+   ev->multi.device = edev->mt_slot;
+   ev->multi.radius = 1;
+   ev->multi.radius_x = 1;
+   ev->multi.radius_y = 1;
+   ev->multi.pressure = 1.0;
+   ev->multi.angle = 0.0;
+#if LIBINPUT_SUPPORT_EXTRA_TOUCH_EVENT
+   if (libinput_event_get_type(libinput_event_touch_get_base_event(event))
+       == LIBINPUT_EVENT_TOUCH_DOWN)
+     {
+        if (libinput_event_touch_has_minor(event))
+          ev->multi.radius_x = libinput_event_touch_get_minor(event);
+        if (libinput_event_touch_has_major(event))
+          ev->multi.radius_y = libinput_event_touch_get_major(event);
+        if (libinput_event_touch_has_pressure(event))
+          ev->multi.pressure = libinput_event_touch_get_pressure(event);
+        if (libinput_event_touch_has_orientation(event))
+          ev->multi.angle = libinput_event_touch_get_orientation(event);
+     }
+#endif
+   ev->multi.x = ev->x;
+   ev->multi.y = ev->y;
+   ev->multi.root.x = ev->x;
+   ev->multi.root.y = ev->y;
+   ev->dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_TOUCH);
+
+   if (state == ECORE_EVENT_MOUSE_BUTTON_DOWN)
+     {
+        unsigned int current;
+
+        current = timestamp;
+        edev->mouse.did_double = EINA_FALSE;
+        edev->mouse.did_triple = EINA_FALSE;
+
+        if (((current - edev->mouse.prev) <= edev->mouse.threshold) &&
+            (button == edev->mouse.prev_button))
+          {
+             edev->mouse.did_double = EINA_TRUE;
+             if (((current - edev->mouse.last) <= (2 * edev->mouse.threshold)) &&
+                 (button == edev->mouse.last_button))
+               {
+                  edev->mouse.did_triple = EINA_TRUE;
+                  edev->mouse.prev = 0;
+                  edev->mouse.last = 0;
+                  current = 0;
+               }
+          }
+
+        edev->mouse.last = edev->mouse.prev;
+        edev->mouse.prev = current;
+        edev->mouse.last_button = edev->mouse.prev_button;
+        edev->mouse.prev_button = button;
+     }
+
+   ev->buttons = ((button & 0x00F) + 1);
+
+   if (edev->mouse.did_double)
+     ev->double_click = 1;
+   if (edev->mouse.did_triple)
+     ev->triple_click = 1;
+
+   ecore_event_add(state, ev, NULL, NULL);
+}
+
+static void
+_device_handle_touch_motion_send(E_Input_Evdev *edev, struct libinput_event_touch *event)
+{
+   E_Input_Backend *input;
+   Ecore_Event_Mouse_Move *ev;
+
+   if (!edev) return;
+   if (!(input = edev->seat->input)) return;
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Move)))) return;
+
+   ev->window = (Ecore_Window)input->dev->window;
+   ev->event_window = (Ecore_Window)input->dev->window;
+   ev->root_window = (Ecore_Window)input->dev->window;
+   ev->timestamp = libinput_event_touch_get_time(event);
+   ev->same_screen = 1;
+
+   _device_modifiers_update(edev);
+   ev->modifiers = edev->xkb.modifiers;
+   ev->modifiers = 0;
+
+   ev->x = edev->seat->ptr.ix;
+   ev->y = edev->seat->ptr.iy;
+   ev->root.x = ev->x;
+   ev->root.y = ev->y;
+
+   ev->multi.device = edev->mt_slot;
+   ev->multi.radius = 1;
+   ev->multi.radius_x = 1;
+   ev->multi.radius_y = 1;
+   ev->multi.pressure = 1.0;
+   ev->multi.angle = 0.0;
+#if LIBINPUT_SUPPORT_EXTRA_TOUCH_EVENT
+   if (libinput_event_touch_has_minor(event))
+     ev->multi.radius_x = libinput_event_touch_get_minor(event);
+   if (libinput_event_touch_has_major(event))
+     ev->multi.radius_y = libinput_event_touch_get_major(event);
+   if (libinput_event_touch_has_pressure(event))
+     ev->multi.pressure = libinput_event_touch_get_pressure(event);
+   if (libinput_event_touch_has_orientation(event))
+     ev->multi.angle = libinput_event_touch_get_orientation(event);
+#endif
+   ev->multi.x = ev->x;
+   ev->multi.y = ev->y;
+   ev->multi.root.x = ev->x;
+   ev->multi.root.y = ev->y;
+   ev->dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_TOUCH);
+
+   ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
+}
+
+static void
+_device_handle_touch_down(struct libinput_device *device, struct libinput_event_touch *event)
+{
+   E_Input_Evdev *edev;
+   int w = 0, h = 0;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+
+   e_output_size_get(e_comp_screen_primary_output_get(e_comp->e_comp_screen), &w, &h);
+
+   edev->mouse.dx = edev->seat->ptr.ix = edev->seat->ptr.dx =
+     libinput_event_touch_get_x_transformed(event, w);
+   edev->mouse.dy = edev->seat->ptr.iy = edev->seat->ptr.dy =
+     libinput_event_touch_get_y_transformed(event, h);
+
+   edev->mt_slot = libinput_event_touch_get_slot(event);
+
+   _device_handle_touch_motion_send(edev, event);
+   _device_handle_touch_event_send(edev, event, ECORE_EVENT_MOUSE_BUTTON_DOWN);
+}
+
+static void
+_device_handle_touch_motion(struct libinput_device *device, struct libinput_event_touch *event)
+{
+   E_Input_Evdev *edev;
+   int w = 0, h = 0;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+
+   e_output_size_get(e_comp_screen_primary_output_get(e_comp->e_comp_screen), &w, &h);
+
+   edev->mouse.dx = edev->seat->ptr.dx =
+     libinput_event_touch_get_x_transformed(event, w);
+   edev->mouse.dy = edev->seat->ptr.dy =
+     libinput_event_touch_get_y_transformed(event, h);
+
+   if (floor(edev->seat->ptr.dx) == edev->seat->ptr.ix &&
+       floor(edev->seat->ptr.dy) == edev->seat->ptr.iy)
+     {
+        return;
+     }
+
+   edev->seat->ptr.ix = edev->seat->ptr.dx;
+   edev->seat->ptr.iy = edev->seat->ptr.dy;
+
+   edev->mt_slot = libinput_event_touch_get_slot(event);
+
+   _device_handle_touch_motion_send(edev, event);
+}
+
+static void
+_device_handle_touch_up(struct libinput_device *device, struct libinput_event_touch *event)
+{
+   E_Input_Evdev *edev;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+
+   edev->mt_slot = libinput_event_touch_get_slot(event);
+   _device_handle_touch_event_send(edev, event, ECORE_EVENT_MOUSE_BUTTON_UP);
+}
+
+static void
+_device_handle_touch_frame(struct libinput_device *device EINA_UNUSED, struct libinput_event_touch *event EINA_UNUSED)
+{
+   /* DBG("Unhandled Touch Frame Event"); */
+}
+
+static void
+_e_input_aux_data_event_free(void *user_data EINA_UNUSED, void *ev)
+{
+   Ecore_Event_Axis_Update *e = (Ecore_Event_Axis_Update *)ev;
+   if (e->axis)
+     free(e->axis);
+   free(e);
+}
+
+static void
+_device_handle_touch_aux_data(struct libinput_device *device, struct libinput_event_touch_aux_data *event)
+{
+   E_Input_Evdev *edev;
+   E_Input_Backend *input;
+   Ecore_Event_Axis_Update *ev;
+   Ecore_Axis *axis;
+
+   if (libinput_event_touch_aux_data_get_type(event) != LIBINPUT_TOUCH_AUX_DATA_TYPE_PALM &&
+       libinput_event_touch_aux_data_get_value(event) > 0)
+      goto end;
+
+   if (!(edev = libinput_device_get_user_data(device))) goto end;
+   if (!(input = edev->seat->input)) goto end;
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Axis_Update))))goto end;
+
+   ev->window = (Ecore_Window)input->dev->window;
+   ev->event_window = (Ecore_Window)input->dev->window;
+   ev->root_window = (Ecore_Window)input->dev->window;
+   ev->timestamp = libinput_event_touch_aux_data_get_time(event);
+
+   axis = (Ecore_Axis *)calloc(1, sizeof(Ecore_Axis));
+   if (axis)
+     {
+        axis->label = ECORE_AXIS_LABEL_TOUCH_PALM;
+        axis->value = libinput_event_touch_aux_data_get_value(event);
+        ev->naxis = 1;
+     }
+   ev->axis = axis;
+
+   ecore_event_add(ECORE_EVENT_AXIS_UPDATE, ev, _e_input_aux_data_event_free, NULL);
+
+end:
+   ;
+}
+
+E_Input_Evdev *
+_e_input_evdev_device_create(E_Input_Seat *seat, struct libinput_device *device)
+{
+   E_Input_Evdev *edev;
+   Eina_List *devices;
+   E_Input_Backend *b_input;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(seat, NULL);
+
+   /* try to allocate space for new evdev */
+   if (!(edev = calloc(1, sizeof(E_Input_Evdev)))) return NULL;
+
+   edev->seat = seat;
+   edev->device = device;
+   edev->path = eina_stringshare_add(libinput_device_get_sysname(device));
+   edev->fd = -1;
+
+   if (edev->path)
+     {
+        devices = eeze_udev_find_by_filter("input", NULL, edev->path);
+        if (eina_list_count(devices) >= 1)
+          {
+             Eina_List *l;
+             const char *dev, *name;
+
+             EINA_LIST_FOREACH(devices, l, dev)
+               {
+                  name = eeze_udev_syspath_get_devname(dev);
+                  if (name && strstr(name, edev->path))
+                    {
+                       eina_stringshare_replace(&edev->path, eeze_udev_syspath_get_devpath(dev));
+                       break;
+                    }
+               }
+
+             EINA_LIST_FREE(devices, dev)
+               eina_stringshare_del(dev);
+          }
+     }
+
+   if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD))
+     {
+        edev->caps |= E_INPUT_SEAT_KEYBOARD;
+        _device_keyboard_setup(edev);
+     }
+
+   if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER))
+     {
+        edev->caps |= E_INPUT_SEAT_POINTER;
+
+        /* TODO: make this configurable */
+        edev->mouse.threshold = 250;
+
+        b_input = seat->input;
+        if (b_input->left_handed == EINA_TRUE)
+          {
+             if (libinput_device_config_left_handed_set(device, 1) !=
+                 LIBINPUT_CONFIG_STATUS_SUCCESS)
+               {
+                  WRN("Failed to set left hand mode about device: %s\n",
+                      libinput_device_get_name(device));
+               }
+          }
+     }
+
+   if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH))
+     {
+        int palm_code;
+        edev->caps |= E_INPUT_SEAT_TOUCH;
+        palm_code = libinput_device_touch_aux_data_get_code(LIBINPUT_TOUCH_AUX_DATA_TYPE_PALM);
+        if (libinput_device_touch_has_aux_data(device, palm_code))
+          {
+             libinput_device_touch_set_aux_data(device, palm_code);
+          }
+     }
+
+   libinput_device_set_user_data(device, edev);
+   libinput_device_ref(device);
+
+   /* configure device */
+   _device_configure(edev);
+
+   return edev;
+}
+
+void
+_e_input_evdev_device_destroy(E_Input_Evdev *edev)
+{
+   EINA_SAFETY_ON_NULL_RETURN(edev);
+
+   if (edev->caps & E_INPUT_SEAT_KEYBOARD)
+     {
+        if (edev->xkb.state) xkb_state_unref(edev->xkb.state);
+        if (edev->xkb.keymap) xkb_map_unref(edev->xkb.keymap);
+     }
+
+   if (edev->path) eina_stringshare_del(edev->path);
+   if (edev->device) libinput_device_unref(edev->device);
+   if (edev->key_remap_hash) eina_hash_free(edev->key_remap_hash);
+
+   free(edev);
+}
+
+Eina_Bool
+_e_input_evdev_event_process(struct libinput_event *event)
+{
+   struct libinput_device *device;
+   Eina_Bool ret = EINA_TRUE;
+
+   device = libinput_event_get_device(event);
+   switch (libinput_event_get_type(event))
+     {
+      case LIBINPUT_EVENT_KEYBOARD_KEY:
+        _device_handle_key(device, libinput_event_get_keyboard_event(event));
+        break;
+      case LIBINPUT_EVENT_POINTER_MOTION:
+        _device_handle_pointer_motion(device,
+                                      libinput_event_get_pointer_event(event));
+        break;
+      case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+        _device_handle_pointer_motion_absolute(device,
+                                               libinput_event_get_pointer_event(event));
+        break;
+      case LIBINPUT_EVENT_POINTER_BUTTON:
+        _device_handle_button(device, libinput_event_get_pointer_event(event));
+        break;
+      case LIBINPUT_EVENT_POINTER_AXIS:
+        _device_handle_axis(device, libinput_event_get_pointer_event(event));
+        break;
+      case LIBINPUT_EVENT_TOUCH_DOWN:
+        _device_handle_touch_down(device, libinput_event_get_touch_event(event));
+        break;
+      case LIBINPUT_EVENT_TOUCH_MOTION:
+        _device_handle_touch_motion(device,
+                                    libinput_event_get_touch_event(event));
+        break;
+      case LIBINPUT_EVENT_TOUCH_UP:
+        _device_handle_touch_up(device, libinput_event_get_touch_event(event));
+        break;
+      case LIBINPUT_EVENT_TOUCH_FRAME:
+        _device_handle_touch_frame(device, libinput_event_get_touch_event(event));
+        break;
+      case LIBINPUT_EVENT_TOUCH_AUX_DATA:
+        _device_handle_touch_aux_data(device, libinput_event_get_touch_aux_data(event));
+        break;
+      default:
+        ret = EINA_FALSE;
+        break;
+     }
+
+   return ret;
+}
+
+/**
+ * @brief Set the axis size of the given device.
+ *
+ * @param dev The device to set the axis size to.
+ * @param w The width of the axis.
+ * @param h The height of the axis.
+ *
+ * This function sets set the width @p w and height @p h of the axis
+ * of device @p dev. If @p dev is a relative input device, a width and
+ * height must set for it. If its absolute set the ioctl correctly, if
+ * not, unsupported device.
+ */
+EINTERN void
+e_input_evdev_axis_size_set(E_Input_Evdev *edev, int w, int h)
+{
+   const char *sysname;
+   float cal[6];
+   const char *device;
+   Eina_List *devices;
+   const char *vals;
+   enum libinput_config_status status;
+
+   EINA_SAFETY_ON_NULL_RETURN(edev);
+   EINA_SAFETY_ON_TRUE_RETURN((w == 0) || (h == 0));
+
+   if ((!libinput_device_config_calibration_has_matrix(edev->device)) ||
+       (libinput_device_config_calibration_get_default_matrix(edev->device, cal) != 0))
+     return;
+
+   sysname = libinput_device_get_sysname(edev->device);
+
+   devices = eeze_udev_find_by_subsystem_sysname("input", sysname);
+   if (eina_list_count(devices) < 1) return;
+
+   EINA_LIST_FREE(devices, device)
+     {
+        vals = eeze_udev_syspath_get_property(device, "WL_CALIBRATION");
+       if ((!vals) ||
+            (sscanf(vals, "%f %f %f %f %f %f",
+                    &cal[0], &cal[1], &cal[2], &cal[3], &cal[4], &cal[5]) != 6))
+          goto cont;
+
+        cal[2] /= w;
+        cal[5] /= h;
+
+        status =
+          libinput_device_config_calibration_set_matrix(edev->device, cal);
+
+        if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
+          ERR("Failed to apply calibration");
+
+cont:
+        eina_stringshare_del(device);
+        continue;
+     }
+}
+
+E_API const char *
+e_input_evdev_name_get(E_Input_Evdev *evdev)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evdev, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evdev->device, NULL);
+
+   return libinput_device_get_name(evdev->device);
+}
+
+EINTERN const char *
+e_input_evdev_sysname_get(E_Input_Evdev *evdev)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evdev, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evdev->device, NULL);
+
+   return libinput_device_get_sysname(evdev->device);
+}
+
+EINTERN Eina_Bool
+e_input_evdev_key_remap_enable(E_Input_Evdev *edev, Eina_Bool enable)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev->device, EINA_FALSE);
+
+   edev->key_remap_enabled = enable;
+
+   if (enable == EINA_FALSE && edev->key_remap_hash)
+     {
+        eina_hash_free(edev->key_remap_hash);
+        edev->key_remap_hash = NULL;
+     }
+
+   return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_input_evdev_key_remap_set(E_Input_Evdev *edev, int *from_keys, int *to_keys, int num)
+{
+   int i;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev->device, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(from_keys, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(to_keys, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(num <= 0, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(!edev->key_remap_enabled, EINA_FALSE);
+
+   if (edev->key_remap_hash == NULL)
+     edev->key_remap_hash = eina_hash_int32_new(NULL);
+
+   if (edev->key_remap_hash == NULL)
+     {
+        ERR("Failed to set remap key information : creating a hash is failed.");
+        return EINA_FALSE;
+     }
+
+   for (i = 0; i < num ; i++)
+     {
+        if (!from_keys[i] || !to_keys[i])
+          {
+             ERR("Failed to set remap key information : given arguments are invalid.");
+             return EINA_FALSE;
+          }
+     }
+
+   for (i = 0; i < num ; i++)
+     {
+        eina_hash_add(edev->key_remap_hash, &from_keys[i], (void *)(intptr_t)to_keys[i]);
+     }
+
+   return EINA_TRUE;
+}
+
+E_API int
+e_input_evdev_wheel_click_angle_get(E_Input_Evdev *dev)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dev, -1);
+   return libinput_device_config_scroll_get_wheel_click_angle(dev->device);
+}
+
+EINTERN Eina_Bool
+e_input_evdev_touch_calibration_set(E_Input_Evdev *edev, float matrix[6])
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev->device, EINA_FALSE);
+
+   if (!libinput_device_config_calibration_has_matrix(edev->device) ||
+       !libinput_device_has_capability(edev->device, LIBINPUT_DEVICE_CAP_TOUCH))
+     return EINA_FALSE;
+
+   if (libinput_device_config_calibration_set_matrix(edev->device, matrix) !=
+       LIBINPUT_CONFIG_STATUS_SUCCESS)
+     {
+        WRN("Failed to set input transformation about device: %s\n",
+            libinput_device_get_name(edev->device));
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
diff --git a/src/bin/e_input_inputs.c b/src/bin/e_input_inputs.c
new file mode 100644 (file)
index 0000000..dfbed89
--- /dev/null
@@ -0,0 +1,449 @@
+#include "e.h"
+#include "e_input_private.h"
+
+static void
+_device_close(const char *device, int fd)
+{
+   if (fd >= 0)
+     close(fd);
+}
+
+static E_Input_Seat *
+_seat_create(E_Input_Backend *input, const char *seat)
+{
+   E_Input_Seat *s;
+
+   /* try to allocate space for new seat */
+   if (!(s = calloc(1, sizeof(E_Input_Seat))))
+     return NULL;
+
+   s->input = input;
+   s->name = eina_stringshare_add(seat);
+
+   /* add this new seat to list */
+   input->dev->seats = eina_list_append(input->dev->seats, s);
+
+   ecore_event_add(E_INPUT_EVENT_SEAT_ADD, NULL, NULL, NULL);
+
+   return s;
+}
+
+static void
+_e_input_event_input_device_add_free(void *data EINA_UNUSED, void *ev)
+{
+   E_Input_Event_Input_Device_Add *e;
+
+   e = ev;
+   eina_stringshare_del(e->name);
+   eina_stringshare_del(e->sysname);
+   eina_stringshare_del(e->seatname);
+
+   free(e);
+}
+
+static void
+_e_input_event_input_device_del_free(void *data EINA_UNUSED, void *ev)
+{
+   E_Input_Event_Input_Device_Del *e;
+
+   e = ev;
+   eina_stringshare_del(e->name);
+   eina_stringshare_del(e->sysname);
+   eina_stringshare_del(e->seatname);
+
+   free(e);
+}
+
+static E_Input_Seat *
+_seat_get(E_Input_Backend *input, const char *seat)
+{
+   E_Input_Seat *s;
+   Eina_List *l;
+
+   /* search for this name in existing seats */
+   EINA_LIST_FOREACH(input->dev->seats, l, s)
+     if (!strcmp(s->name, seat))
+       return s;
+
+   return _seat_create(input, seat);
+}
+
+static void
+_ecore_event_device_info_free(void *data EINA_UNUSED, void *ev)
+{
+   Ecore_Event_Device_Info *e;
+
+   e = ev;
+   eina_stringshare_del(e->name);
+   eina_stringshare_del(e->identifier);
+   eina_stringshare_del(e->seatname);
+
+   free(e);
+}
+
+static Ecore_Device_Class
+_e_input_seat_cap_to_ecore_device_class(unsigned int cap)
+{
+   switch(cap)
+     {
+      case E_INPUT_SEAT_POINTER:
+         return ECORE_DEVICE_CLASS_MOUSE;
+      case E_INPUT_SEAT_KEYBOARD:
+         return ECORE_DEVICE_CLASS_KEYBOARD;
+      case E_INPUT_SEAT_TOUCH:
+         return ECORE_DEVICE_CLASS_TOUCH;
+      default:
+         return ECORE_DEVICE_CLASS_NONE;
+     }
+   return ECORE_DEVICE_CLASS_NONE;
+}
+
+void
+_e_input_send_device_info(unsigned int window, E_Input_Evdev *edev, Ecore_Device_Class clas, Ecore_Device_Subclass subclas, Eina_Bool flag)
+{
+   Ecore_Event_Device_Info *e;
+
+   if (!(e = calloc(1, sizeof(Ecore_Event_Device_Info)))) return;
+
+   e->name = eina_stringshare_add(libinput_device_get_name(edev->device));
+   e->identifier = eina_stringshare_add(edev->path);
+   e->seatname = eina_stringshare_add(edev->seat->name);
+   e->clas = clas;
+   e->subclas = subclas;
+   e->window = window;
+
+   if (flag)
+     ecore_event_add(ECORE_EVENT_DEVICE_ADD, e, _ecore_event_device_info_free, NULL);
+   else
+     ecore_event_add(ECORE_EVENT_DEVICE_DEL, e, _ecore_event_device_info_free, NULL);
+}
+
+static Eina_Bool
+_e_input_add_ecore_device(E_Input_Evdev *edev, Ecore_Device_Class clas)
+{
+   const Eina_List *dev_list = NULL;
+   const Eina_List *l;
+   Ecore_Device *dev = NULL;
+   const char *identifier;
+
+   if (!edev->path) return EINA_FALSE;
+
+   dev_list = ecore_device_list();
+   if (dev_list)
+     {
+        EINA_LIST_FOREACH(dev_list, l, dev)
+          {
+             if (!dev) continue;
+             identifier = ecore_device_identifier_get(dev);
+             if (!identifier) continue;
+             if ((ecore_device_class_get(dev) == clas) && (!strcmp(identifier, edev->path)))
+                return EINA_FALSE;
+          }
+     }
+
+   if(!(dev = ecore_device_add())) return EINA_FALSE;
+
+   ecore_device_name_set(dev, libinput_device_get_name(edev->device));
+   ecore_device_description_set(dev, libinput_device_get_name(edev->device));
+   ecore_device_identifier_set(dev, edev->path);
+   ecore_device_class_set(dev, clas);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_input_remove_ecore_device(E_Input_Evdev *edev, Ecore_Device_Class clas)
+{
+   const Eina_List *dev_list = NULL;
+   const Eina_List *l;
+   Ecore_Device *dev = NULL;
+   const char *identifier;
+
+   if (!edev->path) return EINA_FALSE;
+
+   dev_list = ecore_device_list();
+   if (!dev_list) return EINA_FALSE;
+   EINA_LIST_FOREACH(dev_list, l, dev)
+      {
+         if (!dev) continue;
+         identifier = ecore_device_identifier_get(dev);
+         if (!identifier) continue;
+         if ((ecore_device_class_get(dev) == clas) && (!strcmp(identifier, edev->path)))
+           {
+              ecore_device_del(dev);
+              return EINA_TRUE;
+           }
+      }
+   return EINA_FALSE;
+}
+
+void
+_e_input_device_add(unsigned int window, E_Input_Evdev *edev)
+{
+   Eina_Bool ret = EINA_FALSE;
+   Ecore_Device_Class clas;
+
+   if (edev->caps & E_INPUT_SEAT_POINTER)
+     {
+        clas = _e_input_seat_cap_to_ecore_device_class(E_INPUT_SEAT_POINTER);
+        ret = _e_input_add_ecore_device(edev, clas);
+        if (ret) _e_input_send_device_info(window, edev, clas, ECORE_DEVICE_SUBCLASS_NONE, 1);
+     }
+   if (edev->caps & E_INPUT_SEAT_KEYBOARD)
+     {
+        clas = _e_input_seat_cap_to_ecore_device_class(E_INPUT_SEAT_KEYBOARD);
+        ret = _e_input_add_ecore_device(edev, clas);
+        if (ret) _e_input_send_device_info(window, edev, clas, ECORE_DEVICE_SUBCLASS_NONE, 1);
+     }
+   if (edev->caps & E_INPUT_SEAT_TOUCH)
+     {
+        clas = _e_input_seat_cap_to_ecore_device_class(E_INPUT_SEAT_TOUCH);
+        ret = _e_input_add_ecore_device(edev, clas);
+        if (ret) _e_input_send_device_info(window, edev, clas, ECORE_DEVICE_SUBCLASS_NONE, 1);
+     }
+}
+
+void
+_e_input_device_remove(unsigned int window, E_Input_Evdev *edev)
+{
+   Eina_Bool ret = EINA_FALSE;
+   Ecore_Device_Class clas;
+
+   if (edev->caps & E_INPUT_SEAT_POINTER)
+     {
+        clas = _e_input_seat_cap_to_ecore_device_class(E_INPUT_SEAT_POINTER);
+        ret = _e_input_remove_ecore_device(edev, clas);
+        if (ret) _e_input_send_device_info(window, edev, clas, ECORE_DEVICE_SUBCLASS_NONE, 0);
+     }
+   if (edev->caps & E_INPUT_SEAT_KEYBOARD)
+     {
+        clas = _e_input_seat_cap_to_ecore_device_class(E_INPUT_SEAT_KEYBOARD);
+        ret = _e_input_remove_ecore_device(edev, clas);
+        if (ret) _e_input_send_device_info(window, edev, clas, ECORE_DEVICE_SUBCLASS_NONE, 0);
+     }
+   if (edev->caps & E_INPUT_SEAT_TOUCH)
+     {
+        clas = _e_input_seat_cap_to_ecore_device_class(E_INPUT_SEAT_TOUCH);
+        ret = _e_input_remove_ecore_device(edev, clas);
+        if (ret) _e_input_send_device_info(window, edev, clas, ECORE_DEVICE_SUBCLASS_NONE, 0);
+     }
+}
+
+static void
+_device_added(E_Input_Backend *input, struct libinput_device *device)
+{
+   struct libinput_seat *libinput_seat;
+   const char *seat_name;
+   E_Input_Seat *seat;
+   E_Input_Evdev *edev;
+   E_Input_Event_Input_Device_Add *ev;
+
+   libinput_seat = libinput_device_get_seat(device);
+   seat_name = libinput_seat_get_logical_name(libinput_seat);
+
+   /* try to get a seat */
+   if (!(seat = _seat_get(input, seat_name)))
+     {
+        ERR("Could not get matching seat: %s", seat_name);
+        return;
+     }
+
+   /* try to create a new evdev device */
+   if (!(edev = _e_input_evdev_device_create(seat, device)))
+     {
+        ERR("Failed to create new evdev device");
+        return;
+     }
+
+   edev->fd = (int)(intptr_t)eina_hash_find(input->dev->fd_hash, edev->path);
+
+   /* append this device to the seat */
+   seat->devices = eina_list_append(seat->devices, edev);
+
+   ev = calloc(1, sizeof(E_Input_Event_Input_Device_Add));
+   if (!ev)
+     {
+        return;
+     }
+
+   ev->name = eina_stringshare_add(libinput_device_get_name(device));
+   ev->sysname = eina_stringshare_add(edev->path);
+   ev->seatname = eina_stringshare_add(edev->seat->name);
+   ev->caps = edev->caps;
+
+   ecore_event_add(E_INPUT_EVENT_INPUT_DEVICE_ADD,
+                   ev,
+                   _e_input_event_input_device_add_free,
+                   NULL);
+
+   if (input->dev->window != -1)
+     _e_input_device_add(input->dev->window, edev);
+}
+
+static void
+_device_removed(E_Input_Backend *input, struct libinput_device *device)
+{
+   E_Input_Evdev *edev;
+   E_Input_Event_Input_Device_Del *ev;
+
+   /* try to get the evdev structure */
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+
+   ev = calloc(1, sizeof(E_Input_Event_Input_Device_Del));
+   if (!ev)
+     {
+        return;
+     }
+
+   ev->name = eina_stringshare_add(libinput_device_get_name(device));
+   ev->sysname = eina_stringshare_add(edev->path);
+   ev->seatname = eina_stringshare_add(edev->seat->name);
+   ev->caps = edev->caps;
+
+   ecore_event_add(E_INPUT_EVENT_INPUT_DEVICE_DEL,
+                   ev,
+                   _e_input_event_input_device_del_free,
+                   NULL);
+
+   if (input->dev->window != -1)
+     _e_input_device_remove(input->dev->window, edev);
+
+   /* remove this evdev from the seat's list of devices */
+   edev->seat->devices = eina_list_remove(edev->seat->devices, edev);
+
+   if (input->dev->fd_hash)
+     eina_hash_del_by_key(input->dev->fd_hash, edev->path);
+
+   /* tell launcher to release device */
+   if (edev->fd >= 0)
+     _device_close(edev->path, edev->fd);
+
+   /* destroy this evdev */
+   _e_input_evdev_device_destroy(edev);
+}
+
+static int
+_udev_event_process(struct libinput_event *event)
+{
+   struct libinput *libinput;
+   struct libinput_device *device;
+   E_Input_Backend *input;
+   Eina_Bool ret = EINA_TRUE;
+
+   libinput = libinput_event_get_context(event);
+   input = libinput_get_user_data(libinput);
+   device = libinput_event_get_device(event);
+
+   switch (libinput_event_get_type(event))
+     {
+      case LIBINPUT_EVENT_DEVICE_ADDED:
+        _device_added(input, device);
+        break;
+      case LIBINPUT_EVENT_DEVICE_REMOVED:
+        _device_removed(input, device);
+        break;
+      default:
+        ret = EINA_FALSE;
+     }
+
+   return ret;
+}
+
+static void
+_input_event_process(struct libinput_event *event)
+{
+   if (_udev_event_process(event)) return;
+   if (_e_input_evdev_event_process(event)) return;
+}
+
+void
+_input_events_process(E_Input_Backend *input)
+{
+   struct libinput_event *event;
+
+   while ((event = libinput_get_event(input->libinput)))
+     {
+        _input_event_process(event);
+        libinput_event_destroy(event);
+     }
+}
+
+static Eina_Bool
+_cb_input_dispatch(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
+{
+   E_Input_Backend *input;
+
+   if (!(input = data)) return EINA_TRUE;
+
+   if (libinput_dispatch(input->libinput) != 0)
+     ERR("Failed to dispatch libinput events: %m");
+
+   /* process pending events */
+   _input_events_process(input);
+
+   return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_input_enable_input(E_Input_Backend *input)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(input, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(input->libinput, EINA_FALSE);
+
+   input->fd = libinput_get_fd(input->libinput);
+
+   if (!input->hdlr)
+     {
+        input->hdlr =
+          ecore_main_fd_handler_add(input->fd, ECORE_FD_READ,
+                                    _cb_input_dispatch, input, NULL, NULL);
+     }
+
+   if (input->suspended)
+     {
+        if (libinput_resume(input->libinput) != 0)
+          goto err;
+
+        input->suspended = EINA_FALSE;
+
+        /* process pending events */
+        _input_events_process(input);
+     }
+
+   input->enabled = EINA_TRUE;
+   input->suspended = EINA_FALSE;
+
+   return EINA_TRUE;
+
+err:
+   input->enabled = EINA_FALSE;
+   if (input->hdlr)
+     ecore_main_fd_handler_del(input->hdlr);
+   input->hdlr = NULL;
+
+   return EINA_FALSE;
+}
+
+EINTERN void
+e_input_disable_input(E_Input_Backend *input)
+{
+   EINA_SAFETY_ON_NULL_RETURN(input);
+   EINA_SAFETY_ON_TRUE_RETURN(input->suspended);
+
+   /* suspend this input */
+   libinput_suspend(input->libinput);
+
+   /* process pending events */
+   _input_events_process(input);
+
+   input->suspended = EINA_TRUE;
+}
+
+E_API Eina_List *
+e_input_seat_evdev_list_get(E_Input_Seat *seat)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(seat, NULL);
+   return seat->devices;
+}
diff --git a/src/bin/e_input_private.h b/src/bin/e_input_private.h
new file mode 100644 (file)
index 0000000..10bf73f
--- /dev/null
@@ -0,0 +1,114 @@
+#ifdef E_TYPEDEFS
+
+#else
+
+#ifndef E_INPUT_PRIVIATES_H
+#define E_INPUT_PRIVIATES_H
+
+#include "e.h"
+#include "e_input.h"
+#include <libinput.h>
+#include <Eeze.h>
+
+struct xkb_keymap *cached_keymap;
+struct xkb_context *cached_context;
+
+#define E_INPUT_ENV_LIBINPUT_LOG_DISABLE "E_INPUT_LIBINPUT_LOG_DISABLE"
+#define E_INPUT_ENV_LIBINPUT_LOG_EINA_LOG "E_INPUT_LIBINPUT_LOG_EINA_LOG"
+
+struct _E_Input_Seat
+{
+   const char *name;
+   E_Input_Backend *input;
+   Eina_List *devices;
+   struct libinput_seat *seat;
+
+   struct
+     {
+        int ix, iy;
+        double dx, dy;
+        Eina_Bool swap;
+        Eina_Bool invert_x;
+        Eina_Bool invert_y;
+     } ptr;
+};
+
+struct _E_Input_Backend
+{
+   int fd;
+   E_Input_Device *dev;
+   struct libinput *libinput;
+
+   Ecore_Fd_Handler *hdlr;
+
+   Eina_Bool enabled : 1;
+   Eina_Bool suspended : 1;
+   Eina_Bool left_handed : 1;
+};
+
+struct _E_Input_Evdev
+{
+   E_Input_Seat *seat;
+   struct libinput_device *device;
+
+   const char *path;
+   int fd;
+
+   int mt_slot;
+
+   struct
+     {
+        int minx, miny, maxw, maxh;
+        double dx, dy;
+        unsigned int last, prev;
+        uint32_t threshold;
+        Eina_Bool did_double : 1;
+        Eina_Bool did_triple : 1;
+        uint32_t prev_button, last_button;
+     } mouse;
+
+   struct
+     {
+        struct xkb_keymap *keymap;
+        struct xkb_state *state;
+        xkb_mod_mask_t ctrl_mask;
+        xkb_mod_mask_t alt_mask;
+        xkb_mod_mask_t shift_mask;
+        xkb_mod_mask_t win_mask;
+        xkb_mod_mask_t scroll_mask;
+        xkb_mod_mask_t num_mask;
+        xkb_mod_mask_t caps_mask;
+        xkb_mod_mask_t altgr_mask;
+        unsigned int modifiers;
+        unsigned int depressed, latched, locked, group;
+     } xkb;
+
+     Eina_Hash *key_remap_hash;
+     Eina_Bool key_remap_enabled;
+
+   E_Input_Seat_Capabilities caps;
+
+   struct
+     {
+        struct
+          {
+             int rotation;
+             int x, y;
+             int w, h;
+          } transform;
+     } touch;
+};
+
+void _input_events_process(E_Input_Backend *input);
+E_Input_Evdev *_e_input_evdev_device_create(E_Input_Seat *seat, struct libinput_device *device);
+Eina_Bool _e_input_evdev_event_process(struct libinput_event *event);
+
+struct xkb_context * _e_input_device_cached_context_get(enum xkb_context_flags flags);
+struct xkb_keymap *_e_input_device_cached_keymap_get(struct xkb_context *ctx, const struct xkb_rule_names *names, enum xkb_keymap_compile_flags flags);
+
+
+void _e_input_evdev_device_destroy(E_Input_Evdev *evdev);
+void _e_input_pointer_motion_post(E_Input_Evdev *edev);
+
+#endif
+#endif