Implements MouseEventCheckTest for libinput haltests
authordyamy-lee <dyamy.lee@samsung.com>
Wed, 21 Apr 2021 07:36:59 +0000 (16:36 +0900)
committerduna.oh <duna.oh@samsung.com>
Fri, 27 Jan 2023 05:46:25 +0000 (14:46 +0900)
For test, get lists of libinput devices and check validation of created mouse event.
It generates libinput mouse event and saves sequencely. For example, mouse left button down, move, up.
It checkes devices capability which is mouse, and checkes matching of events. If one of them checked successfully same events as created events, other mouse devices can be skipped.

Change-Id: Ifa06d24d0796eb3b207dc30f13b924af1804a3e1

haltests/meson.build
haltests/test_hal_libinput.cpp
haltests/test_hal_libinput_eventgen.cpp [new file with mode: 0644]
haltests/test_hal_libinput_eventgen.h [new file with mode: 0644]
haltests/test_hal_libinput_info.cpp
haltests/test_hal_libinput_info.h

index d0a7af1..a84da3d 100644 (file)
@@ -6,6 +6,7 @@ libinput_haltests_srcs = [
     'test_main.cpp',
     'test_hal_libinput.cpp',
     'test_hal_libinput_info.cpp',
+    'test_hal_libinput_eventgen.cpp',
 ]
 
 libinput_haltests_include_dirs = include_directories(
index b5bfd02..2001f7e 100644 (file)
@@ -48,7 +48,8 @@ TEST_F(LibInputHalTest, GetDeviceListsTest)
 
 TEST_F(LibInputHalTest, MouseEventCheckTest)
 {
-       EXPECT_TRUE(true);
+       EXPECT_TRUE(handle_libinput_add_event(li) != -1);
+       EXPECT_TRUE(validate_mouse_event(li));
 }
 
 TEST_F(LibInputHalTest, KeyboardEventCheckTest)
diff --git a/haltests/test_hal_libinput_eventgen.cpp b/haltests/test_hal_libinput_eventgen.cpp
new file mode 100644 (file)
index 0000000..c0741c8
--- /dev/null
@@ -0,0 +1,137 @@
+#include "test_hal_libinput_eventgen.h"
+
+int fd = 0;
+
+static inline void msleep(unsigned int ms)
+{
+       usleep(ms * 1000);
+}
+
+static int _write_event_to_device_node(int type, int code, int value)
+{
+       int nwrite;
+       struct input_event ev;
+
+       gettimeofday(&ev.time, NULL);
+
+       ev.type = type;
+       ev.code = code;
+       ev.value = value;
+
+       LOG("(type)%01d (code)%04x (value)%d\n",
+                       ev.type, ev.code, ev.value);
+       nwrite = write(fd, &ev, sizeof(ev));
+
+       return nwrite;
+}
+
+static void _sync_gen(void)
+{
+       _write_event_to_device_node(EV_SYN, 0, 0);
+}
+
+static int _covert_button(int button)
+{
+       switch(button) {
+       case 0:
+               return BTN_LEFT;
+       case 1:
+               return BTN_RIGHT;
+       case 2:
+               return BTN_MIDDLE;
+       default:
+               return button;
+       }
+}
+
+static void _pointer_gen_button(int button, int value)
+{
+       _write_event_to_device_node(EV_KEY, button, value);
+}
+
+static void _pointer_gen_wheel(int value)
+{
+       _write_event_to_device_node(EV_REL, REL_WHEEL, value);
+       _sync_gen();
+}
+
+static void _pointer_gen_hwheel(int value)
+{
+       _write_event_to_device_node(EV_REL, REL_HWHEEL, value);
+       _sync_gen();
+}
+
+static void _pointer_gen_x(int value)
+{
+       _write_event_to_device_node(EV_REL, REL_X, value);
+}
+
+static void _pointer_gen_y(int value)
+{
+       _write_event_to_device_node(EV_REL, REL_Y, value);
+}
+
+static void _button_gen_down(int button)
+{
+       if(button <3)
+               button = _covert_button(button);
+
+       _pointer_gen_button(button,1);
+       _sync_gen();
+}
+
+static void _button_gen_up(int button)
+{
+       if(button <3)
+               button = _covert_button(button);
+
+       _pointer_gen_button(button, 0);
+       _sync_gen();
+}
+
+static void _pointer_gen_move(int x, int y)
+{
+       if(x != 0) _pointer_gen_x(x);
+       if(y != 0) _pointer_gen_y(y);
+       _sync_gen();
+}
+
+static void _input_mousegen(int button, int x, int y, int mouse_state)
+{
+       switch(mouse_state) {
+       case EVENT_STATE_PRESS:
+               _button_gen_down(button);
+               break;
+       case EVENT_STATE_RELEASE:
+               _button_gen_up(button);
+               msleep(30);
+               break;
+       case EVENT_STATE_MOTION:
+               if (button == BUTTON_WHEEL)
+               {
+                       _pointer_gen_wheel(x);
+               }
+               else if (button == BUTTON_HWHEEL)
+               {
+                       _pointer_gen_hwheel(y);
+               }
+               else
+               _pointer_gen_move(x, y);
+               break;
+       case EVENT_STATE_ALL:
+               _button_gen_down(button);
+               _button_gen_up(button);
+               break;
+       default:
+               return;
+       }
+}
+
+int input_mouse_event_gen(int _fd, int button, int x, int y, int state)
+{
+       if (_fd < 0) return -1;
+       fd = _fd;
+       _input_mousegen(button, x, y, state);
+
+       return 0;
+}
diff --git a/haltests/test_hal_libinput_eventgen.h b/haltests/test_hal_libinput_eventgen.h
new file mode 100644 (file)
index 0000000..9f787b8
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __LIBINPUT_TESTS_EVENT_GEN_H__
+#define __LIBINPUT_TESTS_EVENT_GEN_H__
+
+#include <stdio.h>
+#include "test_hal_libinput_info.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/input.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#define BTN_MOUSE              0x110
+#define BTN_LEFT               0x110
+#define BTN_RIGHT              0x111
+#define BTN_MIDDLE             0x112
+
+typedef enum
+{
+   EVENT_STATE_RELEASE = 0,
+   EVENT_STATE_PRESS,
+   EVENT_STATE_MOTION,
+   EVENT_STATE_ALL
+} Input_Event_State;
+
+typedef enum
+{
+   BUTTON_LEFT = 0,
+   BUTTON_RIGHT,
+   BUTTON_MIDDLE,
+   BUTTON_WHEEL,
+   BUTTON_HWHEEL
+} Button;
+
+int input_mouse_event_gen(int _fd, int button, int x, int y, int state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LIBINPUT_TESTS_EVENT_GEN_H__
\ No newline at end of file
index f626461..214195f 100644 (file)
@@ -1,11 +1,19 @@
 #include "test_hal_libinput_info.h"
+#include "test_hal_libinput_eventgen.h"
 #include <limits.h>
 #include <libevdev/libevdev.h>
 #include <libevdev/libevdev-uinput.h>
 
+static const uint32_t screen_width = 100;
+static const uint32_t screen_height = 100;
+
 struct record_device devices[10];
 int devices_cnt = 0;
 
+struct record_event queue_record_event[1000];
+int queue_idx = 0;
+int pop_idx = -1;
+
 #define NLONGS(n) (((n) + LONG_BIT - 1) / LONG_BIT)
 
 static bool evdev_bit_is_set(const unsigned long *array, int bit)
@@ -21,14 +29,14 @@ int handle_device_notify(struct libinput_event *ev)
        const char *devnode;
 
        switch(libinput_event_get_type(ev)) {
-               case LIBINPUT_EVENT_DEVICE_ADDED:
-                       type = LIBINPUT_EVENT_DEVICE_ADDED;
-                       break;
-               case LIBINPUT_EVENT_DEVICE_REMOVED:
-                       type = LIBINPUT_EVENT_DEVICE_REMOVED;
-                       break;
-               default:
-                       abort();
+       case LIBINPUT_EVENT_DEVICE_ADDED:
+               type = LIBINPUT_EVENT_DEVICE_ADDED;
+               break;
+       case LIBINPUT_EVENT_DEVICE_REMOVED:
+               type = LIBINPUT_EVENT_DEVICE_REMOVED;
+               break;
+       default:
+               abort();
        }
 
        if(strstr(udev_device_get_property_value(udev_device, "DEVPATH"), "virtual")){
@@ -96,19 +104,294 @@ int handle_libinput_add_event(struct libinput *li)
        struct libinput_event *ev;
        libinput_dispatch(li);
        while((ev = libinput_get_event(li))) {
-               switch (libinput_event_get_type(ev))
-               {
-                       case LIBINPUT_EVENT_NONE:
-                               abort();
-                       case LIBINPUT_EVENT_DEVICE_ADDED:
-                       case LIBINPUT_EVENT_DEVICE_REMOVED:
-                               handle_device_notify(ev);
-                               break;
-                       default:
-                               break;
+               switch(libinput_event_get_type(ev)) {
+               case LIBINPUT_EVENT_NONE:
+                       abort();
+               case LIBINPUT_EVENT_DEVICE_ADDED:
+               case LIBINPUT_EVENT_DEVICE_REMOVED:
+                       handle_device_notify(ev);
+                       break;
+               default:
+                       break;
+               }
+               libinput_event_destroy(ev);
+               libinput_dispatch(li);
+       }
+       return 0;
+}
+
+static int
+handle_motion_event(struct libinput_event *ev)
+{
+       struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
+       double x = libinput_event_pointer_get_dx(p);
+       double y = libinput_event_pointer_get_dy(p);
+       double ux = libinput_event_pointer_get_dx_unaccelerated(p);
+       double uy = libinput_event_pointer_get_dy_unaccelerated(p);
+       enum libinput_event_type type;
+
+       switch(libinput_event_get_type(ev)) {
+       case LIBINPUT_EVENT_POINTER_MOTION:
+               type = LIBINPUT_EVENT_POINTER_MOTION;
+               break;
+       default:
+               abort();
+       }
+       LOG("delta:  %6.2f/%6.2f , unaccel: (%+6.2f/%+6.2f)\n", x, y, ux, uy);
+       LOG("type = %d, button = %d, x = %d, y = %d, state = %d\n", queue_record_event[pop_idx].p.event_type, queue_record_event[pop_idx].p.button,
+                       queue_record_event[pop_idx].p.x, queue_record_event[pop_idx].p.y, queue_record_event[pop_idx].p.state);
+
+       if(queue_record_event[pop_idx].p.event_type != type) return -1;
+       if(queue_record_event[pop_idx].p.x != (int)ux) return -1;
+       if(queue_record_event[pop_idx].p.x != (int)uy) return -1;
+
+       EXPECT_EQ(queue_record_event[pop_idx].p.event_type, type);
+       EXPECT_EQ(queue_record_event[pop_idx].p.x, (int)ux);
+       EXPECT_EQ(queue_record_event[pop_idx].p.x, (int)uy);
+
+       return 0;
+}
+
+static int
+handle_absmotion_event(struct libinput_event *ev)
+{
+       struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
+       double x = libinput_event_pointer_get_absolute_x(p);
+       double y = libinput_event_pointer_get_absolute_y(p);
+       double tx = libinput_event_pointer_get_absolute_x_transformed(p, screen_width);
+       double ty = libinput_event_pointer_get_absolute_y_transformed(p, screen_height);
+       enum libinput_event_type type;
+
+       switch(libinput_event_get_type(ev)) {
+       case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+               type = LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE;
+               break;
+       default:
+               abort();
+       }
+       LOG("point: %6.2f/%6.2f,  transformed: %6.2f/%6.2f\n", x, y, tx, ty);
+       LOG("type = %d, button = %d, x = %d, y = %d, state = %d\n", queue_record_event[pop_idx].p.event_type, queue_record_event[pop_idx].p.button,
+                       queue_record_event[pop_idx].p.x, queue_record_event[pop_idx].p.y, queue_record_event[pop_idx].p.state);
+       EXPECT_EQ(queue_record_event[pop_idx].p.event_type, type);
+       return 0;
+}
+
+static int
+handle_pointer_button_event(struct libinput_event *ev)
+{
+       struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
+       enum libinput_event_type type;
+       enum libinput_button_state state;
+       const char *buttonname;
+       int button;
+
+       switch(libinput_event_get_type(ev)) {
+       case LIBINPUT_EVENT_POINTER_BUTTON:
+               type = LIBINPUT_EVENT_POINTER_BUTTON;
+               break;
+       default:
+               abort();
+       }
+
+       button = libinput_event_pointer_get_button(p);
+       buttonname = libevdev_event_code_get_name(EV_KEY, button);
+       state = libinput_event_pointer_get_button_state(p);
+
+       LOG("%s (%d) %s, seat count: %u\n",
+                       buttonname ? buttonname : "???",
+                       button,
+                       state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released",
+                       libinput_event_pointer_get_seat_button_count(p));
+
+       if(queue_record_event[pop_idx].p.event_type != type) return -1;
+       if(queue_record_event[pop_idx].p.button != button) return -1;
+       if(queue_record_event[pop_idx].p.state != state) return -1;
+
+       LOG("type = %d, button = %d, x = %d, y = %d, state = %d\n", queue_record_event[pop_idx].p.event_type, queue_record_event[pop_idx].p.button,
+                       queue_record_event[pop_idx].p.x, queue_record_event[pop_idx].p.y, queue_record_event[pop_idx].p.state);
+
+       EXPECT_EQ(queue_record_event[pop_idx].p.event_type, type);
+       EXPECT_EQ(queue_record_event[pop_idx].p.button, button);
+       EXPECT_EQ(queue_record_event[pop_idx].p.state, state);
+       return 0;
+}
+
+static int
+handle_key_event(struct libinput_event *ev)
+{
+       return 0;
+}
+
+static int
+handle_pointer_axis_event(struct libinput_event *ev)
+{
+       struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
+       enum libinput_event_type type;
+       const char *source;
+       double h = 0, v = 0;
+       int hd = 0, vd = 0;
+
+       switch(libinput_event_get_type(ev)) {
+       case LIBINPUT_EVENT_POINTER_AXIS:
+               type = LIBINPUT_EVENT_POINTER_AXIS;
+               break;
+       default:
+               abort();
+       }
+
+       if (libinput_event_pointer_has_axis(p,
+                               LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) {
+               h = libinput_event_pointer_get_axis_value(p,
+                               LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
+               hd = libinput_event_pointer_get_axis_value_discrete(p,
+                               LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
+       }
+       if (libinput_event_pointer_has_axis(p,
+                               LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) {
+               v = libinput_event_pointer_get_axis_value(p,
+                               LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
+               vd = libinput_event_pointer_get_axis_value_discrete(p,
+                               LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
+       }
+       switch(libinput_event_pointer_get_axis_source(p)) {
+       case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: source = "wheel"; break;
+       case LIBINPUT_POINTER_AXIS_SOURCE_FINGER: source = "finger"; break;
+       case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: source = "continuous"; break;
+       case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT: source = "wheel-tilt"; break;
+       default:
+               source = "unknown";
+               break;
+       }
+
+       LOG("axes: %2.2f, %2.2f, discrete: %d, %d, source: %s\n", h, v, hd, vd, source);
+       EXPECT_EQ(queue_record_event[pop_idx].p.event_type, type);
+       return 0;
+}
+
+static int
+handle_touch_event(struct libinput_event *ev)
+{
+       return 0;
+}
+
+int handle_libinput_event(struct libinput *li)
+{
+       int rc = -1;
+       struct libinput_event *ev;
+
+       libinput_dispatch(li);
+       while((ev = libinput_get_event(li))) {
+               switch(libinput_event_get_type(ev)) {
+               case LIBINPUT_EVENT_NONE:
+                       abort();
+               case LIBINPUT_EVENT_DEVICE_ADDED:
+               case LIBINPUT_EVENT_DEVICE_REMOVED:
+                       rc = handle_device_notify(ev);
+                       break;
+               case LIBINPUT_EVENT_KEYBOARD_KEY:
+                       pop_idx++;
+                       rc = handle_key_event(ev);
+                       break;
+               case LIBINPUT_EVENT_POINTER_MOTION:
+                       pop_idx++;
+                       rc = handle_motion_event(ev);
+                       break;
+               case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+                       pop_idx++;
+                       rc = handle_absmotion_event(ev);
+                       break;
+               case LIBINPUT_EVENT_POINTER_BUTTON:
+                       pop_idx++;
+                       rc = handle_pointer_button_event(ev);
+                       break;
+               case LIBINPUT_EVENT_POINTER_AXIS:
+                       pop_idx++;
+                       rc = handle_pointer_axis_event(ev);
+                       break;
+               case LIBINPUT_EVENT_TOUCH_DOWN:
+               case LIBINPUT_EVENT_TOUCH_UP:
+               case LIBINPUT_EVENT_TOUCH_MOTION:
+               case LIBINPUT_EVENT_TOUCH_CANCEL:
+                       pop_idx++;
+                       rc = handle_touch_event(ev);
+                       break;
+               case LIBINPUT_EVENT_TOUCH_FRAME:
+                       rc = handle_touch_event(ev);
+                       break;
+               default:
+                       break;
                }
                libinput_event_destroy(ev);
                libinput_dispatch(li);
+               if(rc < 0) return -1;
        }
        return 0;
 }
+
+int create_mouse_event(struct libinput *li, int idx)
+{
+       int fd = -1;
+       int n = 0;
+
+       struct record_event rc_e;
+       struct record_libinput_event_pointer p[] = {
+               {LIBINPUT_EVENT_POINTER_BUTTON, (int) BTN_LEFT, 100, 100, 1},
+               {LIBINPUT_EVENT_POINTER_MOTION, 0, 120, 120, 2},
+               {LIBINPUT_EVENT_POINTER_BUTTON, (int) BTN_LEFT, 200, 200, 0}
+       };
+
+       if(devices[idx].cap == LIBINPUT_DEVICE_CAP_POINTER){
+               LOG("create_mouse_event\n");
+               fd = open(devices[idx].path, O_RDWR);
+               if (fd < 0) {
+                       LOGE("ERROR: could not open device\n");
+                       return -1;
+               }
+
+               n = sizeof(p)/sizeof(struct record_libinput_event_pointer);
+               rc_e.device = LIBINPUT_DEVICE_CAP_POINTER;
+               for(int i=0; i<n; ++i)
+               {
+                       rc_e.p = p[i];
+
+                       if(input_mouse_event_gen(fd, p[i].button, p[i].x, p[i].y, p[i].state) < 0) {
+                               LOG("No device\n");
+                               continue;
+                       }
+                       queue_record_event[queue_idx++] = rc_e;
+               }
+
+               libinput_dispatch(li);
+               close(fd);
+       }
+       else
+               return -1;
+       return 0;
+}
+
+bool validate_mouse_event(struct libinput *li)
+{
+       bool val = false;
+       bool checked = false;
+       int ret = 0;
+
+       for(int i=0; i< devices_cnt; ++i) {
+               if(devices[i].cap == LIBINPUT_DEVICE_CAP_POINTER) {
+                       checked = true;
+                       LOG("LIBINPUT_DEVICE_CAP_POINTER, path = %s\n", devices[i].path);
+                       queue_idx = 0;
+                       pop_idx = -1;
+                       create_mouse_event(li, i);
+                       ret = handle_libinput_event(li);
+                       if(queue_idx == (pop_idx+1) && !ret) {
+                               val = true;
+                       }
+               }
+               if(val) return true;
+       }
+       if(!val && !checked){
+               LOG("No Devices\n");
+               return true;
+       }
+       return val;
+}
index 484989c..b0b99c0 100644 (file)
@@ -40,11 +40,42 @@ extern "C" {
 
 int handle_libinput_add_event(struct libinput *li);
 
+bool validate_mouse_event(struct libinput *li);
+
 struct record_device {
        enum libinput_device_capability cap;
        const char *path;
 };
 
+struct record_libinput_event_pointer {
+       enum libinput_event_type event_type;
+       int button;
+       int x;
+       int y;
+       int32_t state;
+};
+
+struct record_libinput_event_keyboard {
+       enum libinput_event_type event_type;
+       int key;  //keycode
+       int32_t state;
+};
+
+struct record_libinput_event_touch {
+       enum libinput_event_type event_type;
+       int idx;
+       int x;
+       int y;
+       int32_t state; //pressed
+ };
+
+struct record_event {
+       enum libinput_device_capability device;
+       struct record_libinput_event_pointer p;
+       struct record_libinput_event_keyboard k;
+       struct record_libinput_event_touch t;
+};
+
 #ifdef __cplusplus
 }
 #endif