|
@@ -62,6 +62,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
|
|
|
private final SparseIntArray mJoystickIds = new SparseIntArray(4);
|
|
private final SparseIntArray mJoystickIds = new SparseIntArray(4);
|
|
private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4);
|
|
private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4);
|
|
|
|
+ private final HashSet<Integer> mHardwareKeyboardIds = new HashSet<>();
|
|
|
|
|
|
private final GodotRenderView mRenderView;
|
|
private final GodotRenderView mRenderView;
|
|
private final InputManager mInputManager;
|
|
private final InputManager mInputManager;
|
|
@@ -114,6 +115,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
rotaryInputAxis = axis;
|
|
rotaryInputAxis = axis;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ boolean hasHardwareKeyboard() {
|
|
|
|
+ return !mHardwareKeyboardIds.isEmpty();
|
|
|
|
+ }
|
|
|
|
+
|
|
private boolean isKeyEventGameDevice(int source) {
|
|
private boolean isKeyEventGameDevice(int source) {
|
|
// Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD)
|
|
// Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD)
|
|
if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD))
|
|
if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD))
|
|
@@ -195,7 +200,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
}
|
|
}
|
|
|
|
|
|
public boolean onTouchEvent(final MotionEvent event) {
|
|
public boolean onTouchEvent(final MotionEvent event) {
|
|
- lastSeenToolType = event.getToolType(0);
|
|
|
|
|
|
+ lastSeenToolType = getEventToolType(event);
|
|
|
|
|
|
this.scaleGestureDetector.onTouchEvent(event);
|
|
this.scaleGestureDetector.onTouchEvent(event);
|
|
if (this.gestureDetector.onTouchEvent(event)) {
|
|
if (this.gestureDetector.onTouchEvent(event)) {
|
|
@@ -221,7 +226,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
}
|
|
}
|
|
|
|
|
|
public boolean onGenericMotionEvent(MotionEvent event) {
|
|
public boolean onGenericMotionEvent(MotionEvent event) {
|
|
- lastSeenToolType = event.getToolType(0);
|
|
|
|
|
|
+ lastSeenToolType = getEventToolType(event);
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) {
|
|
// The gesture detector has handled the event.
|
|
// The gesture detector has handled the event.
|
|
@@ -310,11 +315,17 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- int sources = device.getSources();
|
|
|
|
|
|
+ // Device may be an external keyboard; store the device id
|
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
|
|
|
|
+ device.supportsSource(InputDevice.SOURCE_KEYBOARD) &&
|
|
|
|
+ device.isExternal() &&
|
|
|
|
+ device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
|
|
|
|
+ mHardwareKeyboardIds.add(deviceId);
|
|
|
|
+ }
|
|
|
|
|
|
// Device may not be a joystick or gamepad
|
|
// Device may not be a joystick or gamepad
|
|
- if ((sources & InputDevice.SOURCE_GAMEPAD) != InputDevice.SOURCE_GAMEPAD &&
|
|
|
|
- (sources & InputDevice.SOURCE_JOYSTICK) != InputDevice.SOURCE_JOYSTICK) {
|
|
|
|
|
|
+ if (!device.supportsSource(InputDevice.SOURCE_GAMEPAD) &&
|
|
|
|
+ !device.supportsSource(InputDevice.SOURCE_JOYSTICK)) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -359,6 +370,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public void onInputDeviceRemoved(int deviceId) {
|
|
public void onInputDeviceRemoved(int deviceId) {
|
|
|
|
+ mHardwareKeyboardIds.remove(deviceId);
|
|
|
|
+
|
|
// Check if the device has not been already removed
|
|
// Check if the device has not been already removed
|
|
if (mJoystickIds.indexOfKey(deviceId) < 0) {
|
|
if (mJoystickIds.indexOfKey(deviceId) < 0) {
|
|
return;
|
|
return;
|
|
@@ -440,50 +453,65 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
return button;
|
|
return button;
|
|
}
|
|
}
|
|
|
|
|
|
- static boolean isMouseEvent(MotionEvent event) {
|
|
|
|
- return isMouseEvent(event.getSource());
|
|
|
|
|
|
+ private static int getEventToolType(MotionEvent event) {
|
|
|
|
+ return event.getPointerCount() > 0 ? event.getToolType(0) : MotionEvent.TOOL_TYPE_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
|
|
- private static boolean isMouseEvent(int eventSource) {
|
|
|
|
- boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS);
|
|
|
|
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
- mouseSource = mouseSource || ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE);
|
|
|
|
|
|
+ static boolean isMouseEvent(MotionEvent event) {
|
|
|
|
+ int toolType = getEventToolType(event);
|
|
|
|
+ int eventSource = event.getSource();
|
|
|
|
+
|
|
|
|
+ switch (toolType) {
|
|
|
|
+ case MotionEvent.TOOL_TYPE_FINGER:
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ case MotionEvent.TOOL_TYPE_MOUSE:
|
|
|
|
+ case MotionEvent.TOOL_TYPE_STYLUS:
|
|
|
|
+ case MotionEvent.TOOL_TYPE_ERASER:
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ case MotionEvent.TOOL_TYPE_UNKNOWN:
|
|
|
|
+ default:
|
|
|
|
+ boolean mouseSource =
|
|
|
|
+ ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) ||
|
|
|
|
+ ((eventSource & (InputDevice.SOURCE_TOUCHSCREEN | InputDevice.SOURCE_STYLUS)) == InputDevice.SOURCE_STYLUS);
|
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
+ mouseSource = mouseSource ||
|
|
|
|
+ ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE);
|
|
|
|
+ }
|
|
|
|
+ return mouseSource;
|
|
}
|
|
}
|
|
- return mouseSource;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static boolean handleMotionEvent(final MotionEvent event) {
|
|
static boolean handleMotionEvent(final MotionEvent event) {
|
|
- if (isMouseEvent(event)) {
|
|
|
|
- return handleMouseEvent(event);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return handleTouchEvent(event);
|
|
|
|
|
|
+ return handleMotionEvent(event, event.getActionMasked());
|
|
}
|
|
}
|
|
|
|
|
|
- static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) {
|
|
|
|
- return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, false);
|
|
|
|
|
|
+ static boolean handleMotionEvent(final MotionEvent event, int eventActionOverride) {
|
|
|
|
+ return handleMotionEvent(event, eventActionOverride, false);
|
|
}
|
|
}
|
|
|
|
|
|
- static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, boolean doubleTap) {
|
|
|
|
- return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0, doubleTap);
|
|
|
|
|
|
+ static boolean handleMotionEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
|
|
|
|
+ if (isMouseEvent(event)) {
|
|
|
|
+ return handleMouseEvent(event, eventActionOverride, doubleTap);
|
|
|
|
+ }
|
|
|
|
+ return handleTouchEvent(event, eventActionOverride, doubleTap);
|
|
}
|
|
}
|
|
|
|
|
|
- static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleTap) {
|
|
|
|
- if (isMouseEvent(eventSource)) {
|
|
|
|
- return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleTap, false);
|
|
|
|
- }
|
|
|
|
|
|
+ private static float getEventTiltX(MotionEvent event) {
|
|
|
|
+ // Orientation is returned as a radian value between 0 to pi clockwise or 0 to -pi counterclockwise.
|
|
|
|
+ final float orientation = event.getOrientation();
|
|
|
|
|
|
- return handleTouchEvent(eventAction, x, y, doubleTap);
|
|
|
|
- }
|
|
|
|
|
|
+ // Tilt is zero is perpendicular to the screen and pi/2 is flat on the surface.
|
|
|
|
+ final float tilt = event.getAxisValue(MotionEvent.AXIS_TILT);
|
|
|
|
|
|
- static boolean handleMouseEvent(final MotionEvent event) {
|
|
|
|
- final int eventAction = event.getActionMasked();
|
|
|
|
- final float x = event.getX();
|
|
|
|
- final float y = event.getY();
|
|
|
|
- final int buttonsMask = event.getButtonState();
|
|
|
|
|
|
+ float tiltMult = (float)Math.sin(tilt);
|
|
|
|
|
|
- final float pressure = event.getPressure();
|
|
|
|
|
|
+ // To be consistent with expected tilt.
|
|
|
|
+ return (float)-Math.sin(orientation) * tiltMult;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ private static float getEventTiltY(MotionEvent event) {
|
|
// Orientation is returned as a radian value between 0 to pi clockwise or 0 to -pi counterclockwise.
|
|
// Orientation is returned as a radian value between 0 to pi clockwise or 0 to -pi counterclockwise.
|
|
final float orientation = event.getOrientation();
|
|
final float orientation = event.getOrientation();
|
|
|
|
|
|
@@ -493,8 +521,26 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
float tiltMult = (float)Math.sin(tilt);
|
|
float tiltMult = (float)Math.sin(tilt);
|
|
|
|
|
|
// To be consistent with expected tilt.
|
|
// To be consistent with expected tilt.
|
|
- final float tiltX = (float)-Math.sin(orientation) * tiltMult;
|
|
|
|
- final float tiltY = (float)Math.cos(orientation) * tiltMult;
|
|
|
|
|
|
+ return (float)Math.cos(orientation) * tiltMult;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static boolean handleMouseEvent(final MotionEvent event) {
|
|
|
|
+ return handleMouseEvent(event, event.getActionMasked());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride) {
|
|
|
|
+ return handleMouseEvent(event, eventActionOverride, false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
|
|
|
|
+ return handleMouseEvent(event, eventActionOverride, event.getButtonState(), doubleTap);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, int buttonMaskOverride, boolean doubleTap) {
|
|
|
|
+ final float x = event.getX();
|
|
|
|
+ final float y = event.getY();
|
|
|
|
+
|
|
|
|
+ final float pressure = event.getPressure();
|
|
|
|
|
|
float verticalFactor = 0;
|
|
float verticalFactor = 0;
|
|
float horizontalFactor = 0;
|
|
float horizontalFactor = 0;
|
|
@@ -516,15 +562,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
|
sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE);
|
|
sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE);
|
|
}
|
|
}
|
|
- return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false, sourceMouseRelative, pressure, tiltX, tiltY);
|
|
|
|
|
|
+ return handleMouseEvent(eventActionOverride, buttonMaskOverride, x, y, horizontalFactor, verticalFactor, doubleTap, sourceMouseRelative, pressure, getEventTiltX(event), getEventTiltY(event));
|
|
}
|
|
}
|
|
|
|
|
|
- static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y) {
|
|
|
|
- return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false, false);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
|
|
|
|
- return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, 1, 0, 0);
|
|
|
|
|
|
+ static boolean handleMouseEvent(int eventAction, boolean sourceMouseRelative) {
|
|
|
|
+ return handleMouseEvent(eventAction, 0, 0f, 0f, 0f, 0f, false, sourceMouseRelative, 1f, 0f, 0f);
|
|
}
|
|
}
|
|
|
|
|
|
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) {
|
|
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) {
|
|
@@ -563,37 +605,39 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
}
|
|
}
|
|
|
|
|
|
static boolean handleTouchEvent(final MotionEvent event) {
|
|
static boolean handleTouchEvent(final MotionEvent event) {
|
|
|
|
+ return handleTouchEvent(event, event.getActionMasked());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static boolean handleTouchEvent(final MotionEvent event, int eventActionOverride) {
|
|
|
|
+ return handleTouchEvent(event, eventActionOverride, false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static boolean handleTouchEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
|
|
final int pointerCount = event.getPointerCount();
|
|
final int pointerCount = event.getPointerCount();
|
|
if (pointerCount == 0) {
|
|
if (pointerCount == 0) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- final float[] positions = new float[pointerCount * 3]; // pointerId1, x1, y1, pointerId2, etc...
|
|
|
|
|
|
+ final float[] positions = new float[pointerCount * 6]; // pointerId1, x1, y1, pressure1, tiltX1, tiltY1, pointerId2, etc...
|
|
|
|
|
|
for (int i = 0; i < pointerCount; i++) {
|
|
for (int i = 0; i < pointerCount; i++) {
|
|
- positions[i * 3 + 0] = event.getPointerId(i);
|
|
|
|
- positions[i * 3 + 1] = event.getX(i);
|
|
|
|
- positions[i * 3 + 2] = event.getY(i);
|
|
|
|
|
|
+ positions[i * 6 + 0] = event.getPointerId(i);
|
|
|
|
+ positions[i * 6 + 1] = event.getX(i);
|
|
|
|
+ positions[i * 6 + 2] = event.getY(i);
|
|
|
|
+ positions[i * 6 + 3] = event.getPressure(i);
|
|
|
|
+ positions[i * 6 + 4] = getEventTiltX(event);
|
|
|
|
+ positions[i * 6 + 5] = getEventTiltY(event);
|
|
}
|
|
}
|
|
- final int action = event.getActionMasked();
|
|
|
|
final int actionPointerId = event.getPointerId(event.getActionIndex());
|
|
final int actionPointerId = event.getPointerId(event.getActionIndex());
|
|
|
|
|
|
- return handleTouchEvent(action, actionPointerId, pointerCount, positions, false);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- static boolean handleTouchEvent(int eventAction, float x, float y, boolean doubleTap) {
|
|
|
|
- return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y }, doubleTap);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions, boolean doubleTap) {
|
|
|
|
- switch (eventAction) {
|
|
|
|
|
|
+ switch (eventActionOverride) {
|
|
case MotionEvent.ACTION_DOWN:
|
|
case MotionEvent.ACTION_DOWN:
|
|
case MotionEvent.ACTION_CANCEL:
|
|
case MotionEvent.ACTION_CANCEL:
|
|
case MotionEvent.ACTION_UP:
|
|
case MotionEvent.ACTION_UP:
|
|
case MotionEvent.ACTION_MOVE:
|
|
case MotionEvent.ACTION_MOVE:
|
|
case MotionEvent.ACTION_POINTER_UP:
|
|
case MotionEvent.ACTION_POINTER_UP:
|
|
case MotionEvent.ACTION_POINTER_DOWN: {
|
|
case MotionEvent.ACTION_POINTER_DOWN: {
|
|
- GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions, doubleTap);
|
|
|
|
|
|
+ GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|