Skip to content

Commit

Permalink
Merge pull request #77498 from m4gr3d/improve_touchpad_mouse_support_…
Browse files Browse the repository at this point in the history
…main

Improve touchpad and mouse support for the Android editor
  • Loading branch information
YuriSizov authored May 27, 2023
2 parents 2210111 + 01ee00f commit e730a5b
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,10 @@ public void onPointerCaptureChange(boolean hasCapture) {

@Override
public void requestPointerCapture() {
super.requestPointerCapture();
inputHandler.onPointerCaptureChange(true);
if (canCapturePointer()) {
super.requestPointerCapture();
inputHandler.onPointerCaptureChange(true);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ public interface GodotRenderView {
void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY);

void setPointerIcon(int pointerType);

default boolean canCapturePointer() {
return getInputHandler().canCapturePointer();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,10 @@ public boolean onCapturedPointerEvent(MotionEvent event) {

@Override
public void requestPointerCapture() {
super.requestPointerCapture();
mInputHandler.onPointerCaptureChange(true);
if (canCapturePointer()) {
super.requestPointerCapture();
mInputHandler.onPointerCaptureChange(true);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,14 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
)
dragInProgress = false
}
return true
}

dragInProgress = true

val x = terminusEvent.x
val y = terminusEvent.y
if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled && !pointerCaptureInProgress) {
GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f)
} else {
} else if (!scaleInProgress){
dragInProgress = true
GodotInputHandler.handleMotionEvent(terminusEvent)
}
return true
Expand All @@ -246,11 +244,14 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
if (!panningAndScalingEnabled || pointerCaptureInProgress) {
return false
}
GodotLib.magnify(
detector.focusX,
detector.focusY,
detector.scaleFactor
)

if (detector.scaleFactor >= 0.8f && detector.scaleFactor != 1f && detector.scaleFactor <= 1.2f) {
GodotLib.magnify(
detector.focusX,
detector.focusY,
detector.scaleFactor
)
}
return true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
private final ScaleGestureDetector scaleGestureDetector;
private final GodotGestureHandler godotGestureHandler;

/**
* Used to decide whether mouse capture can be enabled.
*/
private int lastSeenToolType = MotionEvent.TOOL_TYPE_UNKNOWN;

public GodotInputHandler(GodotRenderView godotView) {
final Context context = godotView.getView().getContext();
mRenderView = godotView;
Expand Down Expand Up @@ -105,6 +110,10 @@ private boolean isKeyEventGameDevice(int source) {
return (source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD;
}

public boolean canCapturePointer() {
return lastSeenToolType == MotionEvent.TOOL_TYPE_MOUSE;
}

public void onPointerCaptureChange(boolean hasCapture) {
godotGestureHandler.onPointerCaptureChange(hasCapture);
}
Expand Down Expand Up @@ -174,6 +183,8 @@ public boolean onKeyDown(final int keyCode, KeyEvent event) {
}

public boolean onTouchEvent(final MotionEvent event) {
lastSeenToolType = event.getToolType(0);

this.scaleGestureDetector.onTouchEvent(event);
if (this.gestureDetector.onTouchEvent(event)) {
// The gesture detector has handled the event.
Expand All @@ -198,6 +209,8 @@ public boolean onTouchEvent(final MotionEvent event) {
}

public boolean onGenericMotionEvent(MotionEvent event) {
lastSeenToolType = event.getToolType(0);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) {
// The gesture detector has handled the event.
return true;
Expand Down Expand Up @@ -471,15 +484,27 @@ static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float
}

static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
// Fix the buttonsMask
switch (eventAction) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
// Zero-up the button state
buttonsMask = 0;
break;
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
if (buttonsMask == 0) {
buttonsMask = MotionEvent.BUTTON_PRIMARY;
}
break;
}

// 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:
// Zero-up the button state
buttonsMask = 0;
// FALL THROUGH
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_HOVER_ENTER:
case MotionEvent.ACTION_HOVER_EXIT:
Expand Down
13 changes: 12 additions & 1 deletion platform/android/java_godot_view_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,25 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
_request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V");
_release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V");
}

_can_capture_pointer = env->GetMethodID(_cls, "canCapturePointer", "()Z");
}

bool GodotJavaViewWrapper::can_update_pointer_icon() const {
return _configure_pointer_icon != nullptr && _set_pointer_icon != nullptr;
}

bool GodotJavaViewWrapper::can_capture_pointer() const {
return _request_pointer_capture != nullptr && _release_pointer_capture != nullptr;
// We can capture the pointer if the other jni capture method ids are initialized,
// and GodotView#canCapturePointer() returns true.
if (_request_pointer_capture != nullptr && _release_pointer_capture != nullptr && _can_capture_pointer != nullptr) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL_V(env, false);

return env->CallBooleanMethod(_godot_view, _can_capture_pointer);
}

return false;
}

void GodotJavaViewWrapper::request_pointer_capture() {
Expand Down
1 change: 1 addition & 0 deletions platform/android/java_godot_view_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class GodotJavaViewWrapper {

jobject _godot_view;

jmethodID _can_capture_pointer = 0;
jmethodID _request_pointer_capture = 0;
jmethodID _release_pointer_capture = 0;

Expand Down

0 comments on commit e730a5b

Please sign in to comment.