Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.x] Add support for pointer capture #68441

Merged
merged 1 commit into from
Nov 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 32 additions & 16 deletions platform/android/android_input_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,16 +207,22 @@ void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const
}
}

void AndroidInputHandler::_parse_mouse_event_info(int buttons_mask, bool p_pressed, bool p_double_click) {
void AndroidInputHandler::_parse_mouse_event_info(int buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative) {
if (!mouse_event_info.valid) {
return;
}

Ref<InputEventMouseButton> ev;
ev.instance();
_set_key_modifier_state(ev);
ev->set_position(mouse_event_info.pos);
ev->set_global_position(mouse_event_info.pos);
if (p_source_mouse_relative) {
ev->set_position(hover_prev_pos);
ev->set_global_position(hover_prev_pos);
} else {
ev->set_position(mouse_event_info.pos);
ev->set_global_position(mouse_event_info.pos);
hover_prev_pos = mouse_event_info.pos;
}
ev->set_pressed(p_pressed);
int changed_button_mask = buttons_state ^ buttons_mask;

Expand All @@ -226,15 +232,14 @@ void AndroidInputHandler::_parse_mouse_event_info(int buttons_mask, bool p_press
ev->set_button_mask(buttons_mask);
ev->set_doubleclick(p_double_click);
input->parse_input_event(ev);
hover_prev_pos = mouse_event_info.pos;
}

void AndroidInputHandler::_release_mouse_event_info() {
_parse_mouse_event_info(0, false, false);
void AndroidInputHandler::_release_mouse_event_info(bool p_source_mouse_relative) {
_parse_mouse_event_info(0, false, false, p_source_mouse_relative);
mouse_event_info.valid = false;
}

void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click) {
void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative) {
int event_buttons_mask = _android_button_mask_to_godot_button_mask(p_event_android_buttons_mask);
switch (p_event_action) {
case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move
Expand All @@ -259,13 +264,13 @@ void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_an

mouse_event_info.valid = true;
mouse_event_info.pos = p_event_pos;
_parse_mouse_event_info(event_buttons_mask, true, p_double_click);
_parse_mouse_event_info(event_buttons_mask, true, p_double_click, p_source_mouse_relative);
} break;

case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {
_release_mouse_event_info();
_release_mouse_event_info(p_source_mouse_relative);
} break;

case AMOTION_EVENT_ACTION_MOVE: {
Expand All @@ -276,21 +281,32 @@ void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_an
Ref<InputEventMouseMotion> ev;
ev.instance();
_set_key_modifier_state(ev);
ev->set_position(p_event_pos);
ev->set_global_position(p_event_pos);
ev->set_relative(p_event_pos - hover_prev_pos);
if (p_source_mouse_relative) {
ev->set_position(hover_prev_pos);
ev->set_global_position(hover_prev_pos);
ev->set_relative(p_event_pos);
} else {
ev->set_position(p_event_pos);
ev->set_global_position(p_event_pos);
ev->set_relative(p_event_pos - hover_prev_pos);
mouse_event_info.pos = p_event_pos;
hover_prev_pos = p_event_pos;
}
ev->set_button_mask(event_buttons_mask);
input->parse_input_event(ev);
mouse_event_info.pos = p_event_pos;
hover_prev_pos = p_event_pos;
} break;

case AMOTION_EVENT_ACTION_SCROLL: {
Ref<InputEventMouseButton> ev;
ev.instance();
_set_key_modifier_state(ev);
ev->set_position(p_event_pos);
ev->set_global_position(p_event_pos);
if (p_source_mouse_relative) {
ev->set_position(hover_prev_pos);
ev->set_global_position(hover_prev_pos);
} else {
ev->set_position(p_event_pos);
ev->set_global_position(p_event_pos);
}
ev->set_pressed(true);
buttons_state = event_buttons_mask;
if (p_delta.y > 0) {
Expand Down
6 changes: 3 additions & 3 deletions platform/android/android_input_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ class AndroidInputHandler {

void _wheel_button_click(int event_buttons_mask, const Ref<InputEventMouseButton> &ev, int wheel_button, float factor);

void _parse_mouse_event_info(int buttons_mask, bool p_pressed, bool p_double_click);
void _parse_mouse_event_info(int buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative);

void _release_mouse_event_info();
void _release_mouse_event_info(bool p_source_mouse_relative = false);

void _parse_all_touch(bool p_pressed, bool p_double_tap);

Expand All @@ -97,7 +97,7 @@ class AndroidInputHandler {
public:
void process_joy_event(const JoypadEvent &p_event);
void process_key_event(int p_scancode, int p_physical_scancode, int p_unicode, bool p_pressed);
void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click);
void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative);
void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap);
void process_magnify(Point2 p_pos, float p_factor);
void process_pan(Point2 p_pos, Vector2 p_delta);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,29 @@ public boolean onGenericMotionEvent(MotionEvent event) {
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
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ private void handleMessage(final Message msg) {
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -74,7 +77,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}

private fun contextClickRouter(event: MotionEvent) {
if (scaleInProgress) {
if (scaleInProgress || nextDownIsDoubleTap) {
return
}

Expand All @@ -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 -> {
Expand All @@ -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
}
Expand Down Expand Up @@ -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)
Expand All @@ -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(
Expand All @@ -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
Expand Down
Loading