You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-07 12:30:27 +00:00
Add support for pointer capture
This commit is contained in:
@@ -105,7 +105,7 @@ public class GodotLib {
|
||||
/**
|
||||
* Dispatch mouse events
|
||||
*/
|
||||
public static native void dispatchMouseEvent(int event, int buttonMask, float x, float y, float deltaX, float deltaY, boolean doubleClick);
|
||||
public static native void dispatchMouseEvent(int event, int buttonMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative);
|
||||
|
||||
public static native void magnify(float x, float y, float factor);
|
||||
|
||||
|
||||
@@ -126,6 +126,29 @@ public class GodotView extends GLSurfaceView {
|
||||
return inputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCapturedPointerEvent(MotionEvent event) {
|
||||
return inputHandler.onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPointerCaptureChange(boolean hasCapture) {
|
||||
super.onPointerCaptureChange(hasCapture);
|
||||
inputHandler.onPointerCaptureChange(hasCapture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestPointerCapture() {
|
||||
super.requestPointerCapture();
|
||||
inputHandler.onPointerCaptureChange(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releasePointerCapture() {
|
||||
super.releasePointerCapture();
|
||||
inputHandler.onPointerCaptureChange(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from JNI to change the pointer icon
|
||||
*/
|
||||
|
||||
@@ -131,7 +131,9 @@ public class GodotEditText extends EditText {
|
||||
edit.setText("");
|
||||
edit.append(text);
|
||||
if (msg.arg2 != -1) {
|
||||
edit.setSelection(msg.arg1, msg.arg2);
|
||||
int selectionStart = Math.min(msg.arg1, edit.length());
|
||||
int selectionEnd = Math.min(msg.arg2, edit.length());
|
||||
edit.setSelection(selectionStart, selectionEnd);
|
||||
edit.mInputWrapper.setSelection(true);
|
||||
} else {
|
||||
edit.mInputWrapper.setSelection(false);
|
||||
|
||||
@@ -30,7 +30,9 @@
|
||||
|
||||
package org.godotengine.godot.input
|
||||
|
||||
import android.os.Build
|
||||
import android.view.GestureDetector.SimpleOnGestureListener
|
||||
import android.view.InputDevice
|
||||
import android.view.MotionEvent
|
||||
import android.view.ScaleGestureDetector
|
||||
import android.view.ScaleGestureDetector.OnScaleGestureListener
|
||||
@@ -57,6 +59,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
|
||||
private var dragInProgress = false
|
||||
private var scaleInProgress = false
|
||||
private var contextClickInProgress = false
|
||||
private var pointerCaptureInProgress = false
|
||||
|
||||
override fun onDown(event: MotionEvent): Boolean {
|
||||
GodotInputHandler.handleMotionEvent(event.source, MotionEvent.ACTION_DOWN, event.buttonState, event.x, event.y, nextDownIsDoubleTap)
|
||||
@@ -74,7 +77,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
|
||||
}
|
||||
|
||||
private fun contextClickRouter(event: MotionEvent) {
|
||||
if (scaleInProgress) {
|
||||
if (scaleInProgress || nextDownIsDoubleTap) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -97,6 +100,27 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
|
||||
contextClickInProgress = true
|
||||
}
|
||||
|
||||
fun onPointerCaptureChange(hasCapture: Boolean) {
|
||||
if (pointerCaptureInProgress == hasCapture) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!hasCapture) {
|
||||
// Dispatch a mouse relative ACTION_UP event to signal the end of the capture
|
||||
GodotInputHandler.handleMouseEvent(
|
||||
MotionEvent.ACTION_UP,
|
||||
0,
|
||||
0f,
|
||||
0f,
|
||||
0f,
|
||||
0f,
|
||||
false,
|
||||
true
|
||||
)
|
||||
}
|
||||
pointerCaptureInProgress = hasCapture
|
||||
}
|
||||
|
||||
fun onMotionEvent(event: MotionEvent): Boolean {
|
||||
return when (event.actionMasked) {
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_BUTTON_RELEASE -> {
|
||||
@@ -110,30 +134,59 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
|
||||
}
|
||||
|
||||
private fun onActionUp(event: MotionEvent): Boolean {
|
||||
if (dragInProgress) {
|
||||
GodotInputHandler.handleMotionEvent(event)
|
||||
dragInProgress = false
|
||||
if (event.actionMasked == MotionEvent.ACTION_CANCEL && pointerCaptureInProgress) {
|
||||
// Don't dispatch the ACTION_CANCEL while a capture is in progress
|
||||
return true
|
||||
} else if (contextClickInProgress) {
|
||||
GodotInputHandler.handleMouseEvent(
|
||||
event.actionMasked,
|
||||
0,
|
||||
event.x,
|
||||
event.y
|
||||
)
|
||||
}
|
||||
|
||||
val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
if (pointerCaptureInProgress || dragInProgress || contextClickInProgress) {
|
||||
if (contextClickInProgress || GodotInputHandler.isMouseEvent(event)) {
|
||||
// This may be an ACTION_BUTTON_RELEASE event which we don't handle,
|
||||
// so we convert it to an ACTION_UP event.
|
||||
GodotInputHandler.handleMouseEvent(
|
||||
MotionEvent.ACTION_UP,
|
||||
event.buttonState,
|
||||
event.x,
|
||||
event.y,
|
||||
0f,
|
||||
0f,
|
||||
false,
|
||||
sourceMouseRelative
|
||||
)
|
||||
} else {
|
||||
GodotInputHandler.handleTouchEvent(event)
|
||||
}
|
||||
pointerCaptureInProgress = false
|
||||
dragInProgress = false
|
||||
contextClickInProgress = false
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun onActionMove(event: MotionEvent): Boolean {
|
||||
if (contextClickInProgress) {
|
||||
val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
GodotInputHandler.handleMouseEvent(
|
||||
event.actionMasked,
|
||||
MotionEvent.BUTTON_SECONDARY,
|
||||
event.x,
|
||||
event.y
|
||||
event.y,
|
||||
0f,
|
||||
0f,
|
||||
false,
|
||||
sourceMouseRelative
|
||||
)
|
||||
return true
|
||||
}
|
||||
@@ -178,7 +231,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
|
||||
|
||||
val x = terminusEvent.x
|
||||
val y = terminusEvent.y
|
||||
if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled) {
|
||||
if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled && !pointerCaptureInProgress) {
|
||||
GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f)
|
||||
} else {
|
||||
GodotInputHandler.handleMotionEvent(terminusEvent)
|
||||
@@ -187,7 +240,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
|
||||
}
|
||||
|
||||
override fun onScale(detector: ScaleGestureDetector?): Boolean {
|
||||
if (detector == null || !panningAndScalingEnabled) {
|
||||
if (detector == null || !panningAndScalingEnabled || pointerCaptureInProgress) {
|
||||
return false
|
||||
}
|
||||
GodotLib.magnify(
|
||||
@@ -199,7 +252,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
|
||||
}
|
||||
|
||||
override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
|
||||
if (detector == null || !panningAndScalingEnabled) {
|
||||
if (detector == null || !panningAndScalingEnabled || pointerCaptureInProgress) {
|
||||
return false
|
||||
}
|
||||
scaleInProgress = true
|
||||
|
||||
@@ -105,6 +105,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
||||
return (source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD;
|
||||
}
|
||||
|
||||
public void onPointerCaptureChange(boolean hasCapture) {
|
||||
godotGestureHandler.onPointerCaptureChange(hasCapture);
|
||||
}
|
||||
|
||||
public boolean onKeyUp(final int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
return true;
|
||||
@@ -202,6 +206,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (godotGestureHandler.onMotionEvent(event)) {
|
||||
// The gesture handler has handled the event.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getActionMasked() == MotionEvent.ACTION_MOVE) {
|
||||
// Check if the device exists
|
||||
final int deviceId = event.getDeviceId();
|
||||
@@ -237,7 +246,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (isMouseEvent(event)) {
|
||||
} else {
|
||||
return handleMouseEvent(event);
|
||||
}
|
||||
|
||||
@@ -414,7 +423,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
||||
}
|
||||
|
||||
private static boolean isMouseEvent(int eventSource) {
|
||||
return ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS);
|
||||
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);
|
||||
}
|
||||
return mouseSource;
|
||||
}
|
||||
|
||||
static boolean handleMotionEvent(final MotionEvent event) {
|
||||
@@ -435,7 +448,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
||||
|
||||
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);
|
||||
return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleTap, false);
|
||||
}
|
||||
|
||||
return handleTouchEvent(eventAction, x, y, doubleTap);
|
||||
@@ -449,14 +462,25 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
||||
|
||||
final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
|
||||
final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
|
||||
return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false);
|
||||
boolean sourceMouseRelative = false;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE);
|
||||
}
|
||||
return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false, sourceMouseRelative);
|
||||
}
|
||||
|
||||
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y) {
|
||||
return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false);
|
||||
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) {
|
||||
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, boolean doubleClick) {
|
||||
return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, doubleClick, false);
|
||||
}
|
||||
|
||||
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
|
||||
// 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.
|
||||
switch (eventAction) {
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
@@ -469,7 +493,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
case MotionEvent.ACTION_SCROLL: {
|
||||
GodotLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick);
|
||||
GodotLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user