input: Add TC for checking relative move event 89/316189/4
authorJihoon Kim <jihoon48.kim@samsung.com>
Wed, 11 Dec 2024 10:23:32 +0000 (19:23 +0900)
committerJihoon Kim <jihoon48.kim@samsung.com>
Thu, 12 Dec 2024 02:44:26 +0000 (11:44 +0900)
Change-Id: If7530ce94e1cf5485f8226c9fc2d28cb05370575
Signed-off-by: Jihoon Kim <jihoon48.kim@samsung.com>
src/Makefile.am
src/e_test_event.cpp
src/e_test_event.h
src/e_test_inputevent.c [new file with mode: 0644]
src/e_test_inputevent.h [new file with mode: 0644]
src/e_test_util.h
src/testcase/0009_input.cpp

index 18f5e44041ea79c9b47af341f8db18d179ce1da7..4c0b0e6c0e92804b59a647f2aa84ce4a7868e5a0 100644 (file)
@@ -42,6 +42,8 @@ e_test_win.cpp \
 e_test_util.h \
 e_test_efl_util.h \
 e_test_efl_util.cpp \
+e_test_inputevent.h \
+e_test_inputevent.c \
 ${tc_sources}
 
 MAINTAINERCLEANFILES = \
index d7bf19a82b49610661d6fed9dc0485fce770b8b9..42e0094c044b0919662699419081c4a22735f6da 100644 (file)
@@ -4,6 +4,7 @@
 #include <pixman.h>
 
 #include "e_test_event.h"
+#include "e_test_inputevent.h"
 
 #define E_TEST_WORK_TIME 3.0
 #define E_TC_SIGN_WIN_INFO "usiiiiibbbiibibbbi"
@@ -125,6 +126,7 @@ static Eina_Bool _cb_ecore_key_up(void *data, int type, void *event);
 static Eina_Bool _cb_ecore_mouse_button_down(void *data, int type, void *event);
 static Eina_Bool _cb_ecore_mouse_button_up(void *data, int type, void *event);
 static Eina_Bool _cb_ecore_mouse_move(void *data, int type, void *event);
+static Eina_Bool _cb_ecore_mouse_relative_move(void *data, int type, void *event);
 
 /* callbacks - evas */
 static void _cb_evas_key_down(void * data, Evas * evas, Evas_Object * obj, void * event_info);
@@ -248,6 +250,8 @@ etRunner::init()
         ERR("not supported resolution. do not execute verifyTC");
      }
 
+   init_input_device();
+
    return EINA_TRUE;
 }
 
@@ -256,6 +260,8 @@ etRunner::shutdown()
 {
    eina_log_domain_unregister(logDomain);
 
+   deinit_input_device();
+
    freeLastWinInfoList();
 
    if (screenshot)
@@ -1159,6 +1165,12 @@ etRunner::feedMouseMove(int x, int y)
    return EINA_TRUE;
 }
 
+void
+etRunner::feedLowLevelMouseMove(int x, int y)
+{
+   pointer_gen_move(x, y);
+}
+
 Eina_Bool
 etRunner::feedMouseUp(int x, int y)
 {
@@ -1471,7 +1483,8 @@ etRunner::waitEvent(etWin *win, E_TC_Event_Type ev_type)
              return recv_item;
           }
         else if ((ev_type == E_TC_EVENT_TYPE_INPUT_ECORE_KEY) ||
-                 (ev_type == E_TC_EVENT_TYPE_INPUT_ECORE_MOUSE))
+                 (ev_type == E_TC_EVENT_TYPE_INPUT_ECORE_MOUSE) ||
+                 (ev_type == E_TC_EVENT_TYPE_INPUT_ECORE_MOUSE_RELATIVE_MOVE))
           {
              Ecore_Window ew = elm_win_window_id_get(win?win->elm_win:0);
              if (recv_item->isSameWin(ew) &&
@@ -1646,6 +1659,10 @@ etRunner::addSignalHandlers()
    EINA_SAFETY_ON_NULL_GOTO(eh, err);
    ev.eh_list = eina_list_append(ev.eh_list, eh);
 
+   eh = ecore_event_handler_add(ECORE_EVENT_MOUSE_RELATIVE_MOVE, _cb_ecore_mouse_relative_move, this);
+   EINA_SAFETY_ON_NULL_GOTO(eh, err);
+   ev.eh_list = eina_list_append(ev.eh_list, eh);
+
    ev.mouse.ecore_state = EINA_FALSE;
 
    return EINA_TRUE;
@@ -2658,6 +2675,32 @@ _cb_ecore_mouse_move(void *data, int type, void *event)
    return ECORE_CALLBACK_PASS_ON;
 }
 
+static Eina_Bool
+_cb_ecore_mouse_relative_move(void *data, int type, void *event)
+{
+   Ecore_Event_Mouse_Relative_Move *ev = (Ecore_Event_Mouse_Relative_Move *)event;
+   etRunner *runner = (etRunner *)data;
+
+   DBG("[%s] Mouse Relative Move cb (%d, %d)", __func__, ev->dx, ev->dy);
+
+   if ((runner->ev.mouse.x == ev->dx) &&
+       (runner->ev.mouse.y == ev->dy))
+     {
+        if (type == ECORE_EVENT_MOUSE_RELATIVE_MOVE)
+          {
+             if (checkEcoreDeviceInfo(ev->dev))
+               {
+                  DBG("Mouse Relative Move cb. insert event");
+                  runner->insertEventQueue(ev->window, E_TC_EVENT_TYPE_INPUT_ECORE_MOUSE_RELATIVE_MOVE);
+               }
+             else
+               ERR("Mouse Relative MOVE cb. device info is empty");
+          }
+     }
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
 /* callbacks - evas */
 static void
 _cb_evas_key_down(void *data, Evas * evas, Evas_Object * obj, void * event_info)
index ca3b021c8a4ecea43f76a2c8c6f108529fe9f31a..e8baa27c69e291333012918a68f3f272a58f0069 100644 (file)
@@ -322,6 +322,8 @@ public:
    Eina_Bool     feedMouseUp(int x, int y);
    Eina_Bool     feedKeyDown(const char *key);
    Eina_Bool     feedKeyUp(const char *key);
+
+   void          feedLowLevelMouseMove(int x, int y);
 #ifndef DISABLE_GESTURE_TESTS
    Eina_Bool     generateTapGesture(InputGenHandler handler);
    Eina_Bool     generateEdgeSwipeGesture(InputGenHandler handler);
diff --git a/src/e_test_inputevent.c b/src/e_test_inputevent.c
new file mode 100644 (file)
index 0000000..56a07b4
--- /dev/null
@@ -0,0 +1,200 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <linux/uinput.h>
+#include <string.h>
+#include <stdbool.h>
+
+enum
+{
+   INPUT_SEAT_POINTER = 0,
+   INPUT_SEAT_KEYBOARD
+} Input_Device_Type;
+
+typedef struct _Virtual_Input_Device
+{
+   bool virtual_dev;
+   int fd;
+   char *name;
+} Virtual_Input_Device;
+
+static Virtual_Input_Device _input_info[2] =
+{
+     {
+        false,
+        -1,
+        NULL
+     },
+};
+
+static void
+input_set_keyboard(struct uinput_user_dev *uinput_dev, int uinput_fd)
+{
+   int i;
+
+   for (i = KEY_ESC; i <= KEY_MICMUTE; i++)
+     ioctl(uinput_fd, UI_SET_KEYBIT, i);
+
+   for (i = KEY_OK; i <= KEY_LIGHTS_TOGGLE; i++)
+     ioctl(uinput_fd, UI_SET_KEYBIT, i);
+
+   for (i = KEY_ALS_TOGGLE; i <= KEY_ONSCREEN_KEYBOARD; i++)
+     ioctl(uinput_fd, UI_SET_KEYBIT, i);
+}
+
+static void
+input_set_pointer(struct uinput_user_dev *uinput_dev, int uinput_fd)
+{
+   int i;
+
+   ioctl(uinput_fd, UI_SET_EVBIT, EV_REL);
+
+   ioctl(uinput_fd, UI_SET_RELBIT, REL_X);
+   ioctl(uinput_fd, UI_SET_RELBIT, REL_Y);
+   ioctl(uinput_fd, UI_SET_RELBIT, REL_WHEEL);
+   ioctl(uinput_fd, UI_SET_RELBIT, REL_HWHEEL);
+
+   for (i = BTN_MISC; i <= BTN_TASK; i++)
+     ioctl(uinput_fd, UI_SET_KEYBIT, i);
+}
+
+static int
+create_input_device(const char *dev_name, int device_type)
+{
+   int uinput_fd = -1, nwrite = 0;
+   struct uinput_user_dev uinput_dev = {0, };
+
+   uinput_fd = open("/dev/uinput", O_WRONLY | O_NDELAY);
+   if (uinput_fd < 0)
+     return -1;
+
+   strncpy(uinput_dev.name, dev_name, UINPUT_MAX_NAME_SIZE - 1);
+   uinput_dev.id.version = 1;
+   uinput_dev.id.bustype = BUS_VIRTUAL;
+
+   ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY);
+   ioctl(uinput_fd, UI_SET_EVBIT, EV_SYN);
+   ioctl(uinput_fd, UI_SET_EVBIT, EV_MSC);
+   ioctl(uinput_fd, UI_SET_MSCBIT, MSC_SCAN);
+
+   if (device_type == INPUT_SEAT_KEYBOARD)
+     input_set_keyboard(&uinput_dev, uinput_fd);
+   else if (device_type == INPUT_SEAT_POINTER)
+     input_set_pointer(&uinput_dev, uinput_fd);
+
+   /* Create input device into input sub-system */
+   nwrite = write(uinput_fd, &uinput_dev, sizeof(uinput_dev));
+   if (nwrite < 0) printf("Failed to write for create device using uinput (err: %m)\n");
+
+   if (ioctl(uinput_fd, UI_DEV_CREATE))
+     {
+        printf("Failed to create %s device (err: %m)\n", dev_name);
+        close (uinput_fd);
+        return -1;
+     }
+
+   return uinput_fd;
+}
+
+bool init_input_device()
+{
+   int fd = 0;
+   const char *name = "Input_Script";
+
+   for (int device_type = 0; device_type < 2; device_type++)
+     {
+        fd = create_input_device(name, device_type);
+        if (fd)
+          {
+             _input_info[device_type].virtual_dev = true;
+             _input_info[device_type].fd = fd;
+             _input_info[device_type].name = strdup(name);
+          }
+
+        if (fd < 0)
+          {
+             _input_info[device_type].virtual_dev = false;
+             _input_info[device_type].fd = -1;
+             if (_input_info[device_type].name)
+               {
+                  free(_input_info[device_type].name);
+                  _input_info[device_type].name = NULL;
+               }
+
+             printf("Failed to open event node or uinput node");
+             return false;
+          }
+     }
+
+   return true;
+}
+
+void deinit_input_device()
+{
+   int ret;
+
+   for (int i=0; i<2; i++)
+     {
+        if (_input_info[i].fd < 0) continue;
+
+        if (_input_info[i].virtual_dev)
+          {
+             ret = ioctl(_input_info[i].fd, UI_DEV_DESTROY, NULL);
+             if (ret) printf("Failed destroy fd: %d (ret: %d) (err: %m)\n", _input_info[i].fd, ret);
+          }
+        close(_input_info[i].fd);
+
+        _input_info[i].fd = -1;
+        _input_info[i].virtual_dev = false;
+
+        if (_input_info[i].name)
+          {
+             free(_input_info[i].name);
+             _input_info[i].name = NULL;
+          }
+     }
+}
+
+int write_event_to_device_node(int device_type, int event_type, int code, int value)
+{
+   int nwrite;
+   struct input_event ev;
+
+   gettimeofday(&ev.time, NULL);
+
+   ev.type = event_type;
+   ev.code = code;
+   ev.value = value;
+
+   nwrite = write(_input_info[device_type].fd, &ev, sizeof(ev));
+   if (nwrite < 0)
+     printf("Error writing input event\n");
+
+   return nwrite;
+}
+
+static void
+_sync_gen(int device_type)
+{
+   write_event_to_device_node(device_type, EV_SYN, 0, 0);
+}
+
+static void
+_pointer_gen_x(int value)
+{
+   write_event_to_device_node(INPUT_SEAT_POINTER, EV_REL, REL_X, value);
+}
+
+static void
+_pointer_gen_y(int value)
+{
+   write_event_to_device_node(INPUT_SEAT_POINTER, EV_REL, REL_Y, value);
+}
+
+void pointer_gen_move(int x, int y)
+{
+   if (x != 0) _pointer_gen_x(x);
+   if (y != 0) _pointer_gen_y(y);
+   _sync_gen(INPUT_SEAT_POINTER);
+}
diff --git a/src/e_test_inputevent.h b/src/e_test_inputevent.h
new file mode 100644 (file)
index 0000000..8e62103
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __E_TEST_INPUTEVENT_H__
+#define __E_TEST_INPUTEVENT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool init_input_device();
+void deinit_input_device();
+
+void pointer_gen_move(int x, int y);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // end of __E_TEST_INPUTEVENT_H__
index 376d9fbf237169399b37b0d0494baf2d3eaf040e..0de2745bbfb9f983745701f0ea6987663c89cf6e 100644 (file)
@@ -88,6 +88,7 @@ typedef enum _E_TC_Event_Type
    E_TC_EVENT_TYPE_FOCUS_CHANGED,
    E_TC_EVENT_TYPE_INPUT_ECORE_KEY,
    E_TC_EVENT_TYPE_INPUT_ECORE_MOUSE,
+   E_TC_EVENT_TYPE_INPUT_ECORE_MOUSE_RELATIVE_MOVE,
    E_TC_EVENT_TYPE_INPUT_EVAS_KEY,
    E_TC_EVENT_TYPE_EFFECT_EVAS_CB,
    E_TC_EVENT_TYPE_EFFECT,
index 0df73d0220d6ed7fc51b2557a7ec96ee3a9bcfbb..35137f21e9673609f71da9107797c6891d75265a 100644 (file)
@@ -1213,9 +1213,25 @@ TEST_F(etTestInput, pointer_constraints_lock_pointer)
 
    ASSERT_TRUE(ret);
 
+   etRunner::get().work(0.1); // wait for lock pointer.
+
+   etRunner::get().feedLowLevelMouseMove(1, 1);
+
+   // After locking pointer, mouse event should be processed as relative mouse move.
+   ev_result = etRunner::get().waitEvent(tw, E_TC_EVENT_TYPE_INPUT_ECORE_MOUSE_RELATIVE_MOVE);
+   ASSERT_NE(ev_result, nullptr);
+
    ret = ecore_wl2_window_pointer_constraints_unlock_pointer(wlwin);
    ASSERT_TRUE(ret);
 
+   etRunner::get().work(0.1); // wait for unlock pointer.
+
+   etRunner::get().feedLowLevelMouseMove(1, 1);
+
+   // After unlocking pointer, mouse event should be processed as normal mouse move.
+   ev_result = etRunner::get().waitEvent(tw, E_TC_EVENT_TYPE_INPUT_ECORE_MOUSE);
+   ASSERT_NE(ev_result, nullptr);
+
    ASSERT_EQ(etRunner::get().verifyTC(testCaseName, testName), EINA_TRUE);
 }