xref: /aosp_15_r20/frameworks/native/libs/input/VirtualInputDevice.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "VirtualInputDevice"
18 
19 #include <android-base/logging.h>
20 #include <android/input.h>
21 #include <android/keycodes.h>
22 #include <android_companion_virtualdevice_flags.h>
23 #include <fcntl.h>
24 #include <input/Input.h>
25 #include <input/VirtualInputDevice.h>
26 #include <linux/uinput.h>
27 
28 #include <string>
29 
30 using android::base::unique_fd;
31 
32 namespace {
33 
34 /**
35  * Log debug messages about native virtual input devices.
36  * Enable this via "adb shell setprop log.tag.VirtualInputDevice DEBUG"
37  */
isDebug()38 bool isDebug() {
39     return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
40 }
41 
invalidFd()42 unique_fd invalidFd() {
43     return unique_fd(-1);
44 }
45 
46 } // namespace
47 
48 namespace android {
49 
50 namespace vd_flags = android::companion::virtualdevice::flags;
51 
52 /** Creates a new uinput device and assigns a file descriptor. */
openUinput(const char * readableName,int32_t vendorId,int32_t productId,const char * phys,DeviceType deviceType,int32_t screenHeight,int32_t screenWidth)53 unique_fd openUinput(const char* readableName, int32_t vendorId, int32_t productId,
54                      const char* phys, DeviceType deviceType, int32_t screenHeight,
55                      int32_t screenWidth) {
56     unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK)));
57     if (fd < 0) {
58         ALOGE("Error creating uinput device: %s", strerror(errno));
59         return invalidFd();
60     }
61 
62     ioctl(fd, UI_SET_PHYS, phys);
63 
64     ioctl(fd, UI_SET_EVBIT, EV_KEY);
65     ioctl(fd, UI_SET_EVBIT, EV_SYN);
66     switch (deviceType) {
67         case DeviceType::DPAD:
68             for (const auto& [_, keyCode] : VirtualDpad::DPAD_KEY_CODE_MAPPING) {
69                 ioctl(fd, UI_SET_KEYBIT, keyCode);
70             }
71             break;
72         case DeviceType::KEYBOARD:
73             for (const auto& [_, keyCode] : VirtualKeyboard::KEY_CODE_MAPPING) {
74                 ioctl(fd, UI_SET_KEYBIT, keyCode);
75             }
76             break;
77         case DeviceType::MOUSE:
78             ioctl(fd, UI_SET_EVBIT, EV_REL);
79             ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
80             ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
81             ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
82             ioctl(fd, UI_SET_KEYBIT, BTN_BACK);
83             ioctl(fd, UI_SET_KEYBIT, BTN_FORWARD);
84             ioctl(fd, UI_SET_RELBIT, REL_X);
85             ioctl(fd, UI_SET_RELBIT, REL_Y);
86             ioctl(fd, UI_SET_RELBIT, REL_WHEEL);
87             ioctl(fd, UI_SET_RELBIT, REL_HWHEEL);
88             if (vd_flags::high_resolution_scroll()) {
89                 ioctl(fd, UI_SET_RELBIT, REL_WHEEL_HI_RES);
90                 ioctl(fd, UI_SET_RELBIT, REL_HWHEEL_HI_RES);
91             }
92             break;
93         case DeviceType::TOUCHSCREEN:
94             ioctl(fd, UI_SET_EVBIT, EV_ABS);
95             ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH);
96             ioctl(fd, UI_SET_ABSBIT, ABS_MT_SLOT);
97             ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X);
98             ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y);
99             ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID);
100             ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOOL_TYPE);
101             ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR);
102             ioctl(fd, UI_SET_ABSBIT, ABS_MT_PRESSURE);
103             ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);
104             break;
105         case DeviceType::STYLUS:
106             ioctl(fd, UI_SET_EVBIT, EV_ABS);
107             ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH);
108             ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS);
109             ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS2);
110             ioctl(fd, UI_SET_KEYBIT, BTN_TOOL_PEN);
111             ioctl(fd, UI_SET_KEYBIT, BTN_TOOL_RUBBER);
112             ioctl(fd, UI_SET_ABSBIT, ABS_X);
113             ioctl(fd, UI_SET_ABSBIT, ABS_Y);
114             ioctl(fd, UI_SET_ABSBIT, ABS_TILT_X);
115             ioctl(fd, UI_SET_ABSBIT, ABS_TILT_Y);
116             ioctl(fd, UI_SET_ABSBIT, ABS_PRESSURE);
117             ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);
118             break;
119         case DeviceType::ROTARY_ENCODER:
120             ioctl(fd, UI_SET_EVBIT, EV_REL);
121             ioctl(fd, UI_SET_RELBIT, REL_WHEEL);
122             if (vd_flags::high_resolution_scroll()) {
123                 ioctl(fd, UI_SET_RELBIT, REL_WHEEL_HI_RES);
124             }
125             break;
126         default:
127             ALOGE("Invalid input device type %d", static_cast<int32_t>(deviceType));
128             return invalidFd();
129     }
130 
131     int version;
132     if (ioctl(fd, UI_GET_VERSION, &version) == 0 && version >= 5) {
133         uinput_setup setup;
134         memset(&setup, 0, sizeof(setup));
135         std::strncpy(setup.name, readableName, UINPUT_MAX_NAME_SIZE);
136         setup.id.version = 1;
137         setup.id.bustype = BUS_VIRTUAL;
138         setup.id.vendor = vendorId;
139         setup.id.product = productId;
140         if (deviceType == DeviceType::TOUCHSCREEN) {
141             uinput_abs_setup xAbsSetup;
142             xAbsSetup.code = ABS_MT_POSITION_X;
143             xAbsSetup.absinfo.maximum = screenWidth - 1;
144             xAbsSetup.absinfo.minimum = 0;
145             if (ioctl(fd, UI_ABS_SETUP, &xAbsSetup) != 0) {
146                 ALOGE("Error creating touchscreen uinput x axis: %s", strerror(errno));
147                 return invalidFd();
148             }
149             uinput_abs_setup yAbsSetup;
150             yAbsSetup.code = ABS_MT_POSITION_Y;
151             yAbsSetup.absinfo.maximum = screenHeight - 1;
152             yAbsSetup.absinfo.minimum = 0;
153             if (ioctl(fd, UI_ABS_SETUP, &yAbsSetup) != 0) {
154                 ALOGE("Error creating touchscreen uinput y axis: %s", strerror(errno));
155                 return invalidFd();
156             }
157             uinput_abs_setup majorAbsSetup;
158             majorAbsSetup.code = ABS_MT_TOUCH_MAJOR;
159             majorAbsSetup.absinfo.maximum = screenWidth - 1;
160             majorAbsSetup.absinfo.minimum = 0;
161             if (ioctl(fd, UI_ABS_SETUP, &majorAbsSetup) != 0) {
162                 ALOGE("Error creating touchscreen uinput major axis: %s", strerror(errno));
163                 return invalidFd();
164             }
165             uinput_abs_setup pressureAbsSetup;
166             pressureAbsSetup.code = ABS_MT_PRESSURE;
167             pressureAbsSetup.absinfo.maximum = 255;
168             pressureAbsSetup.absinfo.minimum = 0;
169             if (ioctl(fd, UI_ABS_SETUP, &pressureAbsSetup) != 0) {
170                 ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
171                 return invalidFd();
172             }
173             uinput_abs_setup slotAbsSetup;
174             slotAbsSetup.code = ABS_MT_SLOT;
175             slotAbsSetup.absinfo.maximum = MAX_POINTERS - 1;
176             slotAbsSetup.absinfo.minimum = 0;
177             if (ioctl(fd, UI_ABS_SETUP, &slotAbsSetup) != 0) {
178                 ALOGE("Error creating touchscreen uinput slots: %s", strerror(errno));
179                 return invalidFd();
180             }
181             uinput_abs_setup trackingIdAbsSetup;
182             trackingIdAbsSetup.code = ABS_MT_TRACKING_ID;
183             trackingIdAbsSetup.absinfo.maximum = MAX_POINTERS - 1;
184             trackingIdAbsSetup.absinfo.minimum = 0;
185             if (ioctl(fd, UI_ABS_SETUP, &trackingIdAbsSetup) != 0) {
186                 ALOGE("Error creating touchscreen uinput tracking ids: %s", strerror(errno));
187                 return invalidFd();
188             }
189         } else if (deviceType == DeviceType::STYLUS) {
190             uinput_abs_setup xAbsSetup;
191             xAbsSetup.code = ABS_X;
192             xAbsSetup.absinfo.maximum = screenWidth - 1;
193             xAbsSetup.absinfo.minimum = 0;
194             if (ioctl(fd, UI_ABS_SETUP, &xAbsSetup) != 0) {
195                 ALOGE("Error creating stylus uinput x axis: %s", strerror(errno));
196                 return invalidFd();
197             }
198             uinput_abs_setup yAbsSetup;
199             yAbsSetup.code = ABS_Y;
200             yAbsSetup.absinfo.maximum = screenHeight - 1;
201             yAbsSetup.absinfo.minimum = 0;
202             if (ioctl(fd, UI_ABS_SETUP, &yAbsSetup) != 0) {
203                 ALOGE("Error creating stylus uinput y axis: %s", strerror(errno));
204                 return invalidFd();
205             }
206             uinput_abs_setup tiltXAbsSetup;
207             tiltXAbsSetup.code = ABS_TILT_X;
208             tiltXAbsSetup.absinfo.maximum = 90;
209             tiltXAbsSetup.absinfo.minimum = -90;
210             if (ioctl(fd, UI_ABS_SETUP, &tiltXAbsSetup) != 0) {
211                 ALOGE("Error creating stylus uinput tilt x axis: %s", strerror(errno));
212                 return invalidFd();
213             }
214             uinput_abs_setup tiltYAbsSetup;
215             tiltYAbsSetup.code = ABS_TILT_Y;
216             tiltYAbsSetup.absinfo.maximum = 90;
217             tiltYAbsSetup.absinfo.minimum = -90;
218             if (ioctl(fd, UI_ABS_SETUP, &tiltYAbsSetup) != 0) {
219                 ALOGE("Error creating stylus uinput tilt y axis: %s", strerror(errno));
220                 return invalidFd();
221             }
222             uinput_abs_setup pressureAbsSetup;
223             pressureAbsSetup.code = ABS_PRESSURE;
224             pressureAbsSetup.absinfo.maximum = 255;
225             pressureAbsSetup.absinfo.minimum = 0;
226             if (ioctl(fd, UI_ABS_SETUP, &pressureAbsSetup) != 0) {
227                 ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
228                 return invalidFd();
229             }
230         }
231         if (ioctl(fd, UI_DEV_SETUP, &setup) != 0) {
232             ALOGE("Error creating uinput device: %s", strerror(errno));
233             return invalidFd();
234         }
235     } else {
236         // UI_DEV_SETUP was not introduced until version 5. Try setting up manually.
237         ALOGI("Falling back to version %d manual setup", version);
238         uinput_user_dev fallback;
239         memset(&fallback, 0, sizeof(fallback));
240         std::strncpy(fallback.name, readableName, UINPUT_MAX_NAME_SIZE);
241         fallback.id.version = 1;
242         fallback.id.bustype = BUS_VIRTUAL;
243         fallback.id.vendor = vendorId;
244         fallback.id.product = productId;
245         if (deviceType == DeviceType::TOUCHSCREEN) {
246             fallback.absmin[ABS_MT_POSITION_X] = 0;
247             fallback.absmax[ABS_MT_POSITION_X] = screenWidth - 1;
248             fallback.absmin[ABS_MT_POSITION_Y] = 0;
249             fallback.absmax[ABS_MT_POSITION_Y] = screenHeight - 1;
250             fallback.absmin[ABS_MT_TOUCH_MAJOR] = 0;
251             fallback.absmax[ABS_MT_TOUCH_MAJOR] = screenWidth - 1;
252             fallback.absmin[ABS_MT_PRESSURE] = 0;
253             fallback.absmax[ABS_MT_PRESSURE] = 255;
254         } else if (deviceType == DeviceType::STYLUS) {
255             fallback.absmin[ABS_X] = 0;
256             fallback.absmax[ABS_X] = screenWidth - 1;
257             fallback.absmin[ABS_Y] = 0;
258             fallback.absmax[ABS_Y] = screenHeight - 1;
259             fallback.absmin[ABS_TILT_X] = -90;
260             fallback.absmax[ABS_TILT_X] = 90;
261             fallback.absmin[ABS_TILT_Y] = -90;
262             fallback.absmax[ABS_TILT_Y] = 90;
263             fallback.absmin[ABS_PRESSURE] = 0;
264             fallback.absmax[ABS_PRESSURE] = 255;
265         }
266         if (TEMP_FAILURE_RETRY(write(fd, &fallback, sizeof(fallback))) != sizeof(fallback)) {
267             ALOGE("Error creating uinput device: %s", strerror(errno));
268             return invalidFd();
269         }
270     }
271 
272     if (ioctl(fd, UI_DEV_CREATE) != 0) {
273         ALOGE("Error creating uinput device: %s", strerror(errno));
274         return invalidFd();
275     }
276 
277     return fd;
278 }
279 
VirtualInputDevice(unique_fd fd)280 VirtualInputDevice::VirtualInputDevice(unique_fd fd) : mFd(std::move(fd)) {}
281 
~VirtualInputDevice()282 VirtualInputDevice::~VirtualInputDevice() {
283     ioctl(mFd, UI_DEV_DESTROY);
284 }
285 
writeInputEvent(uint16_t type,uint16_t code,int32_t value,std::chrono::nanoseconds eventTime)286 bool VirtualInputDevice::writeInputEvent(uint16_t type, uint16_t code, int32_t value,
287                                          std::chrono::nanoseconds eventTime) {
288     std::chrono::seconds seconds = std::chrono::duration_cast<std::chrono::seconds>(eventTime);
289     std::chrono::microseconds microseconds =
290             std::chrono::duration_cast<std::chrono::microseconds>(eventTime - seconds);
291     struct input_event ev = {.type = type, .code = code, .value = value};
292     ev.input_event_sec = static_cast<decltype(ev.input_event_sec)>(seconds.count());
293     ev.input_event_usec = static_cast<decltype(ev.input_event_usec)>(microseconds.count());
294 
295     return TEMP_FAILURE_RETRY(write(mFd, &ev, sizeof(struct input_event))) == sizeof(ev);
296 }
297 
298 /** Utility method to write keyboard key events or mouse/stylus button events. */
writeEvKeyEvent(int32_t androidCode,int32_t androidAction,const std::map<int,int> & evKeyCodeMapping,const std::map<int,UinputAction> & actionMapping,std::chrono::nanoseconds eventTime)299 bool VirtualInputDevice::writeEvKeyEvent(int32_t androidCode, int32_t androidAction,
300                                          const std::map<int, int>& evKeyCodeMapping,
301                                          const std::map<int, UinputAction>& actionMapping,
302                                          std::chrono::nanoseconds eventTime) {
303     auto evKeyCodeIterator = evKeyCodeMapping.find(androidCode);
304     if (evKeyCodeIterator == evKeyCodeMapping.end()) {
305         ALOGE("Unsupported native EV keycode for android code %d", androidCode);
306         return false;
307     }
308     auto actionIterator = actionMapping.find(androidAction);
309     if (actionIterator == actionMapping.end()) {
310         ALOGE("Unsupported native action for android action %d", androidAction);
311         return false;
312     }
313     int32_t action = static_cast<int32_t>(actionIterator->second);
314     uint16_t evKeyCode = static_cast<uint16_t>(evKeyCodeIterator->second);
315     if (!writeInputEvent(EV_KEY, evKeyCode, action, eventTime)) {
316         ALOGE("Failed to write native action %d and EV keycode %u.", action, evKeyCode);
317         return false;
318     }
319     if (!writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime)) {
320         ALOGE("Failed to write SYN_REPORT for EV_KEY event.");
321         return false;
322     }
323     return true;
324 }
325 
326 // --- VirtualKeyboard ---
327 const std::map<int, UinputAction> VirtualKeyboard::KEY_ACTION_MAPPING = {
328         {AKEY_EVENT_ACTION_DOWN, UinputAction::PRESS},
329         {AKEY_EVENT_ACTION_UP, UinputAction::RELEASE},
330 };
331 
332 // Keycode mapping from https://source.android.com/devices/input/keyboard-devices
333 const std::map<int, int> VirtualKeyboard::KEY_CODE_MAPPING = {
334         {AKEYCODE_0, KEY_0},
335         {AKEYCODE_1, KEY_1},
336         {AKEYCODE_2, KEY_2},
337         {AKEYCODE_3, KEY_3},
338         {AKEYCODE_4, KEY_4},
339         {AKEYCODE_5, KEY_5},
340         {AKEYCODE_6, KEY_6},
341         {AKEYCODE_7, KEY_7},
342         {AKEYCODE_8, KEY_8},
343         {AKEYCODE_9, KEY_9},
344         {AKEYCODE_A, KEY_A},
345         {AKEYCODE_B, KEY_B},
346         {AKEYCODE_C, KEY_C},
347         {AKEYCODE_D, KEY_D},
348         {AKEYCODE_E, KEY_E},
349         {AKEYCODE_F, KEY_F},
350         {AKEYCODE_G, KEY_G},
351         {AKEYCODE_H, KEY_H},
352         {AKEYCODE_I, KEY_I},
353         {AKEYCODE_J, KEY_J},
354         {AKEYCODE_K, KEY_K},
355         {AKEYCODE_L, KEY_L},
356         {AKEYCODE_M, KEY_M},
357         {AKEYCODE_N, KEY_N},
358         {AKEYCODE_O, KEY_O},
359         {AKEYCODE_P, KEY_P},
360         {AKEYCODE_Q, KEY_Q},
361         {AKEYCODE_R, KEY_R},
362         {AKEYCODE_S, KEY_S},
363         {AKEYCODE_T, KEY_T},
364         {AKEYCODE_U, KEY_U},
365         {AKEYCODE_V, KEY_V},
366         {AKEYCODE_W, KEY_W},
367         {AKEYCODE_X, KEY_X},
368         {AKEYCODE_Y, KEY_Y},
369         {AKEYCODE_Z, KEY_Z},
370         {AKEYCODE_GRAVE, KEY_GRAVE},
371         {AKEYCODE_MINUS, KEY_MINUS},
372         {AKEYCODE_EQUALS, KEY_EQUAL},
373         {AKEYCODE_LEFT_BRACKET, KEY_LEFTBRACE},
374         {AKEYCODE_RIGHT_BRACKET, KEY_RIGHTBRACE},
375         {AKEYCODE_BACKSLASH, KEY_BACKSLASH},
376         {AKEYCODE_SEMICOLON, KEY_SEMICOLON},
377         {AKEYCODE_APOSTROPHE, KEY_APOSTROPHE},
378         {AKEYCODE_COMMA, KEY_COMMA},
379         {AKEYCODE_PERIOD, KEY_DOT},
380         {AKEYCODE_SLASH, KEY_SLASH},
381         {AKEYCODE_ALT_LEFT, KEY_LEFTALT},
382         {AKEYCODE_ALT_RIGHT, KEY_RIGHTALT},
383         {AKEYCODE_CTRL_LEFT, KEY_LEFTCTRL},
384         {AKEYCODE_CTRL_RIGHT, KEY_RIGHTCTRL},
385         {AKEYCODE_SHIFT_LEFT, KEY_LEFTSHIFT},
386         {AKEYCODE_SHIFT_RIGHT, KEY_RIGHTSHIFT},
387         {AKEYCODE_META_LEFT, KEY_LEFTMETA},
388         {AKEYCODE_META_RIGHT, KEY_RIGHTMETA},
389         {AKEYCODE_CAPS_LOCK, KEY_CAPSLOCK},
390         {AKEYCODE_SCROLL_LOCK, KEY_SCROLLLOCK},
391         {AKEYCODE_NUM_LOCK, KEY_NUMLOCK},
392         {AKEYCODE_ENTER, KEY_ENTER},
393         {AKEYCODE_TAB, KEY_TAB},
394         {AKEYCODE_SPACE, KEY_SPACE},
395         {AKEYCODE_DPAD_DOWN, KEY_DOWN},
396         {AKEYCODE_DPAD_UP, KEY_UP},
397         {AKEYCODE_DPAD_LEFT, KEY_LEFT},
398         {AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
399         {AKEYCODE_MOVE_END, KEY_END},
400         {AKEYCODE_MOVE_HOME, KEY_HOME},
401         {AKEYCODE_PAGE_DOWN, KEY_PAGEDOWN},
402         {AKEYCODE_PAGE_UP, KEY_PAGEUP},
403         {AKEYCODE_DEL, KEY_BACKSPACE},
404         {AKEYCODE_FORWARD_DEL, KEY_DELETE},
405         {AKEYCODE_INSERT, KEY_INSERT},
406         {AKEYCODE_ESCAPE, KEY_ESC},
407         {AKEYCODE_BREAK, KEY_PAUSE},
408         {AKEYCODE_F1, KEY_F1},
409         {AKEYCODE_F2, KEY_F2},
410         {AKEYCODE_F3, KEY_F3},
411         {AKEYCODE_F4, KEY_F4},
412         {AKEYCODE_F5, KEY_F5},
413         {AKEYCODE_F6, KEY_F6},
414         {AKEYCODE_F7, KEY_F7},
415         {AKEYCODE_F8, KEY_F8},
416         {AKEYCODE_F9, KEY_F9},
417         {AKEYCODE_F10, KEY_F10},
418         {AKEYCODE_F11, KEY_F11},
419         {AKEYCODE_F12, KEY_F12},
420         {AKEYCODE_BACK, KEY_BACK},
421         {AKEYCODE_FORWARD, KEY_FORWARD},
422         {AKEYCODE_NUMPAD_1, KEY_KP1},
423         {AKEYCODE_NUMPAD_2, KEY_KP2},
424         {AKEYCODE_NUMPAD_3, KEY_KP3},
425         {AKEYCODE_NUMPAD_4, KEY_KP4},
426         {AKEYCODE_NUMPAD_5, KEY_KP5},
427         {AKEYCODE_NUMPAD_6, KEY_KP6},
428         {AKEYCODE_NUMPAD_7, KEY_KP7},
429         {AKEYCODE_NUMPAD_8, KEY_KP8},
430         {AKEYCODE_NUMPAD_9, KEY_KP9},
431         {AKEYCODE_NUMPAD_0, KEY_KP0},
432         {AKEYCODE_NUMPAD_ADD, KEY_KPPLUS},
433         {AKEYCODE_NUMPAD_SUBTRACT, KEY_KPMINUS},
434         {AKEYCODE_NUMPAD_MULTIPLY, KEY_KPASTERISK},
435         {AKEYCODE_NUMPAD_DIVIDE, KEY_KPSLASH},
436         {AKEYCODE_NUMPAD_DOT, KEY_KPDOT},
437         {AKEYCODE_NUMPAD_ENTER, KEY_KPENTER},
438         {AKEYCODE_NUMPAD_EQUALS, KEY_KPEQUAL},
439         {AKEYCODE_NUMPAD_COMMA, KEY_KPCOMMA},
440         {AKEYCODE_LANGUAGE_SWITCH, KEY_LANGUAGE},
441 };
442 
VirtualKeyboard(unique_fd fd)443 VirtualKeyboard::VirtualKeyboard(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
444 
~VirtualKeyboard()445 VirtualKeyboard::~VirtualKeyboard() {}
446 
writeKeyEvent(int32_t androidKeyCode,int32_t androidAction,std::chrono::nanoseconds eventTime)447 bool VirtualKeyboard::writeKeyEvent(int32_t androidKeyCode, int32_t androidAction,
448                                     std::chrono::nanoseconds eventTime) {
449     return writeEvKeyEvent(androidKeyCode, androidAction, KEY_CODE_MAPPING, KEY_ACTION_MAPPING,
450                            eventTime);
451 }
452 
453 // --- VirtualDpad ---
454 // Dpad keycode mapping from https://source.android.com/devices/input/keyboard-devices
455 const std::map<int, int> VirtualDpad::DPAD_KEY_CODE_MAPPING = {
456         // clang-format off
457         {AKEYCODE_DPAD_DOWN, KEY_DOWN},
458         {AKEYCODE_DPAD_UP, KEY_UP},
459         {AKEYCODE_DPAD_LEFT, KEY_LEFT},
460         {AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
461         {AKEYCODE_DPAD_CENTER, KEY_SELECT},
462         {AKEYCODE_BACK, KEY_BACK},
463         // clang-format on
464 };
465 
VirtualDpad(unique_fd fd)466 VirtualDpad::VirtualDpad(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
467 
~VirtualDpad()468 VirtualDpad::~VirtualDpad() {}
469 
writeDpadKeyEvent(int32_t androidKeyCode,int32_t androidAction,std::chrono::nanoseconds eventTime)470 bool VirtualDpad::writeDpadKeyEvent(int32_t androidKeyCode, int32_t androidAction,
471                                     std::chrono::nanoseconds eventTime) {
472     return writeEvKeyEvent(androidKeyCode, androidAction, DPAD_KEY_CODE_MAPPING,
473                            VirtualKeyboard::KEY_ACTION_MAPPING, eventTime);
474 }
475 
476 // --- VirtualMouse ---
477 const std::map<int, UinputAction> VirtualMouse::BUTTON_ACTION_MAPPING = {
478         {AMOTION_EVENT_ACTION_BUTTON_PRESS, UinputAction::PRESS},
479         {AMOTION_EVENT_ACTION_BUTTON_RELEASE, UinputAction::RELEASE},
480 };
481 
482 // Button code mapping from https://source.android.com/devices/input/touch-devices
483 const std::map<int, int> VirtualMouse::BUTTON_CODE_MAPPING = {
484         // clang-format off
485         {AMOTION_EVENT_BUTTON_PRIMARY, BTN_LEFT},
486         {AMOTION_EVENT_BUTTON_SECONDARY, BTN_RIGHT},
487         {AMOTION_EVENT_BUTTON_TERTIARY, BTN_MIDDLE},
488         {AMOTION_EVENT_BUTTON_BACK, BTN_BACK},
489         {AMOTION_EVENT_BUTTON_FORWARD, BTN_FORWARD},
490         // clang-format on
491 };
492 
VirtualMouse(unique_fd fd)493 VirtualMouse::VirtualMouse(unique_fd fd)
494       : VirtualInputDevice(std::move(fd)),
495         mAccumulatedHighResScrollX(0),
496         mAccumulatedHighResScrollY(0) {}
497 
~VirtualMouse()498 VirtualMouse::~VirtualMouse() {}
499 
writeButtonEvent(int32_t androidButtonCode,int32_t androidAction,std::chrono::nanoseconds eventTime)500 bool VirtualMouse::writeButtonEvent(int32_t androidButtonCode, int32_t androidAction,
501                                     std::chrono::nanoseconds eventTime) {
502     return writeEvKeyEvent(androidButtonCode, androidAction, BUTTON_CODE_MAPPING,
503                            BUTTON_ACTION_MAPPING, eventTime);
504 }
505 
writeRelativeEvent(float relativeX,float relativeY,std::chrono::nanoseconds eventTime)506 bool VirtualMouse::writeRelativeEvent(float relativeX, float relativeY,
507                                       std::chrono::nanoseconds eventTime) {
508     return writeInputEvent(EV_REL, REL_X, relativeX, eventTime) &&
509             writeInputEvent(EV_REL, REL_Y, relativeY, eventTime) &&
510             writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
511 }
512 
writeScrollEvent(float xAxisMovement,float yAxisMovement,std::chrono::nanoseconds eventTime)513 bool VirtualMouse::writeScrollEvent(float xAxisMovement, float yAxisMovement,
514                                     std::chrono::nanoseconds eventTime) {
515     if (!vd_flags::high_resolution_scroll()) {
516         return writeInputEvent(EV_REL, REL_HWHEEL, static_cast<int32_t>(xAxisMovement),
517                                eventTime) &&
518                 writeInputEvent(EV_REL, REL_WHEEL, static_cast<int32_t>(yAxisMovement),
519                                 eventTime) &&
520                 writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
521     }
522 
523     const auto highResScrollX =
524             static_cast<int32_t>(xAxisMovement * kEvdevHighResScrollUnitsPerDetent);
525     const auto highResScrollY =
526             static_cast<int32_t>(yAxisMovement * kEvdevHighResScrollUnitsPerDetent);
527     bool highResScrollResult =
528             writeInputEvent(EV_REL, REL_HWHEEL_HI_RES, highResScrollX, eventTime) &&
529             writeInputEvent(EV_REL, REL_WHEEL_HI_RES, highResScrollY, eventTime);
530     if (!highResScrollResult) {
531         return false;
532     }
533 
534     // According to evdev spec, a high-resolution mouse needs to emit REL_WHEEL / REL_HWHEEL events
535     // in addition to high-res scroll events. Regular scroll events can approximate high-res scroll
536     // events, so we send a regular scroll event when the accumulated scroll motion reaches a detent
537     // (single mouse wheel click).
538     mAccumulatedHighResScrollX += highResScrollX;
539     mAccumulatedHighResScrollY += highResScrollY;
540     const int32_t scrollX = mAccumulatedHighResScrollX / kEvdevHighResScrollUnitsPerDetent;
541     const int32_t scrollY = mAccumulatedHighResScrollY / kEvdevHighResScrollUnitsPerDetent;
542     if (scrollX != 0) {
543         if (!writeInputEvent(EV_REL, REL_HWHEEL, scrollX, eventTime)) {
544             return false;
545         }
546         mAccumulatedHighResScrollX %= kEvdevHighResScrollUnitsPerDetent;
547     }
548     if (scrollY != 0) {
549         if (!writeInputEvent(EV_REL, REL_WHEEL, scrollY, eventTime)) {
550             return false;
551         }
552         mAccumulatedHighResScrollY %= kEvdevHighResScrollUnitsPerDetent;
553     }
554 
555     return writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
556 }
557 
558 // --- VirtualTouchscreen ---
559 const std::map<int, UinputAction> VirtualTouchscreen::TOUCH_ACTION_MAPPING = {
560         {AMOTION_EVENT_ACTION_DOWN, UinputAction::PRESS},
561         {AMOTION_EVENT_ACTION_UP, UinputAction::RELEASE},
562         {AMOTION_EVENT_ACTION_MOVE, UinputAction::MOVE},
563         {AMOTION_EVENT_ACTION_CANCEL, UinputAction::CANCEL},
564 };
565 
566 // Tool type mapping from https://source.android.com/devices/input/touch-devices
567 const std::map<int, int> VirtualTouchscreen::TOOL_TYPE_MAPPING = {
568         {AMOTION_EVENT_TOOL_TYPE_FINGER, MT_TOOL_FINGER},
569         {AMOTION_EVENT_TOOL_TYPE_PALM, MT_TOOL_PALM},
570 };
571 
VirtualTouchscreen(unique_fd fd)572 VirtualTouchscreen::VirtualTouchscreen(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
573 
~VirtualTouchscreen()574 VirtualTouchscreen::~VirtualTouchscreen() {}
575 
isValidPointerId(int32_t pointerId,UinputAction uinputAction)576 bool VirtualTouchscreen::isValidPointerId(int32_t pointerId, UinputAction uinputAction) {
577     if (pointerId < -1 || pointerId >= (int)MAX_POINTERS) {
578         ALOGE("Virtual touch event has invalid pointer id %d; value must be between -1 and %zu",
579               pointerId, MAX_POINTERS - 0);
580         return false;
581     }
582 
583     if (uinputAction == UinputAction::PRESS && mActivePointers.test(pointerId)) {
584         ALOGE("Repetitive action DOWN event received on a pointer %d that is already down.",
585               pointerId);
586         return false;
587     }
588     if (uinputAction == UinputAction::RELEASE && !mActivePointers.test(pointerId)) {
589         ALOGE("PointerId %d action UP received with no prior action DOWN on touchscreen %d.",
590               pointerId, mFd.get());
591         return false;
592     }
593     return true;
594 }
595 
writeTouchEvent(int32_t pointerId,int32_t toolType,int32_t action,float locationX,float locationY,float pressure,float majorAxisSize,std::chrono::nanoseconds eventTime)596 bool VirtualTouchscreen::writeTouchEvent(int32_t pointerId, int32_t toolType, int32_t action,
597                                          float locationX, float locationY, float pressure,
598                                          float majorAxisSize, std::chrono::nanoseconds eventTime) {
599     auto actionIterator = TOUCH_ACTION_MAPPING.find(action);
600     if (actionIterator == TOUCH_ACTION_MAPPING.end()) {
601         return false;
602     }
603     UinputAction uinputAction = actionIterator->second;
604     if (!isValidPointerId(pointerId, uinputAction)) {
605         return false;
606     }
607     if (!writeInputEvent(EV_ABS, ABS_MT_SLOT, pointerId, eventTime)) {
608         return false;
609     }
610     auto toolTypeIterator = TOOL_TYPE_MAPPING.find(toolType);
611     if (toolTypeIterator == TOOL_TYPE_MAPPING.end()) {
612         return false;
613     }
614     if (!writeInputEvent(EV_ABS, ABS_MT_TOOL_TYPE, static_cast<int32_t>(toolTypeIterator->second),
615                          eventTime)) {
616         return false;
617     }
618     if (uinputAction == UinputAction::PRESS && !handleTouchDown(pointerId, eventTime)) {
619         return false;
620     }
621     if (uinputAction == UinputAction::RELEASE && !handleTouchUp(pointerId, eventTime)) {
622         return false;
623     }
624     if (!writeInputEvent(EV_ABS, ABS_MT_POSITION_X, locationX, eventTime)) {
625         return false;
626     }
627     if (!writeInputEvent(EV_ABS, ABS_MT_POSITION_Y, locationY, eventTime)) {
628         return false;
629     }
630     if (!isnan(pressure)) {
631         if (!writeInputEvent(EV_ABS, ABS_MT_PRESSURE, pressure, eventTime)) {
632             return false;
633         }
634     }
635     if (!isnan(majorAxisSize)) {
636         if (!writeInputEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, majorAxisSize, eventTime)) {
637             return false;
638         }
639     }
640     return writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
641 }
642 
handleTouchUp(int32_t pointerId,std::chrono::nanoseconds eventTime)643 bool VirtualTouchscreen::handleTouchUp(int32_t pointerId, std::chrono::nanoseconds eventTime) {
644     if (!writeInputEvent(EV_ABS, ABS_MT_TRACKING_ID, static_cast<int32_t>(-1), eventTime)) {
645         return false;
646     }
647     // When a pointer is no longer in touch, remove the pointer id from the corresponding
648     // entry in the unreleased touches map.
649     mActivePointers.reset(pointerId);
650     ALOGD_IF(isDebug(), "Pointer %d erased from the touchscreen %d", pointerId, mFd.get());
651 
652     // Only sends the BTN UP event when there's no pointers on the touchscreen.
653     if (mActivePointers.none()) {
654         if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::RELEASE),
655                              eventTime)) {
656             return false;
657         }
658         ALOGD_IF(isDebug(), "No pointers on touchscreen %d, BTN UP event sent.", mFd.get());
659     }
660     return true;
661 }
662 
handleTouchDown(int32_t pointerId,std::chrono::nanoseconds eventTime)663 bool VirtualTouchscreen::handleTouchDown(int32_t pointerId, std::chrono::nanoseconds eventTime) {
664     // When a new pointer is down on the touchscreen, add the pointer id in the corresponding
665     // entry in the unreleased touches map.
666     if (mActivePointers.none()) {
667         // Only sends the BTN Down event when the first pointer on the touchscreen is down.
668         if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::PRESS),
669                              eventTime)) {
670             return false;
671         }
672         ALOGD_IF(isDebug(), "First pointer %d down under touchscreen %d, BTN DOWN event sent",
673                  pointerId, mFd.get());
674     }
675 
676     mActivePointers.set(pointerId);
677     ALOGD_IF(isDebug(), "Added pointer %d under touchscreen %d in the map", pointerId, mFd.get());
678     if (!writeInputEvent(EV_ABS, ABS_MT_TRACKING_ID, static_cast<int32_t>(pointerId), eventTime)) {
679         return false;
680     }
681     return true;
682 }
683 
684 // --- VirtualStylus ---
685 const std::map<int, int> VirtualStylus::TOOL_TYPE_MAPPING = {
686         {AMOTION_EVENT_TOOL_TYPE_STYLUS, BTN_TOOL_PEN},
687         {AMOTION_EVENT_TOOL_TYPE_ERASER, BTN_TOOL_RUBBER},
688 };
689 
690 // Button code mapping from https://source.android.com/devices/input/touch-devices
691 const std::map<int, int> VirtualStylus::BUTTON_CODE_MAPPING = {
692         {AMOTION_EVENT_BUTTON_STYLUS_PRIMARY, BTN_STYLUS},
693         {AMOTION_EVENT_BUTTON_STYLUS_SECONDARY, BTN_STYLUS2},
694 };
695 
VirtualStylus(unique_fd fd)696 VirtualStylus::VirtualStylus(unique_fd fd)
697       : VirtualInputDevice(std::move(fd)), mIsStylusDown(false) {}
698 
~VirtualStylus()699 VirtualStylus::~VirtualStylus() {}
700 
writeMotionEvent(int32_t toolType,int32_t action,int32_t locationX,int32_t locationY,int32_t pressure,int32_t tiltX,int32_t tiltY,std::chrono::nanoseconds eventTime)701 bool VirtualStylus::writeMotionEvent(int32_t toolType, int32_t action, int32_t locationX,
702                                      int32_t locationY, int32_t pressure, int32_t tiltX,
703                                      int32_t tiltY, std::chrono::nanoseconds eventTime) {
704     auto actionIterator = VirtualTouchscreen::TOUCH_ACTION_MAPPING.find(action);
705     if (actionIterator == VirtualTouchscreen::TOUCH_ACTION_MAPPING.end()) {
706         ALOGE("Unsupported action passed for stylus: %d.", action);
707         return false;
708     }
709     UinputAction uinputAction = actionIterator->second;
710     auto toolTypeIterator = TOOL_TYPE_MAPPING.find(toolType);
711     if (toolTypeIterator == TOOL_TYPE_MAPPING.end()) {
712         ALOGE("Unsupported tool type passed for stylus: %d.", toolType);
713         return false;
714     }
715     uint16_t tool = static_cast<uint16_t>(toolTypeIterator->second);
716     if (uinputAction == UinputAction::PRESS && !handleStylusDown(tool, eventTime)) {
717         return false;
718     }
719     if (!mIsStylusDown) {
720         ALOGE("Action UP or MOVE received with no prior action DOWN for stylus %d.", mFd.get());
721         return false;
722     }
723     if (uinputAction == UinputAction::RELEASE && !handleStylusUp(tool, eventTime)) {
724         return false;
725     }
726     if (!writeInputEvent(EV_ABS, ABS_X, locationX, eventTime)) {
727         ALOGE("Unsupported x-axis location passed for stylus: %d.", locationX);
728         return false;
729     }
730     if (!writeInputEvent(EV_ABS, ABS_Y, locationY, eventTime)) {
731         ALOGE("Unsupported y-axis location passed for stylus: %d.", locationY);
732         return false;
733     }
734     if (!writeInputEvent(EV_ABS, ABS_TILT_X, tiltX, eventTime)) {
735         ALOGE("Unsupported x-axis tilt passed for stylus: %d.", tiltX);
736         return false;
737     }
738     if (!writeInputEvent(EV_ABS, ABS_TILT_Y, tiltY, eventTime)) {
739         ALOGE("Unsupported y-axis tilt passed for stylus: %d.", tiltY);
740         return false;
741     }
742     if (!writeInputEvent(EV_ABS, ABS_PRESSURE, pressure, eventTime)) {
743         ALOGE("Unsupported pressure passed for stylus: %d.", pressure);
744         return false;
745     }
746     if (!writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime)) {
747         ALOGE("Failed to write SYN_REPORT for stylus motion event.");
748         return false;
749     }
750     return true;
751 }
752 
writeButtonEvent(int32_t androidButtonCode,int32_t androidAction,std::chrono::nanoseconds eventTime)753 bool VirtualStylus::writeButtonEvent(int32_t androidButtonCode, int32_t androidAction,
754                                      std::chrono::nanoseconds eventTime) {
755     return writeEvKeyEvent(androidButtonCode, androidAction, BUTTON_CODE_MAPPING,
756                            VirtualMouse::BUTTON_ACTION_MAPPING, eventTime);
757 }
758 
handleStylusDown(uint16_t tool,std::chrono::nanoseconds eventTime)759 bool VirtualStylus::handleStylusDown(uint16_t tool, std::chrono::nanoseconds eventTime) {
760     if (mIsStylusDown) {
761         ALOGE("Repetitive action DOWN event received for a stylus that is already down.");
762         return false;
763     }
764     if (!writeInputEvent(EV_KEY, tool, static_cast<int32_t>(UinputAction::PRESS), eventTime)) {
765         ALOGE("Failed to write EV_KEY for stylus tool type: %u.", tool);
766         return false;
767     }
768     if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::PRESS), eventTime)) {
769         ALOGE("Failed to write BTN_TOUCH for stylus press.");
770         return false;
771     }
772     mIsStylusDown = true;
773     return true;
774 }
775 
handleStylusUp(uint16_t tool,std::chrono::nanoseconds eventTime)776 bool VirtualStylus::handleStylusUp(uint16_t tool, std::chrono::nanoseconds eventTime) {
777     if (!writeInputEvent(EV_KEY, tool, static_cast<int32_t>(UinputAction::RELEASE), eventTime)) {
778         ALOGE("Failed to write EV_KEY for stylus tool type: %u.", tool);
779         return false;
780     }
781     if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::RELEASE),
782                          eventTime)) {
783         ALOGE("Failed to write BTN_TOUCH for stylus release.");
784         return false;
785     }
786     mIsStylusDown = false;
787     return true;
788 }
789 
790 // --- VirtualRotaryEncoder ---
VirtualRotaryEncoder(unique_fd fd)791 VirtualRotaryEncoder::VirtualRotaryEncoder(unique_fd fd)
792       : VirtualInputDevice(std::move(fd)), mAccumulatedHighResScrollAmount(0) {}
793 
~VirtualRotaryEncoder()794 VirtualRotaryEncoder::~VirtualRotaryEncoder() {}
795 
writeScrollEvent(float scrollAmount,std::chrono::nanoseconds eventTime)796 bool VirtualRotaryEncoder::writeScrollEvent(float scrollAmount,
797                                             std::chrono::nanoseconds eventTime) {
798     if (!vd_flags::high_resolution_scroll()) {
799         return writeInputEvent(EV_REL, REL_WHEEL, static_cast<int32_t>(scrollAmount), eventTime) &&
800                 writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
801     }
802 
803     const auto highResScrollAmount =
804             static_cast<int32_t>(scrollAmount * kEvdevHighResScrollUnitsPerDetent);
805     if (!writeInputEvent(EV_REL, REL_WHEEL_HI_RES, highResScrollAmount, eventTime)) {
806         return false;
807     }
808 
809     // According to evdev spec, a high-resolution scroll device needs to emit REL_WHEEL / REL_HWHEEL
810     // events in addition to high-res scroll events. Regular scroll events can approximate high-res
811     // scroll events, so we send a regular scroll event when the accumulated scroll motion reaches a
812     // detent (single wheel click).
813     mAccumulatedHighResScrollAmount += highResScrollAmount;
814     const int32_t scroll = mAccumulatedHighResScrollAmount / kEvdevHighResScrollUnitsPerDetent;
815     if (scroll != 0) {
816         if (!writeInputEvent(EV_REL, REL_WHEEL, scroll, eventTime)) {
817             return false;
818         }
819         mAccumulatedHighResScrollAmount %= kEvdevHighResScrollUnitsPerDetent;
820     }
821 
822     return writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
823 }
824 
825 } // namespace android
826