1 /*
2 * Copyright (C) 2021 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 "InputController"
18
19 #include <android-base/unique_fd.h>
20 #include <android/input.h>
21 #include <android/keycodes.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <input/Input.h>
25 #include <input/VirtualInputDevice.h>
26 #include <linux/uinput.h>
27 #include <math.h>
28 #include <nativehelper/JNIHelp.h>
29 #include <nativehelper/ScopedUtfChars.h>
30 #include <utils/Log.h>
31
32 #include <map>
33 #include <set>
34 #include <string>
35
36 using android::base::unique_fd;
37
38 namespace android {
39
40 static constexpr jlong INVALID_PTR = 0;
41
42 enum class DeviceType {
43 KEYBOARD,
44 MOUSE,
45 TOUCHSCREEN,
46 DPAD,
47 STYLUS,
48 };
49
invalidFd()50 static unique_fd invalidFd() {
51 return unique_fd(-1);
52 }
53
54 /** Creates a new uinput device and assigns a file descriptor. */
openUinput(const char * readableName,jint vendorId,jint productId,const char * phys,DeviceType deviceType,jint screenHeight,jint screenWidth)55 static unique_fd openUinput(const char* readableName, jint vendorId, jint productId,
56 const char* phys, DeviceType deviceType, jint screenHeight,
57 jint screenWidth) {
58 unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK)));
59 if (fd < 0) {
60 ALOGE("Error creating uinput device: %s", strerror(errno));
61 return invalidFd();
62 }
63
64 ioctl(fd, UI_SET_PHYS, phys);
65
66 ioctl(fd, UI_SET_EVBIT, EV_KEY);
67 ioctl(fd, UI_SET_EVBIT, EV_SYN);
68 switch (deviceType) {
69 case DeviceType::DPAD:
70 for (const auto& [_, keyCode] : VirtualDpad::DPAD_KEY_CODE_MAPPING) {
71 ioctl(fd, UI_SET_KEYBIT, keyCode);
72 }
73 break;
74 case DeviceType::KEYBOARD:
75 for (const auto& [_, keyCode] : VirtualKeyboard::KEY_CODE_MAPPING) {
76 ioctl(fd, UI_SET_KEYBIT, keyCode);
77 }
78 break;
79 case DeviceType::MOUSE:
80 ioctl(fd, UI_SET_EVBIT, EV_REL);
81 ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
82 ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
83 ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
84 ioctl(fd, UI_SET_KEYBIT, BTN_BACK);
85 ioctl(fd, UI_SET_KEYBIT, BTN_FORWARD);
86 ioctl(fd, UI_SET_RELBIT, REL_X);
87 ioctl(fd, UI_SET_RELBIT, REL_Y);
88 ioctl(fd, UI_SET_RELBIT, REL_WHEEL);
89 ioctl(fd, UI_SET_RELBIT, REL_HWHEEL);
90 break;
91 case DeviceType::TOUCHSCREEN:
92 ioctl(fd, UI_SET_EVBIT, EV_ABS);
93 ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH);
94 ioctl(fd, UI_SET_ABSBIT, ABS_MT_SLOT);
95 ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X);
96 ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y);
97 ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID);
98 ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOOL_TYPE);
99 ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR);
100 ioctl(fd, UI_SET_ABSBIT, ABS_MT_PRESSURE);
101 ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);
102 break;
103 case DeviceType::STYLUS:
104 ioctl(fd, UI_SET_EVBIT, EV_ABS);
105 ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH);
106 ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS);
107 ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS2);
108 ioctl(fd, UI_SET_KEYBIT, BTN_TOOL_PEN);
109 ioctl(fd, UI_SET_KEYBIT, BTN_TOOL_RUBBER);
110 ioctl(fd, UI_SET_ABSBIT, ABS_X);
111 ioctl(fd, UI_SET_ABSBIT, ABS_Y);
112 ioctl(fd, UI_SET_ABSBIT, ABS_TILT_X);
113 ioctl(fd, UI_SET_ABSBIT, ABS_TILT_Y);
114 ioctl(fd, UI_SET_ABSBIT, ABS_PRESSURE);
115 ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);
116 break;
117 default:
118 ALOGE("Invalid input device type %d", static_cast<int32_t>(deviceType));
119 return invalidFd();
120 }
121
122 int version;
123 if (ioctl(fd, UI_GET_VERSION, &version) == 0 && version >= 5) {
124 uinput_setup setup;
125 memset(&setup, 0, sizeof(setup));
126 strlcpy(setup.name, readableName, UINPUT_MAX_NAME_SIZE);
127 setup.id.version = 1;
128 setup.id.bustype = BUS_VIRTUAL;
129 setup.id.vendor = vendorId;
130 setup.id.product = productId;
131 if (deviceType == DeviceType::TOUCHSCREEN) {
132 uinput_abs_setup xAbsSetup;
133 xAbsSetup.code = ABS_MT_POSITION_X;
134 xAbsSetup.absinfo.maximum = screenWidth - 1;
135 xAbsSetup.absinfo.minimum = 0;
136 if (ioctl(fd, UI_ABS_SETUP, &xAbsSetup) != 0) {
137 ALOGE("Error creating touchscreen uinput x axis: %s", strerror(errno));
138 return invalidFd();
139 }
140 uinput_abs_setup yAbsSetup;
141 yAbsSetup.code = ABS_MT_POSITION_Y;
142 yAbsSetup.absinfo.maximum = screenHeight - 1;
143 yAbsSetup.absinfo.minimum = 0;
144 if (ioctl(fd, UI_ABS_SETUP, &yAbsSetup) != 0) {
145 ALOGE("Error creating touchscreen uinput y axis: %s", strerror(errno));
146 return invalidFd();
147 }
148 uinput_abs_setup majorAbsSetup;
149 majorAbsSetup.code = ABS_MT_TOUCH_MAJOR;
150 majorAbsSetup.absinfo.maximum = screenWidth - 1;
151 majorAbsSetup.absinfo.minimum = 0;
152 if (ioctl(fd, UI_ABS_SETUP, &majorAbsSetup) != 0) {
153 ALOGE("Error creating touchscreen uinput major axis: %s", strerror(errno));
154 return invalidFd();
155 }
156 uinput_abs_setup pressureAbsSetup;
157 pressureAbsSetup.code = ABS_MT_PRESSURE;
158 pressureAbsSetup.absinfo.maximum = 255;
159 pressureAbsSetup.absinfo.minimum = 0;
160 if (ioctl(fd, UI_ABS_SETUP, &pressureAbsSetup) != 0) {
161 ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
162 return invalidFd();
163 }
164 uinput_abs_setup slotAbsSetup;
165 slotAbsSetup.code = ABS_MT_SLOT;
166 slotAbsSetup.absinfo.maximum = MAX_POINTERS - 1;
167 slotAbsSetup.absinfo.minimum = 0;
168 if (ioctl(fd, UI_ABS_SETUP, &slotAbsSetup) != 0) {
169 ALOGE("Error creating touchscreen uinput slots: %s", strerror(errno));
170 return invalidFd();
171 }
172 uinput_abs_setup trackingIdAbsSetup;
173 trackingIdAbsSetup.code = ABS_MT_TRACKING_ID;
174 trackingIdAbsSetup.absinfo.maximum = MAX_POINTERS - 1;
175 trackingIdAbsSetup.absinfo.minimum = 0;
176 if (ioctl(fd, UI_ABS_SETUP, &trackingIdAbsSetup) != 0) {
177 ALOGE("Error creating touchscreen uinput tracking ids: %s", strerror(errno));
178 return invalidFd();
179 }
180 } else if (deviceType == DeviceType::STYLUS) {
181 uinput_abs_setup xAbsSetup;
182 xAbsSetup.code = ABS_X;
183 xAbsSetup.absinfo.maximum = screenWidth - 1;
184 xAbsSetup.absinfo.minimum = 0;
185 if (ioctl(fd, UI_ABS_SETUP, &xAbsSetup) != 0) {
186 ALOGE("Error creating stylus uinput x axis: %s", strerror(errno));
187 return invalidFd();
188 }
189 uinput_abs_setup yAbsSetup;
190 yAbsSetup.code = ABS_Y;
191 yAbsSetup.absinfo.maximum = screenHeight - 1;
192 yAbsSetup.absinfo.minimum = 0;
193 if (ioctl(fd, UI_ABS_SETUP, &yAbsSetup) != 0) {
194 ALOGE("Error creating stylus uinput y axis: %s", strerror(errno));
195 return invalidFd();
196 }
197 uinput_abs_setup tiltXAbsSetup;
198 tiltXAbsSetup.code = ABS_TILT_X;
199 tiltXAbsSetup.absinfo.maximum = 90;
200 tiltXAbsSetup.absinfo.minimum = -90;
201 if (ioctl(fd, UI_ABS_SETUP, &tiltXAbsSetup) != 0) {
202 ALOGE("Error creating stylus uinput tilt x axis: %s", strerror(errno));
203 return invalidFd();
204 }
205 uinput_abs_setup tiltYAbsSetup;
206 tiltYAbsSetup.code = ABS_TILT_Y;
207 tiltYAbsSetup.absinfo.maximum = 90;
208 tiltYAbsSetup.absinfo.minimum = -90;
209 if (ioctl(fd, UI_ABS_SETUP, &tiltYAbsSetup) != 0) {
210 ALOGE("Error creating stylus uinput tilt y axis: %s", strerror(errno));
211 return invalidFd();
212 }
213 uinput_abs_setup pressureAbsSetup;
214 pressureAbsSetup.code = ABS_PRESSURE;
215 pressureAbsSetup.absinfo.maximum = 255;
216 pressureAbsSetup.absinfo.minimum = 0;
217 if (ioctl(fd, UI_ABS_SETUP, &pressureAbsSetup) != 0) {
218 ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
219 return invalidFd();
220 }
221 }
222 if (ioctl(fd, UI_DEV_SETUP, &setup) != 0) {
223 ALOGE("Error creating uinput device: %s", strerror(errno));
224 return invalidFd();
225 }
226 } else {
227 // UI_DEV_SETUP was not introduced until version 5. Try setting up manually.
228 ALOGI("Falling back to version %d manual setup", version);
229 uinput_user_dev fallback;
230 memset(&fallback, 0, sizeof(fallback));
231 strlcpy(fallback.name, readableName, UINPUT_MAX_NAME_SIZE);
232 fallback.id.version = 1;
233 fallback.id.bustype = BUS_VIRTUAL;
234 fallback.id.vendor = vendorId;
235 fallback.id.product = productId;
236 if (deviceType == DeviceType::TOUCHSCREEN) {
237 fallback.absmin[ABS_MT_POSITION_X] = 0;
238 fallback.absmax[ABS_MT_POSITION_X] = screenWidth - 1;
239 fallback.absmin[ABS_MT_POSITION_Y] = 0;
240 fallback.absmax[ABS_MT_POSITION_Y] = screenHeight - 1;
241 fallback.absmin[ABS_MT_TOUCH_MAJOR] = 0;
242 fallback.absmax[ABS_MT_TOUCH_MAJOR] = screenWidth - 1;
243 fallback.absmin[ABS_MT_PRESSURE] = 0;
244 fallback.absmax[ABS_MT_PRESSURE] = 255;
245 } else if (deviceType == DeviceType::STYLUS) {
246 fallback.absmin[ABS_X] = 0;
247 fallback.absmax[ABS_X] = screenWidth - 1;
248 fallback.absmin[ABS_Y] = 0;
249 fallback.absmax[ABS_Y] = screenHeight - 1;
250 fallback.absmin[ABS_TILT_X] = -90;
251 fallback.absmax[ABS_TILT_X] = 90;
252 fallback.absmin[ABS_TILT_Y] = -90;
253 fallback.absmax[ABS_TILT_Y] = 90;
254 fallback.absmin[ABS_PRESSURE] = 0;
255 fallback.absmax[ABS_PRESSURE] = 255;
256 }
257 if (TEMP_FAILURE_RETRY(write(fd, &fallback, sizeof(fallback))) != sizeof(fallback)) {
258 ALOGE("Error creating uinput device: %s", strerror(errno));
259 return invalidFd();
260 }
261 }
262
263 if (ioctl(fd, UI_DEV_CREATE) != 0) {
264 ALOGE("Error creating uinput device: %s", strerror(errno));
265 return invalidFd();
266 }
267
268 return fd;
269 }
270
openUinputJni(JNIEnv * env,jstring name,jint vendorId,jint productId,jstring phys,DeviceType deviceType,int screenHeight,int screenWidth)271 static unique_fd openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId,
272 jstring phys, DeviceType deviceType, int screenHeight,
273 int screenWidth) {
274 ScopedUtfChars readableName(env, name);
275 ScopedUtfChars readablePhys(env, phys);
276 return openUinput(readableName.c_str(), vendorId, productId, readablePhys.c_str(), deviceType,
277 screenHeight, screenWidth);
278 }
279
nativeOpenUinputDpad(JNIEnv * env,jobject thiz,jstring name,jint vendorId,jint productId,jstring phys)280 static jlong nativeOpenUinputDpad(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
281 jint productId, jstring phys) {
282 auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::DPAD,
283 /* screenHeight= */ 0, /* screenWidth= */ 0);
284 return fd.ok() ? reinterpret_cast<jlong>(new VirtualDpad(std::move(fd))) : INVALID_PTR;
285 }
286
nativeOpenUinputKeyboard(JNIEnv * env,jobject thiz,jstring name,jint vendorId,jint productId,jstring phys)287 static jlong nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
288 jint productId, jstring phys) {
289 auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD,
290 /* screenHeight= */ 0, /* screenWidth= */ 0);
291 return fd.ok() ? reinterpret_cast<jlong>(new VirtualKeyboard(std::move(fd))) : INVALID_PTR;
292 }
293
nativeOpenUinputMouse(JNIEnv * env,jobject thiz,jstring name,jint vendorId,jint productId,jstring phys)294 static jlong nativeOpenUinputMouse(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
295 jint productId, jstring phys) {
296 auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::MOUSE,
297 /* screenHeight= */ 0, /* screenWidth= */ 0);
298 return fd.ok() ? reinterpret_cast<jlong>(new VirtualMouse(std::move(fd))) : INVALID_PTR;
299 }
300
nativeOpenUinputTouchscreen(JNIEnv * env,jobject thiz,jstring name,jint vendorId,jint productId,jstring phys,jint height,jint width)301 static jlong nativeOpenUinputTouchscreen(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
302 jint productId, jstring phys, jint height, jint width) {
303 auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::TOUCHSCREEN, height,
304 width);
305 return fd.ok() ? reinterpret_cast<jlong>(new VirtualTouchscreen(std::move(fd))) : INVALID_PTR;
306 }
307
nativeOpenUinputStylus(JNIEnv * env,jobject thiz,jstring name,jint vendorId,jint productId,jstring phys,jint height,jint width)308 static jlong nativeOpenUinputStylus(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
309 jint productId, jstring phys, jint height, jint width) {
310 auto fd =
311 openUinputJni(env, name, vendorId, productId, phys, DeviceType::STYLUS, height, width);
312 return fd.ok() ? reinterpret_cast<jlong>(new VirtualStylus(std::move(fd))) : INVALID_PTR;
313 }
314
nativeCloseUinput(JNIEnv * env,jobject thiz,jlong ptr)315 static void nativeCloseUinput(JNIEnv* env, jobject thiz, jlong ptr) {
316 VirtualInputDevice* virtualInputDevice = reinterpret_cast<VirtualInputDevice*>(ptr);
317 delete virtualInputDevice;
318 }
319
320 // Native methods for VirtualDpad
nativeWriteDpadKeyEvent(JNIEnv * env,jobject thiz,jlong ptr,jint androidKeyCode,jint action,jlong eventTimeNanos)321 static bool nativeWriteDpadKeyEvent(JNIEnv* env, jobject thiz, jlong ptr, jint androidKeyCode,
322 jint action, jlong eventTimeNanos) {
323 VirtualDpad* virtualDpad = reinterpret_cast<VirtualDpad*>(ptr);
324 return virtualDpad->writeDpadKeyEvent(androidKeyCode, action,
325 std::chrono::nanoseconds(eventTimeNanos));
326 }
327
328 // Native methods for VirtualKeyboard
nativeWriteKeyEvent(JNIEnv * env,jobject thiz,jlong ptr,jint androidKeyCode,jint action,jlong eventTimeNanos)329 static bool nativeWriteKeyEvent(JNIEnv* env, jobject thiz, jlong ptr, jint androidKeyCode,
330 jint action, jlong eventTimeNanos) {
331 VirtualKeyboard* virtualKeyboard = reinterpret_cast<VirtualKeyboard*>(ptr);
332 return virtualKeyboard->writeKeyEvent(androidKeyCode, action,
333 std::chrono::nanoseconds(eventTimeNanos));
334 }
335
336 // Native methods for VirtualTouchscreen
nativeWriteTouchEvent(JNIEnv * env,jobject thiz,jlong ptr,jint pointerId,jint toolType,jint action,jfloat locationX,jfloat locationY,jfloat pressure,jfloat majorAxisSize,jlong eventTimeNanos)337 static bool nativeWriteTouchEvent(JNIEnv* env, jobject thiz, jlong ptr, jint pointerId,
338 jint toolType, jint action, jfloat locationX, jfloat locationY,
339 jfloat pressure, jfloat majorAxisSize, jlong eventTimeNanos) {
340 VirtualTouchscreen* virtualTouchscreen = reinterpret_cast<VirtualTouchscreen*>(ptr);
341 return virtualTouchscreen->writeTouchEvent(pointerId, toolType, action, locationX, locationY,
342 pressure, majorAxisSize,
343 std::chrono::nanoseconds(eventTimeNanos));
344 }
345
346 // Native methods for VirtualMouse
nativeWriteButtonEvent(JNIEnv * env,jobject thiz,jlong ptr,jint buttonCode,jint action,jlong eventTimeNanos)347 static bool nativeWriteButtonEvent(JNIEnv* env, jobject thiz, jlong ptr, jint buttonCode,
348 jint action, jlong eventTimeNanos) {
349 VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
350 return virtualMouse->writeButtonEvent(buttonCode, action,
351 std::chrono::nanoseconds(eventTimeNanos));
352 }
353
nativeWriteRelativeEvent(JNIEnv * env,jobject thiz,jlong ptr,jfloat relativeX,jfloat relativeY,jlong eventTimeNanos)354 static bool nativeWriteRelativeEvent(JNIEnv* env, jobject thiz, jlong ptr, jfloat relativeX,
355 jfloat relativeY, jlong eventTimeNanos) {
356 VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
357 return virtualMouse->writeRelativeEvent(relativeX, relativeY,
358 std::chrono::nanoseconds(eventTimeNanos));
359 }
360
nativeWriteScrollEvent(JNIEnv * env,jobject thiz,jlong ptr,jfloat xAxisMovement,jfloat yAxisMovement,jlong eventTimeNanos)361 static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jlong ptr, jfloat xAxisMovement,
362 jfloat yAxisMovement, jlong eventTimeNanos) {
363 VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
364 return virtualMouse->writeScrollEvent(xAxisMovement, yAxisMovement,
365 std::chrono::nanoseconds(eventTimeNanos));
366 }
367
368 // Native methods for VirtualStylus
nativeWriteStylusMotionEvent(JNIEnv * env,jobject thiz,jlong ptr,jint toolType,jint action,jint locationX,jint locationY,jint pressure,jint tiltX,jint tiltY,jlong eventTimeNanos)369 static bool nativeWriteStylusMotionEvent(JNIEnv* env, jobject thiz, jlong ptr, jint toolType,
370 jint action, jint locationX, jint locationY, jint pressure,
371 jint tiltX, jint tiltY, jlong eventTimeNanos) {
372 VirtualStylus* virtualStylus = reinterpret_cast<VirtualStylus*>(ptr);
373 return virtualStylus->writeMotionEvent(toolType, action, locationX, locationY, pressure, tiltX,
374 tiltY, std::chrono::nanoseconds(eventTimeNanos));
375 }
376
nativeWriteStylusButtonEvent(JNIEnv * env,jobject thiz,jlong ptr,jint buttonCode,jint action,jlong eventTimeNanos)377 static bool nativeWriteStylusButtonEvent(JNIEnv* env, jobject thiz, jlong ptr, jint buttonCode,
378 jint action, jlong eventTimeNanos) {
379 VirtualStylus* virtualStylus = reinterpret_cast<VirtualStylus*>(ptr);
380 return virtualStylus->writeButtonEvent(buttonCode, action,
381 std::chrono::nanoseconds(eventTimeNanos));
382 }
383
384 static JNINativeMethod methods[] = {
385 {"nativeOpenUinputDpad", "(Ljava/lang/String;IILjava/lang/String;)J",
386 (void*)nativeOpenUinputDpad},
387 {"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)J",
388 (void*)nativeOpenUinputKeyboard},
389 {"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)J",
390 (void*)nativeOpenUinputMouse},
391 {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)J",
392 (void*)nativeOpenUinputTouchscreen},
393 {"nativeOpenUinputStylus", "(Ljava/lang/String;IILjava/lang/String;II)J",
394 (void*)nativeOpenUinputStylus},
395 {"nativeCloseUinput", "(J)V", (void*)nativeCloseUinput},
396 {"nativeWriteDpadKeyEvent", "(JIIJ)Z", (void*)nativeWriteDpadKeyEvent},
397 {"nativeWriteKeyEvent", "(JIIJ)Z", (void*)nativeWriteKeyEvent},
398 {"nativeWriteButtonEvent", "(JIIJ)Z", (void*)nativeWriteButtonEvent},
399 {"nativeWriteTouchEvent", "(JIIIFFFFJ)Z", (void*)nativeWriteTouchEvent},
400 {"nativeWriteRelativeEvent", "(JFFJ)Z", (void*)nativeWriteRelativeEvent},
401 {"nativeWriteScrollEvent", "(JFFJ)Z", (void*)nativeWriteScrollEvent},
402 {"nativeWriteStylusMotionEvent", "(JIIIIIIIJ)Z", (void*)nativeWriteStylusMotionEvent},
403 {"nativeWriteStylusButtonEvent", "(JIIJ)Z", (void*)nativeWriteStylusButtonEvent},
404 };
405
register_android_server_companion_virtual_InputController(JNIEnv * env)406 int register_android_server_companion_virtual_InputController(JNIEnv* env) {
407 return jniRegisterNativeMethods(env, "com/android/server/companion/virtual/InputController",
408 methods, NELEM(methods));
409 }
410
411 } // namespace android
412