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