|
@@ -32,10 +32,14 @@ package org.godotengine.godot.input;
|
|
|
|
|
|
import static org.godotengine.godot.utils.GLUtils.DEBUG;
|
|
|
|
|
|
+import org.godotengine.godot.Godot;
|
|
|
import org.godotengine.godot.GodotLib;
|
|
|
import org.godotengine.godot.GodotRenderView;
|
|
|
|
|
|
import android.content.Context;
|
|
|
+import android.hardware.Sensor;
|
|
|
+import android.hardware.SensorEvent;
|
|
|
+import android.hardware.SensorEventListener;
|
|
|
import android.hardware.input.InputManager;
|
|
|
import android.os.Build;
|
|
|
import android.util.Log;
|
|
@@ -46,6 +50,10 @@ import android.view.InputDevice;
|
|
|
import android.view.KeyEvent;
|
|
|
import android.view.MotionEvent;
|
|
|
import android.view.ScaleGestureDetector;
|
|
|
+import android.view.Surface;
|
|
|
+import android.view.WindowManager;
|
|
|
+
|
|
|
+import androidx.annotation.NonNull;
|
|
|
|
|
|
import java.util.Collections;
|
|
|
import java.util.HashSet;
|
|
@@ -54,7 +62,7 @@ import java.util.Set;
|
|
|
/**
|
|
|
* Handles input related events for the {@link GodotRenderView} view.
|
|
|
*/
|
|
|
-public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
+public class GodotInputHandler implements InputManager.InputDeviceListener, SensorEventListener {
|
|
|
private static final String TAG = GodotInputHandler.class.getSimpleName();
|
|
|
|
|
|
private static final int ROTARY_INPUT_VERTICAL_AXIS = 1;
|
|
@@ -64,8 +72,9 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4);
|
|
|
private final HashSet<Integer> mHardwareKeyboardIds = new HashSet<>();
|
|
|
|
|
|
- private final GodotRenderView mRenderView;
|
|
|
+ private final Godot godot;
|
|
|
private final InputManager mInputManager;
|
|
|
+ private final WindowManager windowManager;
|
|
|
private final GestureDetector gestureDetector;
|
|
|
private final ScaleGestureDetector scaleGestureDetector;
|
|
|
private final GodotGestureHandler godotGestureHandler;
|
|
@@ -77,12 +86,13 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
|
|
|
private int rotaryInputAxis = ROTARY_INPUT_VERTICAL_AXIS;
|
|
|
|
|
|
- public GodotInputHandler(GodotRenderView godotView) {
|
|
|
- final Context context = godotView.getView().getContext();
|
|
|
- mRenderView = godotView;
|
|
|
+ public GodotInputHandler(Context context, Godot godot) {
|
|
|
+ this.godot = godot;
|
|
|
mInputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE);
|
|
|
mInputManager.registerInputDeviceListener(this, null);
|
|
|
|
|
|
+ windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
|
|
|
+
|
|
|
this.godotGestureHandler = new GodotGestureHandler(this);
|
|
|
this.gestureDetector = new GestureDetector(context, godotGestureHandler);
|
|
|
this.gestureDetector.setIsLongpressEnabled(false);
|
|
@@ -174,7 +184,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
|
|
|
public boolean onKeyDown(final int keyCode, KeyEvent event) {
|
|
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
|
- mRenderView.onBackPressed();
|
|
|
+ godot.onBackPressed();
|
|
|
// press 'back' button should not terminate program
|
|
|
//normal handle 'back' event in game logic
|
|
|
return true;
|
|
@@ -507,7 +517,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
return handleTouchEvent(event, eventActionOverride, doubleTap);
|
|
|
}
|
|
|
|
|
|
- private static float getEventTiltX(MotionEvent event) {
|
|
|
+ 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();
|
|
|
|
|
@@ -520,7 +530,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
return (float)-Math.sin(orientation) * tiltMult;
|
|
|
}
|
|
|
|
|
|
- private static float getEventTiltY(MotionEvent event) {
|
|
|
+ static float getEventTiltY(MotionEvent event) {
|
|
|
// Orientation is returned as a radian value between 0 to pi clockwise or 0 to -pi counterclockwise.
|
|
|
final float orientation = event.getOrientation();
|
|
|
|
|
@@ -579,6 +589,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
}
|
|
|
|
|
|
boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) {
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
// Fix the buttonsMask
|
|
|
switch (eventAction) {
|
|
|
case MotionEvent.ACTION_CANCEL:
|
|
@@ -594,7 +609,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- final int updatedButtonsMask = buttonsMask;
|
|
|
// We don't handle ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE events as they typically
|
|
|
// follow ACTION_DOWN and ACTION_UP events. As such, handling them would result in duplicate
|
|
|
// stream of events to the engine.
|
|
@@ -607,11 +621,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
case MotionEvent.ACTION_HOVER_MOVE:
|
|
|
case MotionEvent.ACTION_MOVE:
|
|
|
case MotionEvent.ACTION_SCROLL: {
|
|
|
- if (shouldDispatchInputToRenderThread()) {
|
|
|
- mRenderView.queueOnRenderThread(() -> GodotLib.dispatchMouseEvent(eventAction, updatedButtonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY));
|
|
|
- } else {
|
|
|
- GodotLib.dispatchMouseEvent(eventAction, updatedButtonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY);
|
|
|
- }
|
|
|
+ runnable.setMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY);
|
|
|
+ dispatchInputEventRunnable(runnable);
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
@@ -627,22 +638,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
}
|
|
|
|
|
|
boolean handleTouchEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
|
|
|
- final int pointerCount = event.getPointerCount();
|
|
|
- if (pointerCount == 0) {
|
|
|
+ if (event.getPointerCount() == 0) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- final float[] positions = new float[pointerCount * 6]; // pointerId1, x1, y1, pressure1, tiltX1, tiltY1, pointerId2, etc...
|
|
|
-
|
|
|
- for (int i = 0; i < pointerCount; 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);
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return false;
|
|
|
}
|
|
|
- final int actionPointerId = event.getPointerId(event.getActionIndex());
|
|
|
|
|
|
switch (eventActionOverride) {
|
|
|
case MotionEvent.ACTION_DOWN:
|
|
@@ -651,11 +654,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
case MotionEvent.ACTION_MOVE:
|
|
|
case MotionEvent.ACTION_POINTER_UP:
|
|
|
case MotionEvent.ACTION_POINTER_DOWN: {
|
|
|
- if (shouldDispatchInputToRenderThread()) {
|
|
|
- mRenderView.queueOnRenderThread(() -> GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap));
|
|
|
- } else {
|
|
|
- GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap);
|
|
|
- }
|
|
|
+ runnable.setTouchEvent(event, eventActionOverride, doubleTap);
|
|
|
+ dispatchInputEventRunnable(runnable);
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
@@ -663,58 +663,128 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
|
|
}
|
|
|
|
|
|
void handleMagnifyEvent(float x, float y, float factor) {
|
|
|
- if (shouldDispatchInputToRenderThread()) {
|
|
|
- mRenderView.queueOnRenderThread(() -> GodotLib.magnify(x, y, factor));
|
|
|
- } else {
|
|
|
- GodotLib.magnify(x, y, factor);
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ runnable.setMagnifyEvent(x, y, factor);
|
|
|
+ dispatchInputEventRunnable(runnable);
|
|
|
}
|
|
|
|
|
|
void handlePanEvent(float x, float y, float deltaX, float deltaY) {
|
|
|
- if (shouldDispatchInputToRenderThread()) {
|
|
|
- mRenderView.queueOnRenderThread(() -> GodotLib.pan(x, y, deltaX, deltaY));
|
|
|
- } else {
|
|
|
- GodotLib.pan(x, y, deltaX, deltaY);
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ runnable.setPanEvent(x, y, deltaX, deltaY);
|
|
|
+ dispatchInputEventRunnable(runnable);
|
|
|
}
|
|
|
|
|
|
private void handleJoystickButtonEvent(int device, int button, boolean pressed) {
|
|
|
- if (shouldDispatchInputToRenderThread()) {
|
|
|
- mRenderView.queueOnRenderThread(() -> GodotLib.joybutton(device, button, pressed));
|
|
|
- } else {
|
|
|
- GodotLib.joybutton(device, button, pressed);
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ runnable.setJoystickButtonEvent(device, button, pressed);
|
|
|
+ dispatchInputEventRunnable(runnable);
|
|
|
}
|
|
|
|
|
|
private void handleJoystickAxisEvent(int device, int axis, float value) {
|
|
|
- if (shouldDispatchInputToRenderThread()) {
|
|
|
- mRenderView.queueOnRenderThread(() -> GodotLib.joyaxis(device, axis, value));
|
|
|
- } else {
|
|
|
- GodotLib.joyaxis(device, axis, value);
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ runnable.setJoystickAxisEvent(device, axis, value);
|
|
|
+ dispatchInputEventRunnable(runnable);
|
|
|
}
|
|
|
|
|
|
private void handleJoystickHatEvent(int device, int hatX, int hatY) {
|
|
|
- if (shouldDispatchInputToRenderThread()) {
|
|
|
- mRenderView.queueOnRenderThread(() -> GodotLib.joyhat(device, hatX, hatY));
|
|
|
- } else {
|
|
|
- GodotLib.joyhat(device, hatX, hatY);
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ runnable.setJoystickHatEvent(device, hatX, hatY);
|
|
|
+ dispatchInputEventRunnable(runnable);
|
|
|
}
|
|
|
|
|
|
private void handleJoystickConnectionChangedEvent(int device, boolean connected, String name) {
|
|
|
- if (shouldDispatchInputToRenderThread()) {
|
|
|
- mRenderView.queueOnRenderThread(() -> GodotLib.joyconnectionchanged(device, connected, name));
|
|
|
- } else {
|
|
|
- GodotLib.joyconnectionchanged(device, connected, name);
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ runnable.setJoystickConnectionChangedEvent(device, connected, name);
|
|
|
+ dispatchInputEventRunnable(runnable);
|
|
|
}
|
|
|
|
|
|
void handleKeyEvent(int physicalKeycode, int unicode, int keyLabel, boolean pressed, boolean echo) {
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ runnable.setKeyEvent(physicalKeycode, unicode, keyLabel, pressed, echo);
|
|
|
+ dispatchInputEventRunnable(runnable);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void dispatchInputEventRunnable(@NonNull InputEventRunnable runnable) {
|
|
|
if (shouldDispatchInputToRenderThread()) {
|
|
|
- mRenderView.queueOnRenderThread(() -> GodotLib.key(physicalKeycode, unicode, keyLabel, pressed, echo));
|
|
|
+ godot.runOnRenderThread(runnable);
|
|
|
} else {
|
|
|
- GodotLib.key(physicalKeycode, unicode, keyLabel, pressed, echo);
|
|
|
+ runnable.run();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onSensorChanged(SensorEvent event) {
|
|
|
+ final float[] values = event.values;
|
|
|
+ if (values == null || values.length != 3) {
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ InputEventRunnable runnable = InputEventRunnable.obtain();
|
|
|
+ if (runnable == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ float rotatedValue0 = 0f;
|
|
|
+ float rotatedValue1 = 0f;
|
|
|
+ float rotatedValue2 = 0f;
|
|
|
+ switch (windowManager.getDefaultDisplay().getRotation()) {
|
|
|
+ case Surface.ROTATION_0:
|
|
|
+ rotatedValue0 = values[0];
|
|
|
+ rotatedValue1 = values[1];
|
|
|
+ rotatedValue2 = values[2];
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Surface.ROTATION_90:
|
|
|
+ rotatedValue0 = -values[1];
|
|
|
+ rotatedValue1 = values[0];
|
|
|
+ rotatedValue2 = values[2];
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Surface.ROTATION_180:
|
|
|
+ rotatedValue0 = -values[0];
|
|
|
+ rotatedValue1 = -values[1];
|
|
|
+ rotatedValue2 = values[2];
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Surface.ROTATION_270:
|
|
|
+ rotatedValue0 = values[1];
|
|
|
+ rotatedValue1 = -values[0];
|
|
|
+ rotatedValue2 = values[2];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ runnable.setSensorEvent(event.sensor.getType(), rotatedValue0, rotatedValue1, rotatedValue2);
|
|
|
+ godot.runOnRenderThread(runnable);
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
|
|
}
|