e_input: Do not devide translation components by output's w/h of a matrix
[platform/upstream/enlightenment.git] / src / bin / e_input_evdev.c
index 26bb651..1386b92 100644 (file)
@@ -1,14 +1,38 @@
-#include "e.h"
-#include "e_input_private.h"
+#include "e_input_intern.h"
+#include "e_input_log.h"
+#include "e_input_event.h"
+#include "e_keyrouter_intern.h"
+#include "e_devicemgr_intern.h"
+#include "e_device_intern.h"
+#include "e_comp_screen_intern.h"
+#include "e_output_intern.h"
+
+#include <glib.h>
+#include <ctype.h>
+
+#define G_LIST_GET_DATA(list) ((list) ? (((GList *)(list))->data) : NULL)
 
 static void  _device_modifiers_update(E_Input_Evdev *edev);
+static void  _device_configured_size_get(E_Input_Evdev *edev, int *x, int *y, int *w, int *h);
+static void  _device_output_assign(E_Input_Evdev *edev, E_Input_Seat_Capabilities cap);
 
-static void
+void
 _device_calibration_set(E_Input_Evdev *edev)
 {
    E_Output *output;
    int w = 0, h = 0;
    int temp;
+   E_Comp_Config *comp_conf;
+
+   if (e_comp->e_comp_screen->num_outputs > 1) //multiple outputs
+     {
+        comp_conf = e_comp_config_get();
+        if (comp_conf && (comp_conf->input_output_assign_policy == 1)) //use output-assignment policy
+          {
+             _device_output_assign(edev, E_INPUT_SEAT_POINTER);
+             _device_output_assign(edev, E_INPUT_SEAT_TOUCH);
+          }
+     }
 
    output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
    e_output_size_get(output, &w, &h);
@@ -19,7 +43,7 @@ _device_calibration_set(E_Input_Evdev *edev)
         edev->mouse.maxw = w;
         edev->mouse.maxh = h;
 
-        if (libinput_device_has_capability(edev->device, LIBINPUT_DEVICE_CAP_POINTER))
+        if (edev->caps & E_INPUT_SEAT_POINTER)
           {
              edev->seat->ptr.dx = (double)(w / 2);
              edev->seat->ptr.dy = (double)(h / 2);
@@ -43,51 +67,129 @@ _device_calibration_set(E_Input_Evdev *edev)
 
 //LCOV_EXCL_START
 #ifdef _F_E_INPUT_ENABLE_DEVICE_CALIBRATION_
-   const char *sysname;
    float cal[6];
-   const char *device;
-   Eina_List *devices;
 
    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;
-
 #ifdef _F_E_INPUT_USE_WL_CALIBRATION_
    const char *vals;
    enum libinput_config_status status;
+   struct udev_device *udev_device = NULL;
 
-   EINA_LIST_FREE(devices, device)
+   udev_device = libinput_device_get_udev_device(edev->device);
+   if (!udev_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;
+        ERR("no udev_device");
+        return;
+     }
 
-        cal[2] /= w;
-        cal[5] /= h;
+   vals = udev_device_get_property_value(udev_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))
+     {
+        udev_device_unref(udev_device);
+        return;
+     }
+   udev_device_unref(udev_device);
 
-        status =
-          libinput_device_config_calibration_set_matrix(edev->device, cal);
+   ELOGF("E_INPUT_EVDEV", "calibration_set cal[%lf %lf %lf %lf %lf %lf] (%d x %d)",
+         NULL, cal[0], cal[1], cal[2], cal[3], cal[4], cal[5], w, h);
 
-        if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
-          ERR("Failed to apply calibration");
+   status =
+     libinput_device_config_calibration_set_matrix(edev->device, cal);
 
-cont:
-        eina_stringshare_del(device);
-        continue;
-     }
+   if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
+     ERR("Failed to apply calibration");
 #endif//_F_E_INPUT_USE_WL_CALIBRATION_
 #endif//_F_E_INPUT_ENABLE_DEVICE_CALIBRATION_
 //LCOV_EXCL_STOP
 }
 
 static void
+_device_output_assign(E_Input_Evdev *edev, E_Input_Seat_Capabilities cap)
+{
+   int last_output_idx;
+   E_Input_Evdev *ed;
+   Eina_List *l;
+   Eina_Bool need_assign_output = EINA_FALSE;
+   const char *output_name;
+   E_Output *output;
+
+   if (!(edev->caps & cap)) return;
+   if (edev->output_name) return; //already assigned
+   if (e_comp->e_comp_screen->num_outputs <= 1) return;
+
+   last_output_idx = e_comp->e_comp_screen->num_outputs - 1;
+   EINA_LIST_FOREACH(edev->seat->devices, l, ed)
+     {
+        if (!(ed->caps & cap)) continue;
+        if (ed == edev) continue;
+        if (ed->output_name)
+          {
+             need_assign_output = EINA_FALSE;
+             break;
+          }
+          need_assign_output = EINA_TRUE;
+     }
+   if (need_assign_output)
+     {
+        output = e_output_find_by_index(last_output_idx);
+        if (!output || !output->info.connected) return;
+        output_name = e_output_output_id_get(output);
+        if (output_name) edev->output_name = eina_stringshare_add(output_name);
+        ELOGF("E_INPUT_EVDEV", "Device is assigned to output:%s", NULL, output_name);
+     }
+}
+
+static void
+_device_touch_count_update(E_Input_Evdev *edev)
+{
+   unsigned int device_touch_count = 0;
+   static unsigned int _max_device_touch_count = 0;
+
+   E_Input *ei = e_input_get();
+   EINA_SAFETY_ON_NULL_RETURN(ei);
+
+   device_touch_count = libinput_device_touch_get_touch_count(edev->device);
+
+   if (_max_device_touch_count < device_touch_count)
+     _max_device_touch_count = device_touch_count;
+
+   if (e_config->configured_max_touch.use)
+     {
+        if (_max_device_touch_count > 0 && e_config->configured_max_touch.count > _max_device_touch_count)
+          {
+             ELOGF("E_INPUT_EVDEV_TOUCH", "Touch max count(%d) must be less or equal to device's touch count(%d) !\nTouch max count has been shrinken to %d.\n",
+                         NULL, e_config->configured_max_touch.count, _max_device_touch_count, _max_device_touch_count);
+             ei->touch_max_count = _max_device_touch_count;
+          }
+        else
+          {
+             if (ei->touch_max_count != e_config->configured_max_touch.count)
+             {
+                ELOGF("E_INPUT_EVDEV_TOUCH", "Touch_max_count has been updated to %d -> %d.\n",
+                           NULL, ei->touch_max_count, e_config->configured_max_touch.count);
+                ei->touch_max_count = e_config->configured_max_touch.count;
+             }
+          }
+     }
+   else
+     {
+        if (ei->touch_max_count < _max_device_touch_count)
+          {
+             ELOGF("E_INPUT_EVDEV_TOUCH", "Touch_max_count has been updated to %d -> %d.\n", NULL,
+                   ei->touch_max_count, _max_device_touch_count);
+             ei->touch_max_count = _max_device_touch_count;
+          }
+     }
+
+   ELOGF("E_INPUT_EVDEV_TOUCH", "Touch max count is %d.\n", NULL, ei->touch_max_count);
+}
+
+static void
 _device_configure(E_Input_Evdev *edev)
 {
    if (libinput_device_config_tap_get_finger_count(edev->device) > 0)
@@ -105,6 +207,7 @@ static void
 _device_keyboard_setup(E_Input_Evdev *edev)
 {
    E_Input_Backend *input;
+   xkb_mod_index_t xkb_idx;
 
    if ((!edev) || (!edev->seat)) return;
    if (!(input = edev->seat->input)) return;
@@ -125,22 +228,53 @@ _device_keyboard_setup(E_Input_Evdev *edev)
         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");
+   xkb_idx = xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_CTRL);
+   if (xkb_idx != XKB_MOD_INVALID)
+     edev->xkb.ctrl_mask = 1 << xkb_idx;
+   else
+     edev->xkb.ctrl_mask = 0;
+
+   xkb_idx = xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_ALT);
+   if (xkb_idx != XKB_MOD_INVALID)
+     edev->xkb.alt_mask = 1 << xkb_idx;
+   else
+     edev->xkb.alt_mask = 0;
+
+   xkb_idx = xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_SHIFT);
+   if (xkb_idx != XKB_MOD_INVALID)
+     edev->xkb.shift_mask = 1 << xkb_idx;
+   else
+     edev->xkb.shift_mask = 0;
+
+   xkb_idx = xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_LOGO);
+   if (xkb_idx != XKB_MOD_INVALID)
+     edev->xkb.win_mask = 1 << xkb_idx;
+   else
+     edev->xkb.win_mask = 0;
+
+   xkb_idx = xkb_map_mod_get_index(edev->xkb.keymap, XKB_LED_NAME_SCROLL);
+   if (xkb_idx != XKB_MOD_INVALID)
+     edev->xkb.scroll_mask = 1 << xkb_idx;
+   else
+     edev->xkb.scroll_mask = 0;
+
+   xkb_idx = xkb_map_mod_get_index(edev->xkb.keymap, XKB_LED_NAME_NUM);
+   if (xkb_idx != XKB_MOD_INVALID)
+     edev->xkb.num_mask = 1 << xkb_idx;
+   else
+     edev->xkb.num_mask = 0;
+
+   xkb_idx = xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_CAPS);
+   if (xkb_idx != XKB_MOD_INVALID)
+     edev->xkb.caps_mask = 1 << xkb_idx;
+   else
+     edev->xkb.caps_mask = 0;
+
+   xkb_idx = xkb_map_mod_get_index(edev->xkb.keymap, "ISO_Level3_Shift");
+   if (xkb_idx != XKB_MOD_INVALID)
+     edev->xkb.altgr_mask = 1 << xkb_idx;
+   else
+     edev->xkb.altgr_mask = 0;
 }
 
 static int
@@ -224,15 +358,15 @@ _device_modifiers_update_device(E_Input_Evdev *edev, E_Input_Evdev *from)
 static void
 _device_modifiers_update(E_Input_Evdev *edev)
 {
+   Eina_List *l;
+   E_Input_Evdev *ed;
+
    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;
@@ -258,7 +392,36 @@ _device_remapped_key_get(E_Input_Evdev *edev, int code)
    return code;
 }
 
-E_API Ecore_Device *
+EINTERN E_Device *
+e_input_evdev_get_e_device(const char *path, Ecore_Device_Class clas)
+{
+   const GList *dev_list = NULL;
+   const GList *l;
+   E_Device *dev = NULL;
+   const char *identifier;
+
+   if (!path) return NULL;
+
+   dev_list = e_device_list_get();
+   if (!dev_list) return NULL;
+
+   l = dev_list;
+   while (l)
+     {
+        dev = l->data;
+        if (!dev) continue;
+        identifier = e_device_identifier_get(dev);
+        if (!identifier) continue;
+        if ((e_device_class_get(dev) == clas) && !(strcmp(identifier, path)))
+          return dev;
+
+        l = g_list_next(l);
+     }
+
+   return NULL;
+}
+
+EINTERN Ecore_Device *
 e_input_evdev_get_ecore_device(const char *path, Ecore_Device_Class clas)
 {
    const Eina_List *dev_list = NULL;
@@ -282,6 +445,65 @@ e_input_evdev_get_ecore_device(const char *path, Ecore_Device_Class clas)
 }
 
 static void
+_e_input_event_mouse_move_cb_free(void *data EINA_UNUSED, void *event)
+{
+   Ecore_Event_Mouse_Move *ev = event;
+
+   if (ev->dev) ecore_device_unref(ev->dev);
+
+   free(ev);
+}
+
+static void
+_e_input_event_mouse_relative_move_cb_free(void *data EINA_UNUSED, void *event)
+{
+   Ecore_Event_Mouse_Relative_Move *ev = event;
+
+   if (ev->dev) ecore_device_unref(ev->dev);
+
+   free(ev);
+}
+
+static void
+_e_input_event_mouse_wheel_cb_free(void *data EINA_UNUSED, void *event)
+{
+   Ecore_Event_Mouse_Wheel *ev = event;
+
+   if (ev->dev) ecore_device_unref(ev->dev);
+
+   free(ev);
+}
+
+static void
+_e_input_event_mouse_button_cb_free(void *data EINA_UNUSED, void *event)
+{
+   Ecore_Event_Mouse_Button *ev = event;
+
+   if (ev->dev) ecore_device_unref(ev->dev);
+
+   free(ev);
+}
+
+static void
+_e_input_event_key_cb_free(void *data EINA_UNUSED, void *event)
+{
+   Ecore_Event_Key *ev = event;
+
+   if (e_input_thread_mode_get())
+     {
+        if (ev->dev) g_object_unref(ev->dev);
+     }
+   else
+     {
+        if (ev->dev) ecore_device_unref(ev->dev);
+     }
+
+   if (ev->data) E_FREE(ev->data);
+
+   free(ev);
+}
+
+static void
 _device_handle_key(struct libinput_device *device, struct libinput_event_keyboard *event)
 {
    E_Input_Evdev *edev;
@@ -292,9 +514,19 @@ _device_handle_key(struct libinput_device *device, struct libinput_event_keyboar
    enum libinput_key_state state;
    int key_count;
    xkb_keysym_t sym = XKB_KEY_NoSymbol;
-   char key[256], keyname[256], compose_buffer[256];
+   char key[256] = {0, }, keyname[256] = {0, }, compose_buffer[256] = {0, };
    Ecore_Event_Key *e;
    char *tmp = NULL, *compose = NULL;
+   E_Keyrouter_Event_Data *key_data;
+   Ecore_Device *ecore_dev = NULL, *data;
+   E_Device *e_dev = NULL, *e_dev_data;
+   Eina_List *l = NULL, *l_next = NULL;
+   GList *glist = NULL;
+   E_Comp_Config *comp_conf = NULL;
+   int *pressed_keycode = NULL, *idata = NULL;
+   Eina_Bool dup_found = EINA_FALSE;
+   const char *device_name = NULL;
+   Ecore_Device_Subclass device_subclas = ECORE_DEVICE_SUBCLASS_NONE;
 
    if (!(edev = libinput_device_get_user_data(device)))
      {
@@ -306,12 +538,131 @@ _device_handle_key(struct libinput_device *device, struct libinput_event_keyboar
         return;
      }
 
+   if (!e_input_thread_mode_get())
+     {
+        if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+        else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
+          {
+             EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+               {
+                  if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_KEYBOARD)
+                    {
+                       ecore_dev = data;
+                       break;
+                    }
+               }
+          }
+        else
+          {
+             edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_KEYBOARD);
+             ecore_dev = edev->ecore_dev;
+          }
+
+        if (!ecore_dev)
+          {
+             ERR("Failed to get source ecore device from event !\n");
+             return;
+          }
+
+        device_name = ecore_device_name_get(ecore_dev);
+        device_subclas = ecore_device_subclass_get(ecore_dev);
+     }
+   else
+     {
+        if (edev->e_dev) e_dev = edev->e_dev;
+        else if (edev->e_dev_list && g_list_length(edev->e_dev_list) > 0)
+          {
+             glist = edev->e_dev_list;
+             while (glist)
+               {
+                  e_dev_data = glist->data;
+                  if (e_device_class_get(e_dev_data) == ECORE_DEVICE_CLASS_KEYBOARD)
+                    {
+                       e_dev = e_dev_data;
+                       break;
+                    }
+
+                  glist = g_list_next(glist);
+               }
+          }
+        else
+          {
+             edev->e_dev = e_input_evdev_get_e_device(edev->path, ECORE_DEVICE_CLASS_KEYBOARD);
+             e_dev = edev->e_dev;
+          }
+
+        if (!e_dev)
+          {
+             ERR("Failed to get source e device from event !\n");
+             return;
+          }
+
+        device_name = e_device_name_get(e_dev);
+        device_subclas = e_device_subclass_get(e_dev);
+     }
+
    timestamp = libinput_event_keyboard_get_time(event);
    code = libinput_event_keyboard_get_key(event);
-   code = _device_remapped_key_get(edev, code) + 8;
+   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);
 
+   if (state == LIBINPUT_KEY_STATE_PRESSED)
+     {
+        if ((edev->seat->dev->blocked & E_INPUT_SEAT_KEYBOARD) ||
+            (edev->seat->dev->server_blocked & E_INPUT_SEAT_KEYBOARD))
+          {
+             void *blocked_client = atomic_load(&edev->seat->dev->blocked_client);
+             ELOGF("Key", "Press (keycode: %d, device: %s) is blocked by %p, server: 0x%x", NULL,
+                   code, device_name, blocked_client,
+                   edev->seat->dev->server_blocked);
+             return;
+          }
+
+        /* FIXME: Currently to maintain press/release event pair during input block,
+         *        used Eina_List and this is method used in devicemgr module.
+         *        But we need to consider which way is better to maintain key press/release pair.
+         */
+
+        EINA_LIST_FOREACH(edev->xkb.pressed_keys, l, idata)
+          {
+             if (*idata == code)
+               {
+                  dup_found = EINA_TRUE;
+                  break;
+               }
+          }
+        if (!dup_found)
+          {
+             pressed_keycode = E_NEW(int, 1);
+             EINA_SAFETY_ON_NULL_RETURN(pressed_keycode);
+             *pressed_keycode = code;
+
+             edev->xkb.pressed_keys = eina_list_append(edev->xkb.pressed_keys, pressed_keycode);
+          }
+     }
+   else
+     {
+        dup_found = EINA_FALSE;
+        EINA_LIST_FOREACH_SAFE(edev->xkb.pressed_keys, l, l_next, idata)
+          {
+             if (code == *idata)
+               {
+                  edev->xkb.pressed_keys = eina_list_remove_list(edev->xkb.pressed_keys, l);
+                  E_FREE(idata);
+                  dup_found = EINA_TRUE;
+                  break;
+               }
+          }
+        if (!dup_found)
+          {
+             void *blocked_client = atomic_load(&edev->seat->dev->blocked_client);
+             ELOGF("Key", "Release (keycode: %d, device: %s) is blocked by %p", NULL,
+                   code, device_name, blocked_client);
+             return;
+          }
+     }
+
    /* 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)))
@@ -319,22 +670,45 @@ _device_handle_key(struct libinput_device *device, struct libinput_event_keyboar
         return;
      }
 
+   e_input_keyboard_grab_key_cb func = e_input_keyboard_grab_key_handler_get();
+   if (func)
+     {
+        if (e_devicemgr_keyboard_grab_subtype_is_grabbed(device_subclas))
+          {
+             if (!e_input_thread_mode_get())
+               func(code, state, timestamp, ecore_dev);
+             else
+               func(code, state, timestamp, e_dev);
+             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));
+   if (nsyms == 1) sym = syms[0];
 
-   memset(keyname, 0, sizeof(keyname));
-   memcpy(keyname, key, sizeof(keyname));
+   /* If no keysym was found, name it "Keycode-NNN" */
+   if (sym == XKB_KEY_NoSymbol)
+     snprintf(key, sizeof(key), "Keycode-%u", code);
+   else
+     {
+        /* get the keyname for this sym */
+        xkb_keysym_get_name(sym, key, sizeof(key));
+     }
 
-   if (keyname[0] == '\0')
-     snprintf(keyname, sizeof(keyname), "Keycode-%u", code);
+   if (key[0] == '\0')
+     {
+        /* If no keyname was found, name it "Keycode-NNN" */
+        snprintf(keyname, sizeof(keyname), "Keycode-%u", code);
+     }
+   else
+     {
+        memcpy(keyname, key, sizeof(keyname));
+     }
 
    /* if shift is active, we need to transform the key to lower */
    if (xkb_state_mod_index_is_active(edev->xkb.state,
@@ -346,7 +720,6 @@ _device_handle_key(struct libinput_device *device, struct libinput_event_keyboar
           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)))
      {
@@ -366,6 +739,14 @@ _device_handle_key(struct libinput_device *device, struct libinput_event_keyboar
               ((compose[0] != '\0') ? strlen(compose) : 0) + 3);
    if (!e)
      {
+        E_FREE(tmp);
+        return;
+     }
+   key_data = E_NEW(E_Keyrouter_Event_Data, 1);
+   if (!key_data)
+     {
+        E_FREE(tmp);
+        E_FREE(e);
         return;
      }
 
@@ -384,17 +765,41 @@ _device_handle_key(struct libinput_device *device, struct libinput_event_keyboar
    e->timestamp = timestamp;
    e->same_screen = 1;
    e->keycode = code;
-   e->data = NULL;
+   e->data = key_data;
 
    _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);
+   comp_conf = e_comp_config_get();
+
+   if (comp_conf && comp_conf->input_log_enable)
+     ELOGF("Key", "%s (keyname: %s, keycode: %d, timestamp: %u, device: %s)", NULL, state?"Press":"Release", e->keyname, e->keycode, e->timestamp, device_name);
+
+   if (e_config->key_input_ttrace_enable)
+     {
+        TRACE_INPUT_BEGIN(ECORE_EVENT_KEY:%s:%s:%u:%lld, state ? "PRESS" : "RELEASE", e->keyname, timestamp, (long long unsigned int)libinput_event_keyboard_get_time_usec(event));
+        ELOGF("INPUT", "ECORE_EVENT_KEY:%s:%s:%u:%lld|B|", NULL, state ? "PRESS" : "RELEASE", e->keyname, timestamp, (long long unsigned int)libinput_event_keyboard_get_time_usec(event));
+     }
+
+   _e_input_key_event_list_add(e);
+
+   if (e_input_thread_mode_get())
+     {
+        e->dev = (Eo *)g_object_ref(e_dev);
+        e_input_event_add(input->event_source, state ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP, e, _e_input_event_key_cb_free, NULL);
+     }
    else
-     ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL);
+     {
+        e->dev = ecore_device_ref(ecore_dev);
+        ecore_event_add(state ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP, e, _e_input_event_key_cb_free, NULL);
+     }
+
+   if (e_config->key_input_ttrace_enable)
+     {
+        TRACE_INPUT_END();
+        ELOGF("INPUT", "ECORE_EVENT_KEY|E|", NULL);
+     }
 
    if (tmp) free(tmp);
 }
@@ -404,20 +809,64 @@ _device_pointer_motion(E_Input_Evdev *edev, struct libinput_event_pointer *event
 {
    E_Input_Backend *input;
    Ecore_Event_Mouse_Move *ev;
+   Ecore_Device *ecore_dev = NULL, *data, *detent_data = NULL;
+   Eina_List *l;
+   int x = 0, y = 0, w = 0, h = 0;
 
    if (!(input = edev->seat->input)) return;
 
+   ecore_thread_main_loop_begin();
+
+   if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+   else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
+     {
+        EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+          {
+             if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_MOUSE)
+               {
+                  ecore_dev = data;
+                  break;
+               }
+             else if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_NONE)
+               {
+                  detent_data = data;
+               }
+          }
+        if (!ecore_dev && e_devicemgr_detent_is_detent(libinput_device_get_name(edev->device)))
+          {
+             ecore_dev = detent_data;
+          }
+     }
+   else
+     {
+        edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_MOUSE);
+        ecore_dev = edev->ecore_dev;
+     }
+
+   if (!ecore_dev)
+     {
+        ERR("Failed to get source ecore device from event !\n");
+        goto end;
+     }
+   else if ((detent_data == ecore_dev) || e_devicemgr_detent_is_detent(ecore_device_name_get(ecore_dev)))
+     {
+        /* Do not process detent device's move events. */
+        goto end;
+     }
+
    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);
+   _device_configured_size_get(edev, &x, &y, &w, &h);
 
-   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);
+   if (edev->seat->ptr.ix < x)
+     edev->seat->ptr.dx = edev->seat->ptr.ix = x;
+   else if (edev->seat->ptr.ix >= (x + w))
+     edev->seat->ptr.dx = edev->seat->ptr.ix = (x + w - 1);
+
+   if (edev->seat->ptr.iy < y)
+     edev->seat->ptr.dy = edev->seat->ptr.iy = y;
+   else if (edev->seat->ptr.iy >= (y + h))
+     edev->seat->ptr.dy = edev->seat->ptr.iy = (y + h - 1);
 
    edev->mouse.dx = edev->seat->ptr.dx;
    edev->mouse.dy = edev->seat->ptr.dy;
@@ -446,9 +895,13 @@ _device_pointer_motion(E_Input_Evdev *edev, struct libinput_event_pointer *event
    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);
+   ev->dev = ecore_device_ref(ecore_dev);
+
+   ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, _e_input_event_mouse_move_cb_free, NULL);
+
+end:
+   ecore_thread_main_loop_end();
 }
 
 void
@@ -458,46 +911,157 @@ _e_input_pointer_motion_post(E_Input_Evdev *edev)
 }
 
 static void
-_device_handle_pointer_motion(struct libinput_device *device, struct libinput_event_pointer *event)
+_device_pointer_relative_motion(E_Input_Evdev *edev, struct libinput_event_pointer *event, double dx[2], double dy[2])
 {
-   E_Input_Evdev *edev;
-   double dx, dy, temp;
+   E_Input_Backend *input;
+   Ecore_Event_Mouse_Relative_Move *ev;
+   Ecore_Device *ecore_dev = NULL, *data, *detent_data = NULL;
+   Eina_List *l;
+   E_Comp_Config *comp_conf;
 
-   if (!(edev = libinput_device_get_user_data(device)))
-     {
-        return;
-     }
+   if (!(input = edev->seat->input)) return;
 
-   dx = libinput_event_pointer_get_dx(event);
-   dy = libinput_event_pointer_get_dy(event);
+   ecore_thread_main_loop_begin();
 
-   if (edev->seat->ptr.swap)
+   if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+   else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
+     {
+        EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+          {
+             if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_MOUSE)
+               {
+                  ecore_dev = data;
+                  break;
+               }
+             else if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_NONE)
+               {
+                  detent_data = data;
+               }
+          }
+        if (!ecore_dev && e_devicemgr_detent_is_detent(libinput_device_get_name(edev->device)))
+          {
+             ecore_dev = detent_data;
+          }
+     }
+   else
      {
-         temp = dx;
-         dx = dy;
-         dy = temp;
+        edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_MOUSE);
+        ecore_dev = edev->ecore_dev;
      }
-   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)
+   if (!ecore_dev)
      {
-        return;
+        ERR("Failed to get source ecore device from event !\n");
+        goto end;
+     }
+   else if ((detent_data == ecore_dev) || e_devicemgr_detent_is_detent(ecore_device_name_get(ecore_dev)))
+     {
+        /* Do not process detent device's move events. */
+        goto end;
      }
 
-   edev->seat->ptr.ix = edev->seat->ptr.dx;
-   edev->seat->ptr.iy = edev->seat->ptr.dy;
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Relative_Move)))) return;
+
+   ev->window = (Ecore_Window)input->dev->window;
+   ev->event_window = (Ecore_Window)input->dev->window;
+   if (event) ev->timestamp = libinput_event_pointer_get_time(event);
+
+   ev->modifiers = edev->xkb.modifiers;
+
+   ev->dx = (int)dx[0];
+   ev->dy = (int)dy[0];
+   ev->dx_unaccel = (int)dx[1];
+   ev->dy_unaccel = (int)dy[1];
+
+   ev->dev = ecore_device_ref(ecore_dev);
+
+   comp_conf = e_comp_config_get();
+   if (comp_conf && comp_conf->input_log_enable)
+     ELOGF("Mouse", "Relative Move (time: %d, dx: %d, dy: %d, unaccel(%d, %d) device: %s)", NULL, ev->timestamp, ev->dx, ev->dy, ev->dx_unaccel, ev->dy_unaccel, ecore_device_name_get(ev->dev));
+
+   ecore_event_add(ECORE_EVENT_MOUSE_RELATIVE_MOVE, ev, _e_input_event_mouse_relative_move_cb_free, NULL);
+
+end:
+   ecore_thread_main_loop_end();
+}
+
+static void
+_device_pointer_motion_send(E_Input_Evdev *edev, struct libinput_event_pointer *event, double dx[2], double dy[2])
+{
+   e_input_relative_motion_cb func = e_input_relative_motion_handler_get();
+   if (func)
+     {
+        //func(dx, dy, time_us);
+        _device_pointer_relative_motion(edev, event, dx, dy);
+     }
+   else
+     {
+        double seat_dx, seat_dy, temp;
+        if (edev->disable_acceleration)
+          {
+              seat_dx = dx[1];
+              seat_dy = dy[1];
+          }
+        else
+          {
+              seat_dx = dx[0];
+              seat_dy = dy[0];
+          }
+
+        if (edev->seat->ptr.swap)
+          {
+              temp = seat_dx;
+              seat_dx = seat_dy;
+              seat_dy = temp;
+          }
+        if (edev->seat->ptr.invert_x)
+          seat_dx *= -1;
+        if (edev->seat->ptr.invert_y)
+          seat_dy *= -1;
+
+        edev->seat->ptr.dx += seat_dx;
+        edev->seat->ptr.dy += seat_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;
+
+        if ((edev->seat->dev->blocked & E_INPUT_SEAT_POINTER) ||
+            (edev->seat->dev->server_blocked & E_INPUT_SEAT_POINTER))
+          {
+              return;
+          }
+
+        _device_pointer_motion(edev, event);
+     }
+}
+
+static void
+_device_handle_pointer_motion(struct libinput_device *device, struct libinput_event_pointer *event)
+{
+   E_Input_Evdev *edev;
+   double delta_x[2]; /* delta_x[0] for accelerated, delta_x[1] for unaccelerated */
+   double delta_y[2]; /* delta_y[0] for accelerated, delta_y[1] for unaccelerated */
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+
+   delta_x[0] = libinput_event_pointer_get_dx(event);
+   delta_x[1] = libinput_event_pointer_get_dx_unaccelerated(event);
+   delta_y[0] = libinput_event_pointer_get_dy(event);
+   delta_y[1] = libinput_event_pointer_get_dy_unaccelerated(event);
 
-  _device_pointer_motion(edev, event);
+   _device_pointer_motion_send(edev, event, &delta_x[0], &delta_y[0]);
 }
 
 static void
@@ -526,6 +1090,13 @@ _device_handle_pointer_motion_absolute(struct libinput_device *device, struct li
 
    edev->seat->ptr.ix = edev->seat->ptr.dx;
    edev->seat->ptr.iy = edev->seat->ptr.dy;
+
+   if ((edev->seat->dev->blocked & E_INPUT_SEAT_POINTER) ||
+       (edev->seat->dev->server_blocked & E_INPUT_SEAT_POINTER))
+     {
+        return;
+     }
+
    _device_pointer_motion(edev, event);
 }
 
@@ -537,6 +1108,9 @@ _device_handle_button(struct libinput_device *device, struct libinput_event_poin
    Ecore_Event_Mouse_Button *ev;
    enum libinput_button_state state;
    uint32_t button, timestamp;
+   Ecore_Device *ecore_dev = NULL, *detent_data = NULL, *data;
+   Eina_List *l;
+   E_Comp_Config *comp_conf = NULL;
 
    if (!(edev = libinput_device_get_user_data(device)))
      {
@@ -547,9 +1121,38 @@ _device_handle_button(struct libinput_device *device, struct libinput_event_poin
         return;
      }
 
-   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Button))))
+   ecore_thread_main_loop_begin();
+
+   if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+   else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
      {
-        return;
+        EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+          {
+             if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_MOUSE)
+               {
+                  ecore_dev = data;
+                  break;
+               }
+             else if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_NONE)
+               {
+                  detent_data = data;
+               }
+          }
+        if (!ecore_dev && e_devicemgr_detent_is_detent(libinput_device_get_name(edev->device)))
+          {
+             ecore_dev = detent_data;
+          }
+     }
+   else
+     {
+        edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_MOUSE);
+        ecore_dev = edev->ecore_dev;
+     }
+
+   if (!ecore_dev)
+     {
+        ERR("Failed to get source ecore device from event !\n");
+        goto end;
      }
 
    state = libinput_event_pointer_get_button_state(event);
@@ -560,6 +1163,41 @@ _device_handle_button(struct libinput_device *device, struct libinput_event_poin
    if (button == 3) button = 2;
    else if (button == 2) button = 3;
 
+   void *blocked_client = atomic_load(&edev->seat->dev->blocked_client);
+
+   if (state)
+     {
+        if ((edev->seat->dev->blocked & E_INPUT_SEAT_POINTER) ||
+            (edev->seat->dev->server_blocked & E_INPUT_SEAT_POINTER))
+          {
+
+             ELOGF("Mouse", "Button Press (btn: %d, device: %s) is blocked by %p, server: 0x%x", NULL,
+                   button, ecore_device_name_get(ecore_dev), blocked_client,
+                   edev->seat->dev->server_blocked);
+             goto end;
+          }
+        else
+          {
+             edev->mouse.pressed_button |= (1 << button);
+          }
+     }
+   else
+     {
+        if (!(edev->mouse.pressed_button & (1 << button)))
+          {
+             ELOGF("Mouse", "Button Release (btn: %d, device: %s) is blocked by %p, server: 0x%x", NULL,
+                   button, ecore_device_name_get(ecore_dev), blocked_client,
+                   edev->seat->dev->server_blocked);
+             goto end;
+          }
+        edev->mouse.pressed_button &= ~(1 << button);
+     }
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Button))))
+     {
+        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;
@@ -584,7 +1222,7 @@ _device_handle_button(struct libinput_device *device, struct libinput_event_poin
    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);
+   ev->dev = ecore_device_ref(ecore_dev);
 
    if (state)
      {
@@ -621,10 +1259,60 @@ _device_handle_button(struct libinput_device *device, struct libinput_event_poin
    if (edev->mouse.did_triple)
      ev->triple_click = 1;
 
+   comp_conf = e_comp_config_get();
+   if (comp_conf && comp_conf->input_log_enable)
+     ELOGF("Mouse", "Button %s (btn: %d, device: %s)", NULL, state?"Press":"Release", button, ecore_device_name_get(ev->dev));
+
    if (state)
-     ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
+     ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, _e_input_event_mouse_button_cb_free, NULL);
    else
-     ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
+     ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, _e_input_event_mouse_button_cb_free, NULL);
+
+end:
+   ecore_thread_main_loop_end();
+}
+
+#if !LIBINPUT_HAVE_SCROLL_VALUE_V120
+static int
+_axis_value_get(struct libinput_event_pointer *pointer_event, enum libinput_pointer_axis axis)
+{
+   enum libinput_pointer_axis_source source;
+   double value = 0.0, value_discrete = 0.0;
+   int ret = 0;
+   E_Comp_Config *comp_conf = NULL;
+
+   comp_conf = e_comp_config_get();
+   source = libinput_event_pointer_get_axis_source(pointer_event);
+   switch (source)
+     {
+      case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
+        value_discrete = libinput_event_pointer_get_axis_value_discrete(pointer_event, axis);
+        value = libinput_event_pointer_get_axis_value(pointer_event, axis);
+        if (comp_conf && comp_conf->input_log_enable)
+          {
+             ELOGF("Axis", "SOURCE_WHEEL discrete: %lf (cf. value: %lf)", NULL, value_discrete, value);
+          }
+        ret = (int)value_discrete;
+        break;
+      case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
+      case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
+        value = libinput_event_pointer_get_axis_value(pointer_event, axis);
+        if (comp_conf && comp_conf->input_log_enable)
+          {
+             ELOGF("Axis", "SOURCE_FINGER/CONTINUOUS value: %lf", NULL, value);
+          }
+        if (value >= E_INPUT_FINGER_SCROLL_THRESHOLD)
+          ret = 1;
+        else if (value <= E_INPUT_FINGER_SCROLL_THRESHOLD * (-1))
+          ret = -1;
+        else
+          ret = 0;
+        break;
+      default:
+        break;
+     }
+
+   return ret;
 }
 
 static void
@@ -635,6 +1323,10 @@ _device_handle_axis(struct libinput_device *device, struct libinput_event_pointe
    Ecore_Event_Mouse_Wheel *ev;
    uint32_t timestamp;
    enum libinput_pointer_axis axis;
+   Ecore_Device *ecore_dev = NULL, *detent_data = NULL, *data;
+   Eina_List *l;
+   E_Comp_Config *comp_conf = NULL;
+   int direction = 0, z = 0;
 
    if (!(edev = libinput_device_get_user_data(device)))
      {
@@ -645,9 +1337,81 @@ _device_handle_axis(struct libinput_device *device, struct libinput_event_pointe
         return;
      }
 
+   ecore_thread_main_loop_begin();
+
+   if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+   else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
+     {
+        EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+          {
+             if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_MOUSE)
+               {
+                  ecore_dev = data;
+                  break;
+               }
+             else if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_NONE)
+               {
+                  detent_data = data;
+               }
+          }
+        if (!ecore_dev && e_devicemgr_detent_is_detent(libinput_device_get_name(edev->device)))
+          {
+             ecore_dev = detent_data;
+          }
+     }
+   else
+     {
+        edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_MOUSE);
+        ecore_dev = edev->ecore_dev;
+     }
+
+   if (!ecore_dev)
+     {
+        ERR("Failed to get source ecore device from event !\n");
+        goto end;
+     }
+
+   axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
+   if (libinput_event_pointer_has_axis(event, axis))
+     z = _axis_value_get(event, axis);
+
+   axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
+   if (libinput_event_pointer_has_axis(event, axis))
+     {
+        direction = 1;
+        z = _axis_value_get(event, axis);
+     }
+
+  if (z == 0)
+    {
+       ELOGF("Mouse", "Axis event is ignored since it has zero value", NULL);
+       goto end;
+    }
+
+   comp_conf = e_comp_config_get();
+   if (comp_conf && comp_conf->e_wheel_click_angle)
+     {
+        z = (int)(z * comp_conf->e_wheel_click_angle);
+     }
+
+   if ((edev->seat->dev->blocked & E_INPUT_SEAT_POINTER) ||
+       (edev->seat->dev->server_blocked & E_INPUT_SEAT_POINTER))
+     {
+        void *blocked_client = atomic_load(&edev->seat->dev->blocked_client);
+
+        if (detent_data)
+          ELOGF("Mouse", "Detent (direction: %d, value: %d) is blocked by %p, server: 0x%x", NULL,
+                direction, z, blocked_client, edev->seat->dev->server_blocked);
+        else
+          ELOGF("Mouse", "Wheel (direction: %d, value: %d) is blocked by %p, server: 0x%x", NULL,
+                direction, z, blocked_client, edev->seat->dev->server_blocked);
+
+        goto end;
+     }
+
    if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Wheel))))
      {
-        return;
+        goto end;
      }
 
    timestamp = libinput_event_pointer_get_time(event);
@@ -665,21 +1429,207 @@ _device_handle_axis(struct libinput_device *device, struct libinput_event_pointe
    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);
+   ev->z = z;
+   ev->direction = direction;
+
+   if (comp_conf && comp_conf->input_log_enable)
+     {
+        if (detent_data)
+          ELOGF("Mouse", "Detent (direction: %d, value: %d)", NULL, ev->direction, ev->z);
+        else
+          ELOGF("Mouse", "Wheel (direction: %d, value: %d)", NULL, ev->direction, ev->z);
+     }
+
+
+   ev->dev = ecore_device_ref(ecore_dev);
+   ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, _e_input_event_mouse_wheel_cb_free, NULL);
+
+end:
+   ecore_thread_main_loop_end();
+}
+#endif
+
+#if LIBINPUT_HAVE_SCROLL_VALUE_V120
+static int
+_scroll_value_get(struct libinput_event_pointer *pointer_event, enum libinput_pointer_axis axis, E_Input_Axis_Source source)
+{
+   double value = 0.0;
+   double value_v120 = 0.0;
+   int ret;
+   E_Comp_Config *comp_conf = NULL;
+
+   comp_conf = e_comp_config_get();
+   switch (source)
+     {
+      case E_INPUT_AXIS_SOURCE_WHEEL:
+        value_v120 = libinput_event_pointer_get_scroll_value_v120(pointer_event, axis);
+        value = libinput_event_pointer_get_scroll_value(pointer_event, axis);
+        if (comp_conf && comp_conf->input_log_enable)
+          {
+             ELOGF("Scroll", "SOURCE_WHEEL value_v120: %lf (cf. value: %lf)", NULL, value_v120, value);
+          }
+        if (((int)value_v120 % E_INPUT_POINTER_AXIS_DISCRETE_STEP) != 0)
+          {
+             ERR("Wheel movements should be multiples (or fractions) of 120!\n");
+             ret = 0;
+          }
+        else
+          {
+             ret = value_v120 / E_INPUT_POINTER_AXIS_DISCRETE_STEP;
+          }
+        break;
+      case E_INPUT_AXIS_SOURCE_FINGER:
+      case E_INPUT_AXIS_SOURCE_CONTINUOUS:
+        value = libinput_event_pointer_get_scroll_value(pointer_event, axis);
+        if (comp_conf && comp_conf->input_log_enable)
+          {
+             ELOGF("Scroll", "SOURCE_FINGER/CONTINUOUS value: %lf", NULL, value);
+          }
+        if (value >= E_INPUT_FINGER_SCROLL_THRESHOLD)
+          ret = 1;
+        else if (value <= E_INPUT_FINGER_SCROLL_THRESHOLD * (-1))
+          ret = -1;
+        else
+          ret = 0;
+        break;
+      default:
+        break;
+     }
+
+   return ret;
+}
+
+static void
+_device_handle_axis_v120(struct libinput_device *device, struct libinput_event_pointer *event, E_Input_Axis_Source source)
+{
+   E_Input_Evdev *edev;
+   E_Input_Backend *input;
+   Ecore_Event_Mouse_Wheel *ev;
+   uint32_t timestamp;
+   enum libinput_pointer_axis axis;
+   Ecore_Device *ecore_dev = NULL, *detent_data = NULL, *data;
+   Eina_List *l;
+   E_Comp_Config *comp_conf = NULL;
+   int direction = 0, z = 0;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+   if (!(input = edev->seat->input))
+     {
+        return;
+     }
+
+   ecore_thread_main_loop_begin();
+
+   if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+   else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
+     {
+        EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+          {
+             if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_MOUSE)
+               {
+                  ecore_dev = data;
+                  break;
+               }
+             else if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_NONE)
+               {
+                  detent_data = data;
+               }
+          }
+        if (!ecore_dev && e_devicemgr_detent_is_detent(libinput_device_get_name(edev->device)))
+          {
+             ecore_dev = detent_data;
+          }
+     }
+   else
+     {
+        edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_MOUSE);
+        ecore_dev = edev->ecore_dev;
+     }
+
+   if (!ecore_dev)
+     {
+        ERR("Failed to get source ecore device from event !\n");
+        goto end;
+     }
 
    axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
    if (libinput_event_pointer_has_axis(event, axis))
-     ev->z = libinput_event_pointer_get_axis_value(event, axis);
+     z = _scroll_value_get(event, axis, source);
 
    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);
+        direction = 1;
+        z = _scroll_value_get(event, axis, source);
+     }
+
+   if (z == 0)
+     {
+        ELOGF("Mouse", "Scroll event is ignored since it has zero value", NULL);
+        goto end;
+     }
+
+   comp_conf = e_comp_config_get();
+   if (comp_conf && comp_conf->e_wheel_click_angle)
+     {
+        z = (int)(z * comp_conf->e_wheel_click_angle);
      }
 
-   ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL);
+   if ((edev->seat->dev->blocked & E_INPUT_SEAT_POINTER) ||
+       (edev->seat->dev->server_blocked & E_INPUT_SEAT_POINTER))
+     {
+        void *blocked_client = atomic_load(&edev->seat->dev->blocked_client);
+        if (detent_data)
+          ELOGF("Mouse", "Detent (direction: %d, value: %d) is blocked by %p, server: 0x%x", NULL,
+                direction, z, blocked_client, edev->seat->dev->server_blocked);
+        else
+          ELOGF("Mouse", "Wheel (direction: %d, value: %d) is blocked by %p, server: 0x%x", NULL,
+                direction, z, blocked_client, edev->seat->dev->server_blocked);
+
+        goto end;
+     }
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Wheel))))
+     {
+        goto end;
+     }
+
+   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->z = z;
+   ev->direction = direction;
+
+   if (comp_conf && comp_conf->input_log_enable)
+     {
+        if (detent_data)
+          ELOGF("Mouse", "Detent (direction: %d, value: %d)", NULL, ev->direction, ev->z);
+        else
+          ELOGF("Mouse", "Wheel (direction: %d, value: %d)", NULL, ev->direction, ev->z);
+     }
+
+   ev->dev = ecore_device_ref(ecore_dev);
+   ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, _e_input_event_mouse_wheel_cb_free, NULL);
+
+end:
+   ecore_thread_main_loop_end();
 }
+#endif
 
 static void
 _device_handle_touch_event_send(E_Input_Evdev *edev, struct libinput_event_touch *event, int state)
@@ -687,11 +1637,39 @@ _device_handle_touch_event_send(E_Input_Evdev *edev, struct libinput_event_touch
    E_Input_Backend *input;
    Ecore_Event_Mouse_Button *ev;
    uint32_t timestamp, button = 0;
+   Ecore_Device *ecore_dev = NULL, *data;
+   Eina_List *l;
 
    if (!edev) return;
    if (!(input = edev->seat->input)) return;
 
-   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)))) return;
+   ecore_thread_main_loop_begin();
+
+   if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+   else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
+     {
+        EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+          {
+             if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_TOUCH)
+               {
+                  ecore_dev = data;
+                  break;
+               }
+          }
+     }
+   else
+     {
+        edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_TOUCH);
+        ecore_dev = edev->ecore_dev;
+     }
+
+   if (!ecore_dev)
+     {
+        ERR("Failed to get source ecore device from event !\n");
+        goto end;
+     }
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)))) goto end;
 
    timestamp = libinput_event_touch_get_time(event);
 
@@ -733,7 +1711,7 @@ _device_handle_touch_event_send(E_Input_Evdev *edev, struct libinput_event_touch
    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);
+   ev->dev = ecore_device_ref(ecore_dev);
 
    if (state == ECORE_EVENT_MOUSE_BUTTON_DOWN)
      {
@@ -761,6 +1739,11 @@ _device_handle_touch_event_send(E_Input_Evdev *edev, struct libinput_event_touch
         edev->mouse.prev = current;
         edev->mouse.last_button = edev->mouse.prev_button;
         edev->mouse.prev_button = button;
+        edev->touch.pressed |= (1 << ev->multi.device);
+     }
+   else
+     {
+        edev->touch.pressed &= ~(1 << ev->multi.device);
      }
 
    ev->buttons = ((button & 0x00F) + 1);
@@ -770,7 +1753,10 @@ _device_handle_touch_event_send(E_Input_Evdev *edev, struct libinput_event_touch
    if (edev->mouse.did_triple)
      ev->triple_click = 1;
 
-   ecore_event_add(state, ev, NULL, NULL);
+   ecore_event_add(state, ev, _e_input_event_mouse_button_cb_free, NULL);
+
+end:
+   ecore_thread_main_loop_end();
 }
 
 static void
@@ -778,11 +1764,39 @@ _device_handle_touch_motion_send(E_Input_Evdev *edev, struct libinput_event_touc
 {
    E_Input_Backend *input;
    Ecore_Event_Mouse_Move *ev;
+   Ecore_Device *ecore_dev = NULL, *data;
+   Eina_List *l;
 
    if (!edev) return;
    if (!(input = edev->seat->input)) return;
 
-   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Move)))) return;
+   ecore_thread_main_loop_begin();
+
+   if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+   else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
+     {
+        EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+          {
+             if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_TOUCH)
+               {
+                  ecore_dev = data;
+                  break;
+               }
+          }
+     }
+   else
+     {
+        edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_TOUCH);
+        ecore_dev = edev->ecore_dev;
+     }
+
+   if (!ecore_dev)
+     {
+        ERR("Failed to get source ecore device from event !\n");
+        goto end;
+     }
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Move)))) goto end;
 
    ev->window = (Ecore_Window)input->dev->window;
    ev->event_window = (Ecore_Window)input->dev->window;
@@ -792,7 +1806,6 @@ _device_handle_touch_motion_send(E_Input_Evdev *edev, struct libinput_event_touc
 
    _device_modifiers_update(edev);
    ev->modifiers = edev->xkb.modifiers;
-   ev->modifiers = 0;
 
    ev->x = edev->seat->ptr.ix;
    ev->y = edev->seat->ptr.iy;
@@ -819,30 +1832,185 @@ _device_handle_touch_motion_send(E_Input_Evdev *edev, struct libinput_event_touc
    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);
+   ev->dev = ecore_device_ref(ecore_dev);
+
+   ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, _e_input_event_mouse_move_cb_free, NULL);
+
+end:
+   ecore_thread_main_loop_end();
+}
+
+static void
+_device_handle_touch_cancel_send(E_Input_Evdev *edev, struct libinput_event_touch *event)
+{
+   E_Input_Backend *input;
+   Ecore_Event_Mouse_Button *ev;
+   uint32_t timestamp, button = 0;
+   Ecore_Device *ecore_dev = NULL, *data;
+   Eina_List *l;
+
+   if (!edev) return;
+   if (!(input = edev->seat->input)) return;
+
+   ecore_thread_main_loop_begin();
+
+   if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+   else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
+     {
+        EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+          {
+             if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_TOUCH)
+               {
+                  ecore_dev = data;
+                  break;
+               }
+          }
+     }
+   else
+     {
+        edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_TOUCH);
+        ecore_dev = edev->ecore_dev;
+     }
+
+   if (!ecore_dev)
+     {
+        ERR("Failed to get source ecore device from event !\n");
+        goto end;
+     }
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)))) goto end;
+
+   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;
+
+   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;
+
+   edev->touch.pressed &= ~(1 << ev->multi.device);
+
+   ev->buttons = ((button & 0x00F) + 1);
+   ev->dev = ecore_device_ref(ecore_dev);
+
+   ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_CANCEL, ev, _e_input_event_mouse_button_cb_free, NULL);
+
+end:
+   ecore_thread_main_loop_end();
+}
 
-   ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
+static void
+_device_configured_size_get(E_Input_Evdev *edev, int *x, int *y, int *w, int *h)
+{
+   E_Output *output = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN(edev);
+
+   if (!edev->output_configured)
+     {
+        if (edev->output_name)
+          {
+             output = e_output_find(edev->output_name);
+             if (output)
+               {
+                  edev->mouse.minx = output->config.geom.x;
+                  edev->mouse.miny = output->config.geom.y;
+                  edev->mouse.maxw = output->config.geom.w;
+                  edev->mouse.maxh = output->config.geom.h;
+                  if (edev->caps & E_INPUT_SEAT_POINTER)
+                    {
+                       edev->seat->ptr.dx = (double)(edev->mouse.maxw / 2);
+                       edev->seat->ptr.dy = (double)(edev->mouse.maxh / 2);
+                       edev->seat->ptr.ix = (int)edev->seat->ptr.dx;
+                       edev->seat->ptr.iy = (int)edev->seat->ptr.dy;
+                       edev->mouse.dx = edev->seat->ptr.dx;
+                       edev->mouse.dy = edev->seat->ptr.dy;
+                    }
+               }
+          }
+
+          edev->output_configured = EINA_TRUE;
+          ELOGF("E_INPUT_EVDEV", "Device is configured by output x:%d,y:%d (w:%d, h:%d)",
+                NULL, edev->mouse.minx, edev->mouse.miny, edev->mouse.maxw, edev->mouse.maxh);
+     }
+   if (x) *x = edev->mouse.minx;
+   if (y) *y = edev->mouse.miny;
+   if (w) *w = edev->mouse.maxw;
+   if (h) *h = edev->mouse.maxh;
 }
 
 static void
 _device_handle_touch_down(struct libinput_device *device, struct libinput_event_touch *event)
 {
    E_Input_Evdev *edev;
-   int w = 0, h = 0;
+   int x = 0, y = 0, w = 0, h = 0;
+   E_Comp_Config *comp_conf = NULL;
 
    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);
+   _device_configured_size_get(edev, &x, &y, &w, &h);
 
    edev->mouse.dx = edev->seat->ptr.ix = edev->seat->ptr.dx =
-     libinput_event_touch_get_x_transformed(event, w);
+     x + 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);
+     y + libinput_event_touch_get_y_transformed(event, h);
 
    edev->mt_slot = libinput_event_touch_get_slot(event);
+   if (edev->mt_slot < 0)
+     {
+        /* FIXME: The single touch device return slot id -1
+         *        But currently we have no API to distinguish multi touch or single touch
+         *        After libinput 1.11 version, libinput provides get_touch_count API,
+         *        so we can distinguish multi touch device or single touch device.
+         */
+        if (edev->mt_slot == -1)
+          edev->mt_slot = 0;
+        else
+          {
+             WRN("%d slot touch down events are not supported\n", edev->mt_slot);
+             return;
+          }
+     }
+
+   if (edev->mt_slot < e_input_touch_max_count_get())
+     {
+        edev->touch.coords[edev->mt_slot].x = edev->seat->ptr.ix;
+        edev->touch.coords[edev->mt_slot].y = edev->seat->ptr.iy;
+     }
+
+   comp_conf = e_comp_config_get();
+   if (comp_conf && comp_conf->input_log_enable)
+     ELOGF("Touch", "Down (id: %d, x: %d, y: %d)", NULL, edev->mt_slot, edev->seat->ptr.ix, edev->seat->ptr.iy);
+
+   atomic_fetch_or(&edev->touch.raw_pressed, (1 << edev->mt_slot));
+
+   if (edev->touch.blocked)
+     {
+        void *blocked_client = atomic_load(&edev->seat->dev->blocked_client);
+        ELOGF("Touch", "Down (id: %d, x: %d, y: %d) is blocked by %p, server: 0x%x", NULL,
+              edev->mt_slot, edev->seat->ptr.ix, edev->seat->ptr.iy, blocked_client,
+              edev->seat->dev->server_blocked);
+        return;
+     }
 
    _device_handle_touch_motion_send(edev, event);
    _device_handle_touch_event_send(edev, event, ECORE_EVENT_MOUSE_BUTTON_DOWN);
@@ -852,19 +2020,19 @@ static void
 _device_handle_touch_motion(struct libinput_device *device, struct libinput_event_touch *event)
 {
    E_Input_Evdev *edev;
-   int w = 0, h = 0;
+   int x = 0, y = 0, 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);
+   _device_configured_size_get(edev, &x, &y, &w, &h);
 
    edev->mouse.dx = edev->seat->ptr.dx =
-     libinput_event_touch_get_x_transformed(event, w);
+     x + libinput_event_touch_get_x_transformed(event, w);
    edev->mouse.dy = edev->seat->ptr.dy =
-     libinput_event_touch_get_y_transformed(event, h);
+     y + 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)
@@ -876,6 +2044,35 @@ _device_handle_touch_motion(struct libinput_device *device, struct libinput_even
    edev->seat->ptr.iy = edev->seat->ptr.dy;
 
    edev->mt_slot = libinput_event_touch_get_slot(event);
+   if (edev->mt_slot < 0)
+     {
+        /* FIXME: The single touch device return slot id -1
+         *        But currently we have no API to distinguish multi touch or single touch
+         *        After libinput 1.11 version, libinput provides get_touch_count API,
+         *        so we can distinguish multi touch device or single touch device.
+         */
+        if (edev->mt_slot == -1)
+          edev->mt_slot = 0;
+        else
+          {
+             WRN("%d slot touch motion events are not supported\n", edev->mt_slot);
+             return;
+          }
+     }
+
+   if (edev->mt_slot < e_input_touch_max_count_get())
+     {
+        edev->touch.coords[edev->mt_slot].x = edev->seat->ptr.ix;
+        edev->touch.coords[edev->mt_slot].y = edev->seat->ptr.iy;
+     }
+
+   if (!(edev->touch.pressed & (1 << edev->mt_slot)))
+     {
+        if (edev->touch.blocked)
+          {
+             return;
+          }
+     }
 
    _device_handle_touch_motion_send(edev, event);
 }
@@ -884,6 +2081,7 @@ static void
 _device_handle_touch_up(struct libinput_device *device, struct libinput_event_touch *event)
 {
    E_Input_Evdev *edev;
+   E_Comp_Config *comp_conf = NULL;
 
    if (!(edev = libinput_device_get_user_data(device)))
      {
@@ -891,10 +2089,93 @@ _device_handle_touch_up(struct libinput_device *device, struct libinput_event_to
      }
 
    edev->mt_slot = libinput_event_touch_get_slot(event);
+   if (edev->mt_slot < 0)
+     {
+        /* FIXME: The single touch device return slot id -1
+         *        But currently we have no API to distinguish multi touch or single touch
+         *        After libinput 1.11 version, libinput provides get_touch_count API,
+         *        so we can distinguish multi touch device or single touch device.
+         */
+        if (edev->mt_slot == -1)
+          edev->mt_slot = 0;
+        else
+          {
+             WRN("%d slot touch up events are not supported\n", edev->mt_slot);
+             return;
+          }
+     }
+
+   if (edev->mt_slot < e_input_touch_max_count_get())
+     {
+        edev->mouse.dx = edev->seat->ptr.dx = edev->seat->ptr.ix =
+          edev->touch.coords[edev->mt_slot].x;
+        edev->mouse.dy = edev->seat->ptr.dy = edev->seat->ptr.iy =
+          edev->touch.coords[edev->mt_slot].y;
+     }
+
+   comp_conf = e_comp_config_get();
+   if (comp_conf && comp_conf->input_log_enable)
+     ELOGF("Touch", "Up (id: %d, x: %d, y: %d)", NULL, edev->mt_slot, edev->seat->ptr.ix, edev->seat->ptr.iy);
+
+   atomic_fetch_and(&edev->touch.raw_pressed, ~(1 << edev->mt_slot));
+
+   if (edev->touch.blocked)
+     {
+        if (!(edev->touch.pressed & (1 << edev->mt_slot)))
+          {
+             void *blocked_client = atomic_load(&edev->seat->dev->blocked_client);
+             ELOGF("Touch", "Up (id: %d, x: %d, y: %d) is blocked by %p, server(0x%x)", NULL,
+                   edev->mt_slot, edev->seat->ptr.ix, edev->seat->ptr.iy, blocked_client,
+                   edev->seat->dev->server_blocked);
+
+             if (edev->touch.raw_pressed == 0x0)
+               {
+                  edev->touch.blocked = EINA_FALSE;
+               }
+             return;
+          }
+     }
+
    _device_handle_touch_event_send(edev, event, ECORE_EVENT_MOUSE_BUTTON_UP);
 }
 
 static void
+_device_handle_touch_cancel(struct libinput_device *device, struct libinput_event_touch *event)
+{
+   E_Input_Evdev *edev;
+   E_Comp_Config *comp_conf = NULL;
+
+   if (!(edev = libinput_device_get_user_data(device)))
+     {
+        return;
+     }
+
+   edev->mt_slot = libinput_event_touch_get_slot(event);
+   if (edev->mt_slot < 0)
+     {
+        /* FIXME: The single touch device return slot id -1
+         *        But currently we have no API to distinguish multi touch or single touch
+         *        After libinput 1.11 version, libinput provides get_touch_count API,
+         *        so we can distinguish multi touch device or single touch device.
+         */
+        if (edev->mt_slot == -1)
+          edev->mt_slot = 0;
+        else
+          {
+             WRN("%d slot touch up events are not supported\n", edev->mt_slot);
+             return;
+          }
+     }
+
+   comp_conf = e_comp_config_get();
+   if (comp_conf && comp_conf->input_log_enable)
+     ELOGF("Touch", "cancel (id: %d, x: %d, y: %d)", NULL, edev->mt_slot, edev->seat->ptr.ix, edev->seat->ptr.iy);
+
+   _device_handle_touch_cancel_send(edev, event);
+}
+
+
+static void
 _device_handle_touch_frame(struct libinput_device *device EINA_UNUSED, struct libinput_event_touch *event EINA_UNUSED)
 {
    /* DBG("Unhandled Touch Frame Event"); */
@@ -904,8 +2185,10 @@ 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);
+
+   if (e->axis) free(e->axis);
+   if (e->dev) ecore_device_unref(e->dev);
+
    free(e);
 }
 
@@ -916,6 +2199,11 @@ _device_handle_touch_aux_data(struct libinput_device *device, struct libinput_ev
    E_Input_Backend *input;
    Ecore_Event_Axis_Update *ev;
    Ecore_Axis *axis;
+   Ecore_Device *ecore_dev = NULL, *data;
+   Eina_List *l;
+   E_Comp_Config *comp_conf;
+
+   ecore_thread_main_loop_begin();
 
    if (libinput_event_touch_aux_data_get_type(event) != LIBINPUT_TOUCH_AUX_DATA_TYPE_PALM &&
        libinput_event_touch_aux_data_get_value(event) > 0)
@@ -923,7 +2211,32 @@ _device_handle_touch_aux_data(struct libinput_device *device, struct libinput_ev
 
    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;
+
+   if (edev->ecore_dev) ecore_dev = edev->ecore_dev;
+   else if (edev->ecore_dev_list && eina_list_count(edev->ecore_dev_list) > 0)
+     {
+        EINA_LIST_FOREACH(edev->ecore_dev_list, l, data)
+          {
+             if (ecore_device_class_get(data) == ECORE_DEVICE_CLASS_TOUCH)
+               {
+                  ecore_dev = data;
+                  break;
+               }
+          }
+     }
+   else
+     {
+        edev->ecore_dev = e_input_evdev_get_ecore_device(edev->path, ECORE_DEVICE_CLASS_TOUCH);
+        ecore_dev = edev->ecore_dev;
+     }
+
+   if (!ecore_dev)
+     {
+        ERR("Failed to get source ecore device from event !\n");
+        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;
@@ -939,10 +2252,16 @@ _device_handle_touch_aux_data(struct libinput_device *device, struct libinput_ev
      }
    ev->axis = axis;
 
+   comp_conf = e_comp_config_get();
+   if (comp_conf && comp_conf->input_log_enable)
+     ELOGF("Touch", "Axis (label: %d, value: %lf)", NULL, axis?axis->label:-1, axis?axis->value:0.0);
+
+   ev->dev = ecore_device_ref(ecore_dev);
+
    ecore_event_add(ECORE_EVENT_AXIS_UPDATE, ev, _e_input_aux_data_event_free, NULL);
 
 end:
-   ;
+   ecore_thread_main_loop_end();
 }
 
 E_Input_Evdev *
@@ -950,6 +2269,7 @@ _e_input_evdev_device_create(E_Input_Seat *seat, struct libinput_device *device)
 {
    E_Input_Evdev *edev;
    E_Input_Backend *b_input;
+   const char *output_name;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(seat, NULL);
 
@@ -959,7 +2279,6 @@ _e_input_evdev_device_create(E_Input_Seat *seat, struct libinput_device *device)
    edev->seat = seat;
    edev->device = device;
    edev->path = eina_stringshare_printf("%s/%s", e_input_base_dir_get(), libinput_device_get_sysname(device));
-   edev->fd = -1;
 
    if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD))
      {
@@ -995,6 +2314,20 @@ _e_input_evdev_device_create(E_Input_Seat *seat, struct libinput_device *device)
           {
              libinput_device_touch_set_aux_data(device, palm_code);
           }
+
+        _device_touch_count_update(edev);
+
+        edev->touch.coords = calloc(1, sizeof(E_Input_Coord)*e_input_touch_max_count_get());
+
+        if  (!edev->touch.coords)
+          ERR("Failed to allocate memory for touch coords !\n");
+     }
+
+   output_name = libinput_device_get_output_name(device);
+   if (output_name)
+     {
+        eina_stringshare_replace(&edev->output_name, output_name);
+        ELOGF("E_INPUT_EVDEV", "Device has output_name:%s", NULL, output_name);
      }
 
    libinput_device_set_user_data(device, edev);
@@ -1009,17 +2342,49 @@ _e_input_evdev_device_create(E_Input_Seat *seat, struct libinput_device *device)
 void
 _e_input_evdev_device_destroy(E_Input_Evdev *edev)
 {
+   Ecore_Device *dev;
    EINA_SAFETY_ON_NULL_RETURN(edev);
 
+   ecore_thread_main_loop_begin();
+
    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->ecore_dev) ecore_device_del(edev->ecore_dev);
+   if (edev->ecore_dev_list)
+     EINA_LIST_FREE(edev->ecore_dev_list, dev)
+       {
+          ecore_device_del(dev);
+       }
+
+   if (edev->e_dev) g_object_unref(edev->e_dev);
+   if (edev->e_dev_list)
+     {
+        GList *glist = edev->e_dev_list;
+        E_Device *e_dev;
+        while (glist)
+          {
+             e_dev = glist->data;
+             g_object_unref(e_dev);
+
+             glist = g_list_next(glist);
+          }
+     }
    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);
+   if (edev->touch.coords)
+     {
+        free(edev->touch.coords);
+        edev->touch.coords = NULL;
+     }
+   eina_stringshare_del(edev->output_name);
+
+   ecore_thread_main_loop_end();
 
    free(edev);
 }
@@ -1048,8 +2413,21 @@ _e_input_evdev_event_process(struct libinput_event *event)
         _device_handle_button(device, libinput_event_get_pointer_event(event));
         break;
       case LIBINPUT_EVENT_POINTER_AXIS:
+#if !LIBINPUT_HAVE_SCROLL_VALUE_V120
         _device_handle_axis(device, libinput_event_get_pointer_event(event));
+#endif
+        break;
+#if LIBINPUT_HAVE_SCROLL_VALUE_V120
+      case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
+        _device_handle_axis_v120(device, libinput_event_get_pointer_event(event), E_INPUT_AXIS_SOURCE_WHEEL);
         break;
+      case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
+        _device_handle_axis_v120(device, libinput_event_get_pointer_event(event), E_INPUT_AXIS_SOURCE_FINGER);
+        break;
+      case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
+        _device_handle_axis_v120(device, libinput_event_get_pointer_event(event), E_INPUT_AXIS_SOURCE_CONTINUOUS);
+        break;
+#endif
       case LIBINPUT_EVENT_TOUCH_DOWN:
         _device_handle_touch_down(device, libinput_event_get_touch_event(event));
         break;
@@ -1060,6 +2438,9 @@ _e_input_evdev_event_process(struct libinput_event *event)
       case LIBINPUT_EVENT_TOUCH_UP:
         _device_handle_touch_up(device, libinput_event_get_touch_event(event));
         break;
+      case LIBINPUT_EVENT_TOUCH_CANCEL:
+        _device_handle_touch_cancel(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;
@@ -1089,12 +2470,10 @@ _e_input_evdev_event_process(struct libinput_event *event)
 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;
+   struct udev_device *udev_device = NULL;
 
    EINA_SAFETY_ON_NULL_RETURN(edev);
    EINA_SAFETY_ON_TRUE_RETURN((w == 0) || (h == 0));
@@ -1103,35 +2482,37 @@ e_input_evdev_axis_size_set(E_Input_Evdev *edev, int w, int h)
        (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;
+   udev_device = libinput_device_get_udev_device(edev->device);
+   if (!udev_device)
+     {
+        ERR("no udev_device");
+        return;
+     }
 
-   EINA_LIST_FREE(devices, device)
+   vals = udev_device_get_property_value(udev_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))
      {
-        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;
+        udev_device_unref(udev_device);
+        return;
+     }
+   udev_device_unref(udev_device);
 
-        cal[2] /= w;
-        cal[5] /= h;
+   ELOGF("E_INPUT_EVDEV", "axis_size_set cal[%lf %lf %lf %lf %lf %lf] (%d x %d)",
+         NULL, cal[0], cal[1], cal[2], cal[3], cal[4], cal[5], w, h);
 
-        status =
-          libinput_device_config_calibration_set_matrix(edev->device, cal);
+   cal[2] /= w;
+   cal[5] /= h;
 
-        if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
-          ERR("Failed to apply calibration");
+   status =
+     libinput_device_config_calibration_set_matrix(edev->device, cal);
 
-cont:
-        eina_stringshare_del(device);
-        continue;
-     }
+   if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
+     ERR("Failed to apply calibration");
 }
 
-E_API const char *
+EINTERN const char *
 e_input_evdev_name_get(E_Input_Evdev *evdev)
 {
    EINA_SAFETY_ON_NULL_RETURN_VAL(evdev, NULL);
@@ -1204,7 +2585,7 @@ e_input_evdev_key_remap_set(E_Input_Evdev *edev, int *from_keys, int *to_keys, i
    return EINA_TRUE;
 }
 
-E_API int
+EINTERN int
 e_input_evdev_wheel_click_angle_get(E_Input_Evdev *dev)
 {
    EINA_SAFETY_ON_NULL_RETURN_VAL(dev, -1);
@@ -1232,3 +2613,75 @@ e_input_evdev_touch_calibration_set(E_Input_Evdev *edev, float matrix[6])
    return EINA_TRUE;
 }
 
+EINTERN Eina_Bool
+e_input_evdev_mouse_accel_speed_set(E_Input_Evdev *edev, double speed)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev->device, EINA_FALSE);
+
+   if (!libinput_device_has_capability(edev->device, LIBINPUT_DEVICE_CAP_POINTER))
+     return EINA_FALSE;
+
+   if (!libinput_device_config_accel_is_available(edev->device))
+     return EINA_FALSE;
+
+   if (libinput_device_config_accel_set_speed(edev->device, speed) !=
+       LIBINPUT_CONFIG_STATUS_SUCCESS)
+     {
+        WRN("Failed to set mouse accel about device: %s\n",
+            libinput_device_get_name(edev->device));
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+EINTERN unsigned int
+e_input_evdev_touch_pressed_get(E_Input_Evdev *edev)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edev, 0x0);
+
+   return edev->touch.pressed;
+}
+
+const char *
+e_input_evdev_seatname_get(E_Input_Evdev *evdev)
+{
+   struct libinput_seat *libinput_seat;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evdev, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evdev->device, NULL);
+
+   libinput_seat = libinput_device_get_seat(evdev->device);
+
+   return libinput_seat_get_logical_name(libinput_seat);
+}
+
+Eina_Bool
+e_input_evdev_seatname_set(E_Input_Evdev *evdev, const char *seatname)
+{
+   Eina_Bool res = EINA_FALSE;
+   E_Input_Backend *input;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(seatname, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evdev, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evdev->device, EINA_FALSE);
+
+   if (libinput_device_set_seat_logical_name(evdev->device, seatname) == 0)
+     {
+        input = evdev->seat->input;
+        if (!input) return EINA_FALSE;
+
+        if (libinput_dispatch(input->libinput) != 0)
+          {
+             ERR("Failed to dispatch libinput events: %m");
+
+             return EINA_FALSE;
+          }
+
+        /* process pending events */
+        _input_events_process(input);
+        res = EINA_TRUE;
+     }
+
+   return res;
+}