Merge "Move device specific logic to VirtualInputDevice and its subclasses." into udc-dev
This commit is contained in:
@@ -242,7 +242,7 @@ class InputController {
|
||||
private void closeInputDeviceDescriptorLocked(IBinder token,
|
||||
InputDeviceDescriptor inputDeviceDescriptor) {
|
||||
token.unlinkToDeath(inputDeviceDescriptor.getDeathRecipient(), /* flags= */ 0);
|
||||
mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor());
|
||||
mNativeWrapper.closeUinput(inputDeviceDescriptor.getNativePointer());
|
||||
String phys = inputDeviceDescriptor.getPhys();
|
||||
InputManager.getInstance().removeUniqueIdAssociation(phys);
|
||||
// Type associations are added in the case of navigation touchpads. Those should be removed
|
||||
@@ -366,7 +366,7 @@ class InputController {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not send key event to input device for given token");
|
||||
}
|
||||
return mNativeWrapper.writeDpadKeyEvent(inputDeviceDescriptor.getFileDescriptor(),
|
||||
return mNativeWrapper.writeDpadKeyEvent(inputDeviceDescriptor.getNativePointer(),
|
||||
event.getKeyCode(), event.getAction());
|
||||
}
|
||||
}
|
||||
@@ -379,7 +379,7 @@ class InputController {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not send key event to input device for given token");
|
||||
}
|
||||
return mNativeWrapper.writeKeyEvent(inputDeviceDescriptor.getFileDescriptor(),
|
||||
return mNativeWrapper.writeKeyEvent(inputDeviceDescriptor.getNativePointer(),
|
||||
event.getKeyCode(), event.getAction());
|
||||
}
|
||||
}
|
||||
@@ -397,7 +397,7 @@ class InputController {
|
||||
throw new IllegalStateException(
|
||||
"Display id associated with this mouse is not currently targetable");
|
||||
}
|
||||
return mNativeWrapper.writeButtonEvent(inputDeviceDescriptor.getFileDescriptor(),
|
||||
return mNativeWrapper.writeButtonEvent(inputDeviceDescriptor.getNativePointer(),
|
||||
event.getButtonCode(), event.getAction());
|
||||
}
|
||||
}
|
||||
@@ -410,7 +410,7 @@ class InputController {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not send touch event to input device for given token");
|
||||
}
|
||||
return mNativeWrapper.writeTouchEvent(inputDeviceDescriptor.getFileDescriptor(),
|
||||
return mNativeWrapper.writeTouchEvent(inputDeviceDescriptor.getNativePointer(),
|
||||
event.getPointerId(), event.getToolType(), event.getAction(), event.getX(),
|
||||
event.getY(), event.getPressure(), event.getMajorAxisSize());
|
||||
}
|
||||
@@ -429,7 +429,7 @@ class InputController {
|
||||
throw new IllegalStateException(
|
||||
"Display id associated with this mouse is not currently targetable");
|
||||
}
|
||||
return mNativeWrapper.writeRelativeEvent(inputDeviceDescriptor.getFileDescriptor(),
|
||||
return mNativeWrapper.writeRelativeEvent(inputDeviceDescriptor.getNativePointer(),
|
||||
event.getRelativeX(), event.getRelativeY());
|
||||
}
|
||||
}
|
||||
@@ -447,7 +447,7 @@ class InputController {
|
||||
throw new IllegalStateException(
|
||||
"Display id associated with this mouse is not currently targetable");
|
||||
}
|
||||
return mNativeWrapper.writeScrollEvent(inputDeviceDescriptor.getFileDescriptor(),
|
||||
return mNativeWrapper.writeScrollEvent(inputDeviceDescriptor.getNativePointer(),
|
||||
event.getXAxisMovement(), event.getYAxisMovement());
|
||||
}
|
||||
}
|
||||
@@ -474,7 +474,7 @@ class InputController {
|
||||
synchronized (mLock) {
|
||||
fout.println(" Active descriptors: ");
|
||||
for (InputDeviceDescriptor inputDeviceDescriptor : mInputDeviceDescriptors.values()) {
|
||||
fout.println(" fd: " + inputDeviceDescriptor.getFileDescriptor());
|
||||
fout.println(" ptr: " + inputDeviceDescriptor.getNativePointer());
|
||||
fout.println(" displayId: " + inputDeviceDescriptor.getDisplayId());
|
||||
fout.println(" creationOrder: "
|
||||
+ inputDeviceDescriptor.getCreationOrderNumber());
|
||||
@@ -487,10 +487,10 @@ class InputController {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void addDeviceForTesting(IBinder deviceToken, int fd, int type, int displayId, String phys,
|
||||
void addDeviceForTesting(IBinder deviceToken, long ptr, int type, int displayId, String phys,
|
||||
String deviceName, int inputDeviceId) {
|
||||
synchronized (mLock) {
|
||||
mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, () -> {
|
||||
mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(ptr, () -> {
|
||||
}, type, displayId, phys, deviceName, inputDeviceId));
|
||||
}
|
||||
}
|
||||
@@ -504,75 +504,76 @@ class InputController {
|
||||
return inputDeviceDescriptors;
|
||||
}
|
||||
|
||||
private static native int nativeOpenUinputDpad(String deviceName, int vendorId, int productId,
|
||||
private static native long nativeOpenUinputDpad(String deviceName, int vendorId, int productId,
|
||||
String phys);
|
||||
private static native int nativeOpenUinputKeyboard(String deviceName, int vendorId,
|
||||
private static native long nativeOpenUinputKeyboard(String deviceName, int vendorId,
|
||||
int productId, String phys);
|
||||
private static native int nativeOpenUinputMouse(String deviceName, int vendorId, int productId,
|
||||
private static native long nativeOpenUinputMouse(String deviceName, int vendorId, int productId,
|
||||
String phys);
|
||||
private static native int nativeOpenUinputTouchscreen(String deviceName, int vendorId,
|
||||
private static native long nativeOpenUinputTouchscreen(String deviceName, int vendorId,
|
||||
int productId, String phys, int height, int width);
|
||||
private static native boolean nativeCloseUinput(int fd);
|
||||
private static native boolean nativeWriteDpadKeyEvent(int fd, int androidKeyCode, int action);
|
||||
private static native boolean nativeWriteKeyEvent(int fd, int androidKeyCode, int action);
|
||||
private static native boolean nativeWriteButtonEvent(int fd, int buttonCode, int action);
|
||||
private static native boolean nativeWriteTouchEvent(int fd, int pointerId, int toolType,
|
||||
private static native void nativeCloseUinput(long ptr);
|
||||
private static native boolean nativeWriteDpadKeyEvent(long ptr, int androidKeyCode, int action);
|
||||
private static native boolean nativeWriteKeyEvent(long ptr, int androidKeyCode, int action);
|
||||
private static native boolean nativeWriteButtonEvent(long ptr, int buttonCode, int action);
|
||||
private static native boolean nativeWriteTouchEvent(long ptr, int pointerId, int toolType,
|
||||
int action, float locationX, float locationY, float pressure, float majorAxisSize);
|
||||
private static native boolean nativeWriteRelativeEvent(int fd, float relativeX,
|
||||
private static native boolean nativeWriteRelativeEvent(long ptr, float relativeX,
|
||||
float relativeY);
|
||||
private static native boolean nativeWriteScrollEvent(int fd, float xAxisMovement,
|
||||
private static native boolean nativeWriteScrollEvent(long ptr, float xAxisMovement,
|
||||
float yAxisMovement);
|
||||
|
||||
/** Wrapper around the static native methods for tests. */
|
||||
@VisibleForTesting
|
||||
protected static class NativeWrapper {
|
||||
public int openUinputDpad(String deviceName, int vendorId, int productId, String phys) {
|
||||
public long openUinputDpad(String deviceName, int vendorId, int productId, String phys) {
|
||||
return nativeOpenUinputDpad(deviceName, vendorId, productId, phys);
|
||||
}
|
||||
|
||||
public int openUinputKeyboard(String deviceName, int vendorId, int productId, String phys) {
|
||||
public long openUinputKeyboard(String deviceName, int vendorId, int productId,
|
||||
String phys) {
|
||||
return nativeOpenUinputKeyboard(deviceName, vendorId, productId, phys);
|
||||
}
|
||||
|
||||
public int openUinputMouse(String deviceName, int vendorId, int productId, String phys) {
|
||||
public long openUinputMouse(String deviceName, int vendorId, int productId, String phys) {
|
||||
return nativeOpenUinputMouse(deviceName, vendorId, productId, phys);
|
||||
}
|
||||
|
||||
public int openUinputTouchscreen(String deviceName, int vendorId,
|
||||
public long openUinputTouchscreen(String deviceName, int vendorId,
|
||||
int productId, String phys, int height, int width) {
|
||||
return nativeOpenUinputTouchscreen(deviceName, vendorId, productId, phys, height,
|
||||
width);
|
||||
}
|
||||
|
||||
public boolean closeUinput(int fd) {
|
||||
return nativeCloseUinput(fd);
|
||||
public void closeUinput(long ptr) {
|
||||
nativeCloseUinput(ptr);
|
||||
}
|
||||
|
||||
public boolean writeDpadKeyEvent(int fd, int androidKeyCode, int action) {
|
||||
return nativeWriteDpadKeyEvent(fd, androidKeyCode, action);
|
||||
public boolean writeDpadKeyEvent(long ptr, int androidKeyCode, int action) {
|
||||
return nativeWriteDpadKeyEvent(ptr, androidKeyCode, action);
|
||||
}
|
||||
|
||||
public boolean writeKeyEvent(int fd, int androidKeyCode, int action) {
|
||||
return nativeWriteKeyEvent(fd, androidKeyCode, action);
|
||||
public boolean writeKeyEvent(long ptr, int androidKeyCode, int action) {
|
||||
return nativeWriteKeyEvent(ptr, androidKeyCode, action);
|
||||
}
|
||||
|
||||
public boolean writeButtonEvent(int fd, int buttonCode, int action) {
|
||||
return nativeWriteButtonEvent(fd, buttonCode, action);
|
||||
public boolean writeButtonEvent(long ptr, int buttonCode, int action) {
|
||||
return nativeWriteButtonEvent(ptr, buttonCode, action);
|
||||
}
|
||||
|
||||
public boolean writeTouchEvent(int fd, int pointerId, int toolType, int action,
|
||||
public boolean writeTouchEvent(long ptr, int pointerId, int toolType, int action,
|
||||
float locationX, float locationY, float pressure, float majorAxisSize) {
|
||||
return nativeWriteTouchEvent(fd, pointerId, toolType,
|
||||
return nativeWriteTouchEvent(ptr, pointerId, toolType,
|
||||
action, locationX, locationY,
|
||||
pressure, majorAxisSize);
|
||||
}
|
||||
|
||||
public boolean writeRelativeEvent(int fd, float relativeX, float relativeY) {
|
||||
return nativeWriteRelativeEvent(fd, relativeX, relativeY);
|
||||
public boolean writeRelativeEvent(long ptr, float relativeX, float relativeY) {
|
||||
return nativeWriteRelativeEvent(ptr, relativeX, relativeY);
|
||||
}
|
||||
|
||||
public boolean writeScrollEvent(int fd, float xAxisMovement, float yAxisMovement) {
|
||||
return nativeWriteScrollEvent(fd, xAxisMovement,
|
||||
public boolean writeScrollEvent(long ptr, float xAxisMovement, float yAxisMovement) {
|
||||
return nativeWriteScrollEvent(ptr, xAxisMovement,
|
||||
yAxisMovement);
|
||||
}
|
||||
}
|
||||
@@ -597,7 +598,8 @@ class InputController {
|
||||
|
||||
private static final AtomicLong sNextCreationOrderNumber = new AtomicLong(1);
|
||||
|
||||
private final int mFd;
|
||||
// Pointer to the native input device object.
|
||||
private final long mPtr;
|
||||
private final IBinder.DeathRecipient mDeathRecipient;
|
||||
private final @Type int mType;
|
||||
private final int mDisplayId;
|
||||
@@ -611,9 +613,9 @@ class InputController {
|
||||
// Monotonically increasing number; devices with lower numbers were created earlier.
|
||||
private final long mCreationOrderNumber;
|
||||
|
||||
InputDeviceDescriptor(int fd, IBinder.DeathRecipient deathRecipient, @Type int type,
|
||||
InputDeviceDescriptor(long ptr, IBinder.DeathRecipient deathRecipient, @Type int type,
|
||||
int displayId, String phys, String name, int inputDeviceId) {
|
||||
mFd = fd;
|
||||
mPtr = ptr;
|
||||
mDeathRecipient = deathRecipient;
|
||||
mType = type;
|
||||
mDisplayId = displayId;
|
||||
@@ -623,8 +625,8 @@ class InputController {
|
||||
mCreationOrderNumber = sNextCreationOrderNumber.getAndIncrement();
|
||||
}
|
||||
|
||||
public int getFileDescriptor() {
|
||||
return mFd;
|
||||
public long getNativePointer() {
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
@@ -767,7 +769,7 @@ class InputController {
|
||||
*/
|
||||
private void createDeviceInternal(@InputDeviceDescriptor.Type int type, String deviceName,
|
||||
int vendorId, int productId, IBinder deviceToken, int displayId, String phys,
|
||||
Supplier<Integer> deviceOpener)
|
||||
Supplier<Long> deviceOpener)
|
||||
throws DeviceCreationException {
|
||||
if (!mThreadVerifier.isValidThread()) {
|
||||
throw new IllegalStateException(
|
||||
@@ -776,19 +778,22 @@ class InputController {
|
||||
}
|
||||
validateDeviceName(deviceName);
|
||||
|
||||
final int fd;
|
||||
final long ptr;
|
||||
final BinderDeathRecipient binderDeathRecipient;
|
||||
|
||||
final int inputDeviceId;
|
||||
|
||||
setUniqueIdAssociation(displayId, phys);
|
||||
try (WaitForDevice waiter = new WaitForDevice(deviceName, vendorId, productId)) {
|
||||
fd = deviceOpener.get();
|
||||
if (fd < 0) {
|
||||
ptr = deviceOpener.get();
|
||||
// See INVALID_PTR in libs/input/VirtualInputDevice.cpp.
|
||||
if (ptr == 0) {
|
||||
throw new DeviceCreationException(
|
||||
"A native error occurred when creating touchscreen: " + -fd);
|
||||
"A native error occurred when creating virtual input device: "
|
||||
+ deviceName);
|
||||
}
|
||||
// The fd is valid from here, so ensure that all failures close the fd after this point.
|
||||
// The pointer to the native input device is valid from here, so ensure that all
|
||||
// failures close the device after this point.
|
||||
try {
|
||||
inputDeviceId = waiter.waitForDeviceCreation();
|
||||
|
||||
@@ -800,7 +805,7 @@ class InputController {
|
||||
"Client died before virtual device could be created.", e);
|
||||
}
|
||||
} catch (DeviceCreationException e) {
|
||||
mNativeWrapper.closeUinput(fd);
|
||||
mNativeWrapper.closeUinput(ptr);
|
||||
throw e;
|
||||
}
|
||||
} catch (DeviceCreationException e) {
|
||||
@@ -810,7 +815,7 @@ class InputController {
|
||||
|
||||
synchronized (mLock) {
|
||||
mInputDeviceDescriptors.put(deviceToken,
|
||||
new InputDeviceDescriptor(fd, binderDeathRecipient, type, displayId, phys,
|
||||
new InputDeviceDescriptor(ptr, binderDeathRecipient, type, displayId, phys,
|
||||
deviceName, inputDeviceId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <input/Input.h>
|
||||
#include <input/VirtualInputDevice.h>
|
||||
#include <linux/uinput.h>
|
||||
#include <math.h>
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
@@ -32,16 +33,12 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* Log debug messages about native virtual input devices.
|
||||
* Enable this via "adb shell setprop log.tag.InputController DEBUG"
|
||||
*/
|
||||
static bool isDebug() {
|
||||
return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
|
||||
}
|
||||
using android::base::unique_fd;
|
||||
|
||||
namespace android {
|
||||
|
||||
static constexpr jlong INVALID_PTR = 0;
|
||||
|
||||
enum class DeviceType {
|
||||
KEYBOARD,
|
||||
MOUSE,
|
||||
@@ -49,176 +46,18 @@ enum class DeviceType {
|
||||
DPAD,
|
||||
};
|
||||
|
||||
enum class UinputAction {
|
||||
RELEASE = 0,
|
||||
PRESS = 1,
|
||||
MOVE = 2,
|
||||
CANCEL = 3,
|
||||
};
|
||||
|
||||
static std::map<int, UinputAction> BUTTON_ACTION_MAPPING = {
|
||||
{AMOTION_EVENT_ACTION_BUTTON_PRESS, UinputAction::PRESS},
|
||||
{AMOTION_EVENT_ACTION_BUTTON_RELEASE, UinputAction::RELEASE},
|
||||
};
|
||||
|
||||
static std::map<int, UinputAction> KEY_ACTION_MAPPING = {
|
||||
{AKEY_EVENT_ACTION_DOWN, UinputAction::PRESS},
|
||||
{AKEY_EVENT_ACTION_UP, UinputAction::RELEASE},
|
||||
};
|
||||
|
||||
static std::map<int, UinputAction> TOUCH_ACTION_MAPPING = {
|
||||
{AMOTION_EVENT_ACTION_DOWN, UinputAction::PRESS},
|
||||
{AMOTION_EVENT_ACTION_UP, UinputAction::RELEASE},
|
||||
{AMOTION_EVENT_ACTION_MOVE, UinputAction::MOVE},
|
||||
{AMOTION_EVENT_ACTION_CANCEL, UinputAction::CANCEL},
|
||||
};
|
||||
|
||||
// Button code mapping from https://source.android.com/devices/input/touch-devices
|
||||
static std::map<int, int> BUTTON_CODE_MAPPING = {
|
||||
{AMOTION_EVENT_BUTTON_PRIMARY, BTN_LEFT}, {AMOTION_EVENT_BUTTON_SECONDARY, BTN_RIGHT},
|
||||
{AMOTION_EVENT_BUTTON_TERTIARY, BTN_MIDDLE}, {AMOTION_EVENT_BUTTON_BACK, BTN_BACK},
|
||||
{AMOTION_EVENT_BUTTON_FORWARD, BTN_FORWARD},
|
||||
};
|
||||
|
||||
// Tool type mapping from https://source.android.com/devices/input/touch-devices
|
||||
static std::map<int, int> TOOL_TYPE_MAPPING = {
|
||||
{AMOTION_EVENT_TOOL_TYPE_FINGER, MT_TOOL_FINGER},
|
||||
{AMOTION_EVENT_TOOL_TYPE_PALM, MT_TOOL_PALM},
|
||||
};
|
||||
|
||||
// Dpad keycode mapping from https://source.android.com/devices/input/keyboard-devices
|
||||
static std::map<int, int> DPAD_KEY_CODE_MAPPING = {
|
||||
{AKEYCODE_DPAD_DOWN, KEY_DOWN}, {AKEYCODE_DPAD_UP, KEY_UP},
|
||||
{AKEYCODE_DPAD_LEFT, KEY_LEFT}, {AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
|
||||
{AKEYCODE_DPAD_CENTER, KEY_SELECT}, {AKEYCODE_BACK, KEY_BACK},
|
||||
};
|
||||
|
||||
// Keycode mapping from https://source.android.com/devices/input/keyboard-devices
|
||||
static std::map<int, int> KEY_CODE_MAPPING = {
|
||||
{AKEYCODE_0, KEY_0},
|
||||
{AKEYCODE_1, KEY_1},
|
||||
{AKEYCODE_2, KEY_2},
|
||||
{AKEYCODE_3, KEY_3},
|
||||
{AKEYCODE_4, KEY_4},
|
||||
{AKEYCODE_5, KEY_5},
|
||||
{AKEYCODE_6, KEY_6},
|
||||
{AKEYCODE_7, KEY_7},
|
||||
{AKEYCODE_8, KEY_8},
|
||||
{AKEYCODE_9, KEY_9},
|
||||
{AKEYCODE_A, KEY_A},
|
||||
{AKEYCODE_B, KEY_B},
|
||||
{AKEYCODE_C, KEY_C},
|
||||
{AKEYCODE_D, KEY_D},
|
||||
{AKEYCODE_E, KEY_E},
|
||||
{AKEYCODE_F, KEY_F},
|
||||
{AKEYCODE_G, KEY_G},
|
||||
{AKEYCODE_H, KEY_H},
|
||||
{AKEYCODE_I, KEY_I},
|
||||
{AKEYCODE_J, KEY_J},
|
||||
{AKEYCODE_K, KEY_K},
|
||||
{AKEYCODE_L, KEY_L},
|
||||
{AKEYCODE_M, KEY_M},
|
||||
{AKEYCODE_N, KEY_N},
|
||||
{AKEYCODE_O, KEY_O},
|
||||
{AKEYCODE_P, KEY_P},
|
||||
{AKEYCODE_Q, KEY_Q},
|
||||
{AKEYCODE_R, KEY_R},
|
||||
{AKEYCODE_S, KEY_S},
|
||||
{AKEYCODE_T, KEY_T},
|
||||
{AKEYCODE_U, KEY_U},
|
||||
{AKEYCODE_V, KEY_V},
|
||||
{AKEYCODE_W, KEY_W},
|
||||
{AKEYCODE_X, KEY_X},
|
||||
{AKEYCODE_Y, KEY_Y},
|
||||
{AKEYCODE_Z, KEY_Z},
|
||||
{AKEYCODE_GRAVE, KEY_GRAVE},
|
||||
{AKEYCODE_MINUS, KEY_MINUS},
|
||||
{AKEYCODE_EQUALS, KEY_EQUAL},
|
||||
{AKEYCODE_LEFT_BRACKET, KEY_LEFTBRACE},
|
||||
{AKEYCODE_RIGHT_BRACKET, KEY_RIGHTBRACE},
|
||||
{AKEYCODE_BACKSLASH, KEY_BACKSLASH},
|
||||
{AKEYCODE_SEMICOLON, KEY_SEMICOLON},
|
||||
{AKEYCODE_APOSTROPHE, KEY_APOSTROPHE},
|
||||
{AKEYCODE_COMMA, KEY_COMMA},
|
||||
{AKEYCODE_PERIOD, KEY_DOT},
|
||||
{AKEYCODE_SLASH, KEY_SLASH},
|
||||
{AKEYCODE_ALT_LEFT, KEY_LEFTALT},
|
||||
{AKEYCODE_ALT_RIGHT, KEY_RIGHTALT},
|
||||
{AKEYCODE_CTRL_LEFT, KEY_LEFTCTRL},
|
||||
{AKEYCODE_CTRL_RIGHT, KEY_RIGHTCTRL},
|
||||
{AKEYCODE_SHIFT_LEFT, KEY_LEFTSHIFT},
|
||||
{AKEYCODE_SHIFT_RIGHT, KEY_RIGHTSHIFT},
|
||||
{AKEYCODE_META_LEFT, KEY_LEFTMETA},
|
||||
{AKEYCODE_META_RIGHT, KEY_RIGHTMETA},
|
||||
{AKEYCODE_CAPS_LOCK, KEY_CAPSLOCK},
|
||||
{AKEYCODE_SCROLL_LOCK, KEY_SCROLLLOCK},
|
||||
{AKEYCODE_NUM_LOCK, KEY_NUMLOCK},
|
||||
{AKEYCODE_ENTER, KEY_ENTER},
|
||||
{AKEYCODE_TAB, KEY_TAB},
|
||||
{AKEYCODE_SPACE, KEY_SPACE},
|
||||
{AKEYCODE_DPAD_DOWN, KEY_DOWN},
|
||||
{AKEYCODE_DPAD_UP, KEY_UP},
|
||||
{AKEYCODE_DPAD_LEFT, KEY_LEFT},
|
||||
{AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
|
||||
{AKEYCODE_MOVE_END, KEY_END},
|
||||
{AKEYCODE_MOVE_HOME, KEY_HOME},
|
||||
{AKEYCODE_PAGE_DOWN, KEY_PAGEDOWN},
|
||||
{AKEYCODE_PAGE_UP, KEY_PAGEUP},
|
||||
{AKEYCODE_DEL, KEY_BACKSPACE},
|
||||
{AKEYCODE_FORWARD_DEL, KEY_DELETE},
|
||||
{AKEYCODE_INSERT, KEY_INSERT},
|
||||
{AKEYCODE_ESCAPE, KEY_ESC},
|
||||
{AKEYCODE_BREAK, KEY_PAUSE},
|
||||
{AKEYCODE_F1, KEY_F1},
|
||||
{AKEYCODE_F2, KEY_F2},
|
||||
{AKEYCODE_F3, KEY_F3},
|
||||
{AKEYCODE_F4, KEY_F4},
|
||||
{AKEYCODE_F5, KEY_F5},
|
||||
{AKEYCODE_F6, KEY_F6},
|
||||
{AKEYCODE_F7, KEY_F7},
|
||||
{AKEYCODE_F8, KEY_F8},
|
||||
{AKEYCODE_F9, KEY_F9},
|
||||
{AKEYCODE_F10, KEY_F10},
|
||||
{AKEYCODE_F11, KEY_F11},
|
||||
{AKEYCODE_F12, KEY_F12},
|
||||
{AKEYCODE_BACK, KEY_BACK},
|
||||
{AKEYCODE_FORWARD, KEY_FORWARD},
|
||||
{AKEYCODE_NUMPAD_1, KEY_KP1},
|
||||
{AKEYCODE_NUMPAD_2, KEY_KP2},
|
||||
{AKEYCODE_NUMPAD_3, KEY_KP3},
|
||||
{AKEYCODE_NUMPAD_4, KEY_KP4},
|
||||
{AKEYCODE_NUMPAD_5, KEY_KP5},
|
||||
{AKEYCODE_NUMPAD_6, KEY_KP6},
|
||||
{AKEYCODE_NUMPAD_7, KEY_KP7},
|
||||
{AKEYCODE_NUMPAD_8, KEY_KP8},
|
||||
{AKEYCODE_NUMPAD_9, KEY_KP9},
|
||||
{AKEYCODE_NUMPAD_0, KEY_KP0},
|
||||
{AKEYCODE_NUMPAD_ADD, KEY_KPPLUS},
|
||||
{AKEYCODE_NUMPAD_SUBTRACT, KEY_KPMINUS},
|
||||
{AKEYCODE_NUMPAD_MULTIPLY, KEY_KPASTERISK},
|
||||
{AKEYCODE_NUMPAD_DIVIDE, KEY_KPSLASH},
|
||||
{AKEYCODE_NUMPAD_DOT, KEY_KPDOT},
|
||||
{AKEYCODE_NUMPAD_ENTER, KEY_KPENTER},
|
||||
{AKEYCODE_NUMPAD_EQUALS, KEY_KPEQUAL},
|
||||
{AKEYCODE_NUMPAD_COMMA, KEY_KPCOMMA},
|
||||
};
|
||||
|
||||
/*
|
||||
* Map from the uinput touchscreen fd to the pointers present in the previous touch events that
|
||||
* hasn't been lifted.
|
||||
* We only allow pointer id to go up to MAX_POINTERS because the maximum slots of virtual
|
||||
* touchscreen is set up with MAX_POINTERS. Note that in other cases Android allows pointer id to go
|
||||
* up to MAX_POINTERS_ID.
|
||||
*/
|
||||
static std::map<int32_t, std::bitset<MAX_POINTERS>> unreleasedTouches;
|
||||
static unique_fd invalidFd() {
|
||||
return unique_fd(-1);
|
||||
}
|
||||
|
||||
/** Creates a new uinput device and assigns a file descriptor. */
|
||||
static int openUinput(const char* readableName, jint vendorId, jint productId, const char* phys,
|
||||
DeviceType deviceType, jint screenHeight, jint screenWidth) {
|
||||
android::base::unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK)));
|
||||
static unique_fd openUinput(const char* readableName, jint vendorId, jint productId,
|
||||
const char* phys, DeviceType deviceType, jint screenHeight,
|
||||
jint screenWidth) {
|
||||
unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK)));
|
||||
if (fd < 0) {
|
||||
ALOGE("Error creating uinput device: %s", strerror(errno));
|
||||
return -errno;
|
||||
return invalidFd();
|
||||
}
|
||||
|
||||
ioctl(fd, UI_SET_PHYS, phys);
|
||||
@@ -227,12 +66,12 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, c
|
||||
ioctl(fd, UI_SET_EVBIT, EV_SYN);
|
||||
switch (deviceType) {
|
||||
case DeviceType::DPAD:
|
||||
for (const auto& [_, keyCode] : DPAD_KEY_CODE_MAPPING) {
|
||||
for (const auto& [_, keyCode] : VirtualDpad::DPAD_KEY_CODE_MAPPING) {
|
||||
ioctl(fd, UI_SET_KEYBIT, keyCode);
|
||||
}
|
||||
break;
|
||||
case DeviceType::KEYBOARD:
|
||||
for (const auto& [_, keyCode] : KEY_CODE_MAPPING) {
|
||||
for (const auto& [_, keyCode] : VirtualKeyboard::KEY_CODE_MAPPING) {
|
||||
ioctl(fd, UI_SET_KEYBIT, keyCode);
|
||||
}
|
||||
break;
|
||||
@@ -277,7 +116,7 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, c
|
||||
xAbsSetup.absinfo.minimum = 0;
|
||||
if (ioctl(fd, UI_ABS_SETUP, &xAbsSetup) != 0) {
|
||||
ALOGE("Error creating touchscreen uinput x axis: %s", strerror(errno));
|
||||
return -errno;
|
||||
return invalidFd();
|
||||
}
|
||||
uinput_abs_setup yAbsSetup;
|
||||
yAbsSetup.code = ABS_MT_POSITION_Y;
|
||||
@@ -285,7 +124,7 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, c
|
||||
yAbsSetup.absinfo.minimum = 0;
|
||||
if (ioctl(fd, UI_ABS_SETUP, &yAbsSetup) != 0) {
|
||||
ALOGE("Error creating touchscreen uinput y axis: %s", strerror(errno));
|
||||
return -errno;
|
||||
return invalidFd();
|
||||
}
|
||||
uinput_abs_setup majorAbsSetup;
|
||||
majorAbsSetup.code = ABS_MT_TOUCH_MAJOR;
|
||||
@@ -293,7 +132,7 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, c
|
||||
majorAbsSetup.absinfo.minimum = 0;
|
||||
if (ioctl(fd, UI_ABS_SETUP, &majorAbsSetup) != 0) {
|
||||
ALOGE("Error creating touchscreen uinput major axis: %s", strerror(errno));
|
||||
return -errno;
|
||||
return invalidFd();
|
||||
}
|
||||
uinput_abs_setup pressureAbsSetup;
|
||||
pressureAbsSetup.code = ABS_MT_PRESSURE;
|
||||
@@ -301,7 +140,7 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, c
|
||||
pressureAbsSetup.absinfo.minimum = 0;
|
||||
if (ioctl(fd, UI_ABS_SETUP, &pressureAbsSetup) != 0) {
|
||||
ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
|
||||
return -errno;
|
||||
return invalidFd();
|
||||
}
|
||||
uinput_abs_setup slotAbsSetup;
|
||||
slotAbsSetup.code = ABS_MT_SLOT;
|
||||
@@ -309,12 +148,12 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, c
|
||||
slotAbsSetup.absinfo.minimum = 0;
|
||||
if (ioctl(fd, UI_ABS_SETUP, &slotAbsSetup) != 0) {
|
||||
ALOGE("Error creating touchscreen uinput slots: %s", strerror(errno));
|
||||
return -errno;
|
||||
return invalidFd();
|
||||
}
|
||||
}
|
||||
if (ioctl(fd, UI_DEV_SETUP, &setup) != 0) {
|
||||
ALOGE("Error creating uinput device: %s", strerror(errno));
|
||||
return -errno;
|
||||
return invalidFd();
|
||||
}
|
||||
} else {
|
||||
// UI_DEV_SETUP was not introduced until version 5. Try setting up manually.
|
||||
@@ -338,255 +177,118 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, c
|
||||
}
|
||||
if (TEMP_FAILURE_RETRY(write(fd, &fallback, sizeof(fallback))) != sizeof(fallback)) {
|
||||
ALOGE("Error creating uinput device: %s", strerror(errno));
|
||||
return -errno;
|
||||
return invalidFd();
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(fd, UI_DEV_CREATE) != 0) {
|
||||
ALOGE("Error creating uinput device: %s", strerror(errno));
|
||||
return -errno;
|
||||
return invalidFd();
|
||||
}
|
||||
|
||||
return fd.release();
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId, jstring phys,
|
||||
DeviceType deviceType, int screenHeight, int screenWidth) {
|
||||
static unique_fd openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId,
|
||||
jstring phys, DeviceType deviceType, int screenHeight,
|
||||
int screenWidth) {
|
||||
ScopedUtfChars readableName(env, name);
|
||||
ScopedUtfChars readablePhys(env, phys);
|
||||
return openUinput(readableName.c_str(), vendorId, productId, readablePhys.c_str(), deviceType,
|
||||
screenHeight, screenWidth);
|
||||
}
|
||||
|
||||
static int nativeOpenUinputDpad(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys) {
|
||||
return openUinputJni(env, name, vendorId, productId, phys, DeviceType::DPAD,
|
||||
/* screenHeight */ 0, /* screenWidth */ 0);
|
||||
static jlong nativeOpenUinputDpad(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys) {
|
||||
auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::DPAD,
|
||||
/* screenHeight= */ 0, /* screenWidth= */ 0);
|
||||
return fd.ok() ? reinterpret_cast<jlong>(new VirtualDpad(std::move(fd))) : INVALID_PTR;
|
||||
}
|
||||
|
||||
static int nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys) {
|
||||
return openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD,
|
||||
/* screenHeight */ 0, /* screenWidth */ 0);
|
||||
static jlong nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys) {
|
||||
auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD,
|
||||
/* screenHeight= */ 0, /* screenWidth= */ 0);
|
||||
return fd.ok() ? reinterpret_cast<jlong>(new VirtualKeyboard(std::move(fd))) : INVALID_PTR;
|
||||
}
|
||||
|
||||
static int nativeOpenUinputMouse(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys) {
|
||||
return openUinputJni(env, name, vendorId, productId, phys, DeviceType::MOUSE,
|
||||
/* screenHeight */ 0, /* screenWidth */ 0);
|
||||
static jlong nativeOpenUinputMouse(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys) {
|
||||
auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::MOUSE,
|
||||
/* screenHeight= */ 0, /* screenWidth= */ 0);
|
||||
return fd.ok() ? reinterpret_cast<jlong>(new VirtualMouse(std::move(fd))) : INVALID_PTR;
|
||||
}
|
||||
|
||||
static int nativeOpenUinputTouchscreen(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys, jint height, jint width) {
|
||||
return openUinputJni(env, name, vendorId, productId, phys, DeviceType::TOUCHSCREEN, height,
|
||||
width);
|
||||
static jlong nativeOpenUinputTouchscreen(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys, jint height, jint width) {
|
||||
auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::TOUCHSCREEN, height,
|
||||
width);
|
||||
return fd.ok() ? reinterpret_cast<jlong>(new VirtualTouchscreen(std::move(fd))) : INVALID_PTR;
|
||||
}
|
||||
|
||||
static bool nativeCloseUinput(JNIEnv* env, jobject thiz, jint fd) {
|
||||
ioctl(fd, UI_DEV_DESTROY);
|
||||
if (auto touchesOnFd = unreleasedTouches.find(fd); touchesOnFd != unreleasedTouches.end()) {
|
||||
const size_t remainingPointers = touchesOnFd->second.size();
|
||||
unreleasedTouches.erase(touchesOnFd);
|
||||
ALOGW_IF(remainingPointers > 0, "Closing touchscreen %d, erased %zu unreleased pointers.",
|
||||
fd, remainingPointers);
|
||||
}
|
||||
return close(fd);
|
||||
static void nativeCloseUinput(JNIEnv* env, jobject thiz, jlong ptr) {
|
||||
VirtualInputDevice* virtualInputDevice = reinterpret_cast<VirtualInputDevice*>(ptr);
|
||||
delete virtualInputDevice;
|
||||
}
|
||||
|
||||
static bool writeInputEvent(int fd, uint16_t type, uint16_t code, int32_t value) {
|
||||
struct input_event ev = {.type = type, .code = code, .value = value};
|
||||
return TEMP_FAILURE_RETRY(write(fd, &ev, sizeof(struct input_event))) == sizeof(ev);
|
||||
}
|
||||
|
||||
static bool writeKeyEvent(jint fd, jint androidKeyCode, jint action,
|
||||
const std::map<int, int>& keyCodeMapping) {
|
||||
auto keyCodeIterator = keyCodeMapping.find(androidKeyCode);
|
||||
if (keyCodeIterator == keyCodeMapping.end()) {
|
||||
ALOGE("Unsupported native keycode for androidKeyCode %d", androidKeyCode);
|
||||
return false;
|
||||
}
|
||||
auto actionIterator = KEY_ACTION_MAPPING.find(action);
|
||||
if (actionIterator == KEY_ACTION_MAPPING.end()) {
|
||||
return false;
|
||||
}
|
||||
if (!writeInputEvent(fd, EV_KEY, static_cast<uint16_t>(keyCodeIterator->second),
|
||||
static_cast<int32_t>(actionIterator->second))) {
|
||||
return false;
|
||||
}
|
||||
if (!writeInputEvent(fd, EV_SYN, SYN_REPORT, 0)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nativeWriteDpadKeyEvent(JNIEnv* env, jobject thiz, jint fd, jint androidKeyCode,
|
||||
// Native methods for VirtualDpad
|
||||
static bool nativeWriteDpadKeyEvent(JNIEnv* env, jobject thiz, jlong ptr, jint androidKeyCode,
|
||||
jint action) {
|
||||
return writeKeyEvent(fd, androidKeyCode, action, DPAD_KEY_CODE_MAPPING);
|
||||
VirtualDpad* virtualDpad = reinterpret_cast<VirtualDpad*>(ptr);
|
||||
return virtualDpad->writeDpadKeyEvent(androidKeyCode, action);
|
||||
}
|
||||
|
||||
static bool nativeWriteKeyEvent(JNIEnv* env, jobject thiz, jint fd, jint androidKeyCode,
|
||||
// Native methods for VirtualKeyboard
|
||||
static bool nativeWriteKeyEvent(JNIEnv* env, jobject thiz, jlong ptr, jint androidKeyCode,
|
||||
jint action) {
|
||||
return writeKeyEvent(fd, androidKeyCode, action, KEY_CODE_MAPPING);
|
||||
VirtualKeyboard* virtualKeyboard = reinterpret_cast<VirtualKeyboard*>(ptr);
|
||||
return virtualKeyboard->writeKeyEvent(androidKeyCode, action);
|
||||
}
|
||||
|
||||
static bool nativeWriteButtonEvent(JNIEnv* env, jobject thiz, jint fd, jint buttonCode,
|
||||
// Native methods for VirtualTouchscreen
|
||||
static bool nativeWriteTouchEvent(JNIEnv* env, jobject thiz, jlong ptr, jint pointerId,
|
||||
jint toolType, jint action, jfloat locationX, jfloat locationY,
|
||||
jfloat pressure, jfloat majorAxisSize) {
|
||||
VirtualTouchscreen* virtualTouchscreen = reinterpret_cast<VirtualTouchscreen*>(ptr);
|
||||
return virtualTouchscreen->writeTouchEvent(pointerId, toolType, action, locationX, locationY,
|
||||
pressure, majorAxisSize);
|
||||
}
|
||||
|
||||
// Native methods for VirtualMouse
|
||||
static bool nativeWriteButtonEvent(JNIEnv* env, jobject thiz, jlong ptr, jint buttonCode,
|
||||
jint action) {
|
||||
auto buttonCodeIterator = BUTTON_CODE_MAPPING.find(buttonCode);
|
||||
if (buttonCodeIterator == BUTTON_CODE_MAPPING.end()) {
|
||||
return false;
|
||||
}
|
||||
auto actionIterator = BUTTON_ACTION_MAPPING.find(action);
|
||||
if (actionIterator == BUTTON_ACTION_MAPPING.end()) {
|
||||
return false;
|
||||
}
|
||||
if (!writeInputEvent(fd, EV_KEY, static_cast<uint16_t>(buttonCodeIterator->second),
|
||||
static_cast<int32_t>(actionIterator->second))) {
|
||||
return false;
|
||||
}
|
||||
if (!writeInputEvent(fd, EV_SYN, SYN_REPORT, 0)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
|
||||
return virtualMouse->writeButtonEvent(buttonCode, action);
|
||||
}
|
||||
|
||||
static bool handleTouchUp(int fd, int pointerId) {
|
||||
if (!writeInputEvent(fd, EV_ABS, ABS_MT_TRACKING_ID, static_cast<int32_t>(-1))) {
|
||||
return false;
|
||||
}
|
||||
auto touchesOnFd = unreleasedTouches.find(fd);
|
||||
if (touchesOnFd == unreleasedTouches.end()) {
|
||||
ALOGE("PointerId %d action UP received with no prior events on touchscreen %d.", pointerId,
|
||||
fd);
|
||||
return false;
|
||||
}
|
||||
ALOGD_IF(isDebug(), "Unreleased touches found for touchscreen %d in the map", fd);
|
||||
|
||||
// When a pointer is no longer in touch, remove the pointer id from the corresponding
|
||||
// entry in the unreleased touches map.
|
||||
if (pointerId < 0 || pointerId >= MAX_POINTERS) {
|
||||
ALOGE("Virtual touch event has invalid pointer id %d; value must be between 0 and %zu",
|
||||
pointerId, MAX_POINTERS - 1);
|
||||
return false;
|
||||
}
|
||||
if (!touchesOnFd->second.test(pointerId)) {
|
||||
ALOGE("PointerId %d action UP received with no prior action DOWN on touchscreen %d.",
|
||||
pointerId, fd);
|
||||
return false;
|
||||
}
|
||||
touchesOnFd->second.reset(pointerId);
|
||||
ALOGD_IF(isDebug(), "Pointer %d erased from the touchscreen %d", pointerId, fd);
|
||||
|
||||
// Only sends the BTN UP event when there's no pointers on the touchscreen.
|
||||
if (touchesOnFd->second.none()) {
|
||||
unreleasedTouches.erase(touchesOnFd);
|
||||
if (!writeInputEvent(fd, EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::RELEASE))) {
|
||||
return false;
|
||||
}
|
||||
ALOGD_IF(isDebug(), "No pointers on touchscreen %d, BTN UP event sent.", fd);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handleTouchDown(int fd, int pointerId) {
|
||||
// When a new pointer is down on the touchscreen, add the pointer id in the corresponding
|
||||
// entry in the unreleased touches map.
|
||||
auto touchesOnFd = unreleasedTouches.find(fd);
|
||||
if (touchesOnFd == unreleasedTouches.end()) {
|
||||
// Only sends the BTN Down event when the first pointer on the touchscreen is down.
|
||||
if (!writeInputEvent(fd, EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::PRESS))) {
|
||||
return false;
|
||||
}
|
||||
touchesOnFd = unreleasedTouches.insert({fd, {}}).first;
|
||||
ALOGD_IF(isDebug(), "New touchscreen with fd %d added in the unreleased touches map.", fd);
|
||||
}
|
||||
if (touchesOnFd->second.test(pointerId)) {
|
||||
ALOGE("Repetitive action DOWN event received on a pointer %d that is already down.",
|
||||
pointerId);
|
||||
return false;
|
||||
}
|
||||
touchesOnFd->second.set(pointerId);
|
||||
ALOGD_IF(isDebug(), "Added pointer %d under touchscreen %d in the map", pointerId, fd);
|
||||
if (!writeInputEvent(fd, EV_ABS, ABS_MT_TRACKING_ID, static_cast<int32_t>(pointerId))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nativeWriteTouchEvent(JNIEnv* env, jobject thiz, jint fd, jint pointerId, jint toolType,
|
||||
jint action, jfloat locationX, jfloat locationY, jfloat pressure,
|
||||
jfloat majorAxisSize) {
|
||||
if (!writeInputEvent(fd, EV_ABS, ABS_MT_SLOT, pointerId)) {
|
||||
return false;
|
||||
}
|
||||
auto toolTypeIterator = TOOL_TYPE_MAPPING.find(toolType);
|
||||
if (toolTypeIterator == TOOL_TYPE_MAPPING.end()) {
|
||||
return false;
|
||||
}
|
||||
if (toolType != -1) {
|
||||
if (!writeInputEvent(fd, EV_ABS, ABS_MT_TOOL_TYPE,
|
||||
static_cast<int32_t>(toolTypeIterator->second))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
auto actionIterator = TOUCH_ACTION_MAPPING.find(action);
|
||||
if (actionIterator == TOUCH_ACTION_MAPPING.end()) {
|
||||
return false;
|
||||
}
|
||||
UinputAction uinputAction = actionIterator->second;
|
||||
if (uinputAction == UinputAction::PRESS && !handleTouchDown(fd, pointerId)) {
|
||||
return false;
|
||||
} else if (uinputAction == UinputAction::RELEASE && !handleTouchUp(fd, pointerId)) {
|
||||
return false;
|
||||
}
|
||||
if (!writeInputEvent(fd, EV_ABS, ABS_MT_POSITION_X, locationX)) {
|
||||
return false;
|
||||
}
|
||||
if (!writeInputEvent(fd, EV_ABS, ABS_MT_POSITION_Y, locationY)) {
|
||||
return false;
|
||||
}
|
||||
if (!isnan(pressure)) {
|
||||
if (!writeInputEvent(fd, EV_ABS, ABS_MT_PRESSURE, pressure)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!isnan(majorAxisSize)) {
|
||||
if (!writeInputEvent(fd, EV_ABS, ABS_MT_TOUCH_MAJOR, majorAxisSize)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return writeInputEvent(fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
|
||||
static bool nativeWriteRelativeEvent(JNIEnv* env, jobject thiz, jint fd, jfloat relativeX,
|
||||
static bool nativeWriteRelativeEvent(JNIEnv* env, jobject thiz, jlong ptr, jfloat relativeX,
|
||||
jfloat relativeY) {
|
||||
return writeInputEvent(fd, EV_REL, REL_X, relativeX) &&
|
||||
writeInputEvent(fd, EV_REL, REL_Y, relativeY) &&
|
||||
writeInputEvent(fd, EV_SYN, SYN_REPORT, 0);
|
||||
VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
|
||||
return virtualMouse->writeRelativeEvent(relativeX, relativeY);
|
||||
}
|
||||
|
||||
static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jint fd, jfloat xAxisMovement,
|
||||
static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jlong ptr, jfloat xAxisMovement,
|
||||
jfloat yAxisMovement) {
|
||||
return writeInputEvent(fd, EV_REL, REL_HWHEEL, xAxisMovement) &&
|
||||
writeInputEvent(fd, EV_REL, REL_WHEEL, yAxisMovement) &&
|
||||
writeInputEvent(fd, EV_SYN, SYN_REPORT, 0);
|
||||
VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
|
||||
return virtualMouse->writeScrollEvent(xAxisMovement, yAxisMovement);
|
||||
}
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
{"nativeOpenUinputDpad", "(Ljava/lang/String;IILjava/lang/String;)I",
|
||||
{"nativeOpenUinputDpad", "(Ljava/lang/String;IILjava/lang/String;)J",
|
||||
(void*)nativeOpenUinputDpad},
|
||||
{"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)I",
|
||||
{"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)J",
|
||||
(void*)nativeOpenUinputKeyboard},
|
||||
{"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)I",
|
||||
{"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)J",
|
||||
(void*)nativeOpenUinputMouse},
|
||||
{"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)I",
|
||||
{"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)J",
|
||||
(void*)nativeOpenUinputTouchscreen},
|
||||
{"nativeCloseUinput", "(I)Z", (void*)nativeCloseUinput},
|
||||
{"nativeWriteDpadKeyEvent", "(III)Z", (void*)nativeWriteDpadKeyEvent},
|
||||
{"nativeWriteKeyEvent", "(III)Z", (void*)nativeWriteKeyEvent},
|
||||
{"nativeWriteButtonEvent", "(III)Z", (void*)nativeWriteButtonEvent},
|
||||
{"nativeWriteTouchEvent", "(IIIIFFFF)Z", (void*)nativeWriteTouchEvent},
|
||||
{"nativeWriteRelativeEvent", "(IFF)Z", (void*)nativeWriteRelativeEvent},
|
||||
{"nativeWriteScrollEvent", "(IFF)Z", (void*)nativeWriteScrollEvent},
|
||||
{"nativeCloseUinput", "(J)V", (void*)nativeCloseUinput},
|
||||
{"nativeWriteDpadKeyEvent", "(JII)Z", (void*)nativeWriteDpadKeyEvent},
|
||||
{"nativeWriteKeyEvent", "(JII)Z", (void*)nativeWriteKeyEvent},
|
||||
{"nativeWriteButtonEvent", "(JII)Z", (void*)nativeWriteButtonEvent},
|
||||
{"nativeWriteTouchEvent", "(JIIIFFFF)Z", (void*)nativeWriteTouchEvent},
|
||||
{"nativeWriteRelativeEvent", "(JFF)Z", (void*)nativeWriteRelativeEvent},
|
||||
{"nativeWriteScrollEvent", "(JFF)Z", (void*)nativeWriteScrollEvent},
|
||||
};
|
||||
|
||||
int register_android_server_companion_virtual_InputController(JNIEnv* env) {
|
||||
|
||||
@@ -79,7 +79,7 @@ class InputManagerMockHelper {
|
||||
InputManager.resetInstance(mIInputManagerMock);
|
||||
}
|
||||
|
||||
private Void handleNativeOpenInputDevice(InvocationOnMock inv) {
|
||||
private long handleNativeOpenInputDevice(InvocationOnMock inv) {
|
||||
Objects.requireNonNull(mDevicesChangedListener,
|
||||
"InputController did not register an InputDevicesChangedListener.");
|
||||
|
||||
@@ -101,6 +101,7 @@ class InputManagerMockHelper {
|
||||
}
|
||||
// Process the device added notification.
|
||||
mTestableLooper.processAllMessages();
|
||||
return null;
|
||||
// Return a placeholder pointer to the native input device.
|
||||
return 1L;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user