1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef TEST_DEVICE_H
17 #define TEST_DEVICE_H
18 
19 #include <chrono>
20 #include <thread>
21 
22 #include <libevdev/libevdev-uinput.h>
23 #include <libevdev/libevdev.h>
24 
25 class TestDevice {
26 public:
27     static constexpr auto TEST_BUS = 0xBAD;
28     static constexpr auto TEST_VENDOR = 0x1234;
29     static constexpr auto TEST_PRODUCT = 0x5678;
30     static constexpr auto TEST_VERSION = 0xAA;
31     static constexpr auto TEST_NAME = "test device";
32 
TestDevice()33     TestDevice()
34     {
35         evdev_ = libevdev_new();
36     }
37 
~TestDevice()38     ~TestDevice()
39     {
40         if (uidev_ != nullptr) {
41             Destroy();
42         }
43         libevdev_free(evdev_);
44     }
45 
DefaultSetup()46     void DefaultSetup()
47     {
48         libevdev_set_name(evdev_, TEST_NAME);
49         libevdev_set_id_bustype(evdev_, TEST_BUS);
50         libevdev_set_id_vendor(evdev_, TEST_VENDOR);
51         libevdev_set_id_product(evdev_, TEST_PRODUCT); // fake product id
52         libevdev_set_id_version(evdev_, TEST_VERSION); // fake version id
53         libevdev_enable_event_type(evdev_, EV_REL);
54         libevdev_enable_event_code(evdev_, EV_REL, REL_X, nullptr);
55         libevdev_enable_event_code(evdev_, EV_REL, REL_Y, nullptr);
56         libevdev_enable_event_type(evdev_, EV_KEY);
57         libevdev_enable_event_code(evdev_, EV_KEY, BTN_LEFT, nullptr);
58         libevdev_enable_event_code(evdev_, EV_KEY, BTN_MIDDLE, nullptr);
59         libevdev_enable_event_code(evdev_, EV_KEY, BTN_RIGHT, nullptr);
60     }
61 
AbsMouseSetup()62     void AbsMouseSetup()
63     {
64         libevdev_set_name(evdev_, TEST_NAME);
65         libevdev_enable_event_type(evdev_, EV_ABS);
66         input_absinfo info{.maximum = 100};
67         libevdev_enable_event_code(evdev_, EV_ABS, ABS_X, &info);
68         libevdev_enable_event_code(evdev_, EV_ABS, ABS_Y, &info);
69         libevdev_enable_event_type(evdev_, EV_KEY);
70         libevdev_enable_event_code(evdev_, EV_KEY, BTN_LEFT, nullptr);
71         libevdev_enable_event_code(evdev_, EV_KEY, BTN_MIDDLE, nullptr);
72         libevdev_enable_event_code(evdev_, EV_KEY, BTN_RIGHT, nullptr);
73         // Test special case with too many axis here too
74         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_POSITION_X, &info);
75         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_POSITION_Y, &info);
76         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_SLOT, &info);
77         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_SLOT - 1, &info);
78     }
79 
WheelSetup()80     void WheelSetup()
81     {
82         // Also test special names
83         libevdev_set_name(evdev_, TEST_NAME);
84         libevdev_enable_event_type(evdev_, EV_REL);
85         libevdev_enable_event_code(evdev_, EV_REL, REL_WHEEL, nullptr);
86     }
87 
KeyboardSetup()88     void KeyboardSetup()
89     {
90         libevdev_set_name(evdev_, TEST_NAME);
91         libevdev_enable_event_type(evdev_, EV_KEY);
92         for (int32_t i = KEY_ESC; i < KEY_D; i++) {
93             libevdev_enable_event_code(evdev_, EV_KEY, i, nullptr);
94         }
95     }
96 
SwitchSetup()97     void SwitchSetup()
98     {
99         libevdev_set_name(evdev_, TEST_NAME);
100         libevdev_enable_event_type(evdev_, EV_SW);
101         libevdev_enable_event_code(evdev_, EV_SW, 0, nullptr);
102     }
103 
AccelerometerSetup()104     void AccelerometerSetup()
105     {
106         libevdev_set_name(evdev_, TEST_NAME);
107         libevdev_enable_event_type(evdev_, EV_ABS);
108         input_absinfo info{.maximum = 100};
109         libevdev_enable_event_code(evdev_, EV_ABS, ABS_X, &info);
110         libevdev_enable_event_code(evdev_, EV_ABS, ABS_Y, &info);
111         libevdev_enable_event_code(evdev_, EV_ABS, ABS_Z, &info);
112         libevdev_enable_property(evdev_, INPUT_PROP_ACCELEROMETER);
113     }
114 
StickSetup()115     void StickSetup()
116     {
117         libevdev_set_name(evdev_, TEST_NAME);
118         libevdev_enable_property(evdev_, INPUT_PROP_POINTING_STICK);
119     }
120 
TouchpadSetup()121     void TouchpadSetup()
122     {
123         libevdev_set_name(evdev_, TEST_NAME);
124         libevdev_enable_event_type(evdev_, EV_ABS);
125         input_absinfo info{.maximum = 100};
126         libevdev_enable_event_code(evdev_, EV_ABS, ABS_X, &info);
127         libevdev_enable_event_code(evdev_, EV_ABS, ABS_Y, &info);
128         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_POSITION_X, &info);
129         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_POSITION_Y, &info);
130         libevdev_enable_event_type(evdev_, EV_KEY);
131         libevdev_enable_event_code(evdev_, EV_KEY, BTN_TOOL_FINGER, nullptr);
132         libevdev_enable_event_code(evdev_, EV_KEY, BTN_TOUCH, nullptr);
133     }
134 
TouchscreenSetup()135     void TouchscreenSetup()
136     {
137         libevdev_set_name(evdev_, TEST_NAME);
138         libevdev_enable_event_type(evdev_, EV_ABS);
139         input_absinfo info{.maximum = 100};
140         libevdev_enable_event_code(evdev_, EV_ABS, ABS_X, &info);
141         libevdev_enable_event_code(evdev_, EV_ABS, ABS_Y, &info);
142         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_POSITION_X, &info);
143         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_POSITION_Y, &info);
144         libevdev_enable_event_type(evdev_, EV_KEY);
145         libevdev_enable_event_code(evdev_, EV_KEY, BTN_TOUCH, nullptr);
146         libevdev_enable_property(evdev_, INPUT_PROP_DIRECT);
147     }
148 
JoystickSetup()149     void JoystickSetup()
150     {
151         libevdev_set_name(evdev_, TEST_NAME);
152         libevdev_enable_event_type(evdev_, EV_KEY);
153         libevdev_enable_event_code(evdev_, EV_KEY, BTN_JOYSTICK, nullptr);
154     }
155 
JoystickSetup1()156     void JoystickSetup1()
157     {
158         libevdev_set_name(evdev_, TEST_NAME);
159         libevdev_enable_event_type(evdev_, EV_ABS);
160         input_absinfo info{.maximum = 100};
161         libevdev_enable_event_code(evdev_, EV_ABS, ABS_X, &info);
162         libevdev_enable_event_code(evdev_, EV_ABS, ABS_Y, &info);
163         libevdev_enable_event_code(evdev_, EV_ABS, ABS_RX, &info);
164         libevdev_enable_event_code(evdev_, EV_ABS, ABS_RY, &info);
165     }
166 
TabletSetup()167     void TabletSetup()
168     {
169         libevdev_set_name(evdev_, TEST_NAME);
170         libevdev_enable_event_type(evdev_, EV_ABS);
171         input_absinfo info{.maximum = 100, .resolution = 10};
172         libevdev_enable_event_code(evdev_, EV_ABS, ABS_X, &info);
173         libevdev_enable_event_code(evdev_, EV_ABS, ABS_Y, &info);
174         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_POSITION_X, &info);
175         libevdev_enable_event_code(evdev_, EV_ABS, ABS_MT_POSITION_Y, &info);
176         libevdev_enable_event_type(evdev_, EV_KEY);
177         libevdev_enable_event_code(evdev_, EV_KEY, BTN_STYLUS, nullptr);
178     }
179 
Destroy()180     void Destroy()
181     {
182         libevdev_uinput_destroy(uidev_);
183         uidev_ = nullptr;
184     }
185 
GetDevNode()186     auto GetDevNode()
187     {
188         return libevdev_uinput_get_devnode(uidev_);
189     }
190 
GetSysPath()191     auto GetSysPath()
192     {
193         return libevdev_uinput_get_syspath(uidev_);
194     }
195 
GetDevNum()196     auto GetDevNum() const
197     {
198         return devnum_;
199     }
200 
SetDevnum()201     bool SetDevnum()
202     {
203         const auto* fname = libevdev_uinput_get_devnode(uidev_);
204         if (fname == nullptr) {
205             return false;
206         }
207         struct stat st;
208         int t = stat(fname, &st);
209         if (t < 0) {
210             return false;
211         }
212         devnum_ = st.st_rdev;
213         return true;
214     }
215 
216     void Init(bool def = true)
217     {
218         using namespace std::chrono_literals;
219         constexpr auto initDelay = 50ms;
220         ASSERT_NE(evdev_, nullptr);
221         if (def) {
222             DefaultSetup();
223         }
224         auto res = libevdev_uinput_create_from_device(evdev_, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev_);
225         auto err = std::error_code{errno, std::system_category()};
226         ASSERT_EQ(res, 0) << "Failed to create uinput device. Error: " << err.message()
227                           << (err == std::errc::permission_denied ? ". Run test as ROOT!" : "") << std::endl;
228         ASSERT_NE(uidev_, nullptr);
229 
230         std::this_thread::sleep_for(initDelay);
231         ASSERT_TRUE(SetDevnum());
232     }
233 
234 private:
235     struct libevdev* evdev_ {};
236     struct libevdev_uinput* uidev_ {};
237     dev_t devnum_ {};
238 };
239 #endif // TEST_DEVICE_H
240