From 99c8cd2b174337912456aff236c9ba815a6d2f6b Mon Sep 17 00:00:00 2001 From: Aleksey Kapustyanenko Date: Sun, 18 Feb 2024 14:04:32 +0400 Subject: [PATCH] Rotary input for 3.x --- doc/classes/InputEventMouseButton.xml | 1 + doc/classes/ProjectSettings.xml | 3 ++ main/main.cpp | 5 ++++ .../lib/src/org/godotengine/godot/Godot.java | 2 ++ .../godot/input/GodotInputHandler.java | 30 +++++++++++++++++-- 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml index f48aca2e3aaf..9af7f9b45375 100644 --- a/doc/classes/InputEventMouseButton.xml +++ b/doc/classes/InputEventMouseButton.xml @@ -5,6 +5,7 @@ Contains mouse click information. See [method Node._input]. + [b]Note:[/b] On Wear OS devices, rotary input is mapped to [constant BUTTON_WHEEL_UP] and [constant BUTTON_WHEEL_DOWN]. This can be changed to [constant BUTTON_WHEEL_LEFT] and [constant BUTTON_WHEEL_RIGHT] with the [member ProjectSettings.input_devices/pointing/android/rotary_input_scroll_axis] setting. $DOCS_URL/tutorials/inputs/mouse_and_input_coordinates.html diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 6b3bee98e4c4..b6554b631fd7 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -682,6 +682,9 @@ If [code]true[/code], multi-touch pan and scale gestures are enabled on Android devices. + + On Wear OS devices, defines which axis of the mouse wheel rotary input is mapped to. This rotary input is usually performed by rotating the physical or virtual (touch-based) bezel on a smartwatch. + If [code]true[/code], sends mouse input events when tapping or swiping on the touchscreen. diff --git a/main/main.cpp b/main/main.cpp index 5e6e612d5159..62726113fc7a 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1581,6 +1581,11 @@ Error Main::setup2(Thread::ID p_main_tid_override) { GLOBAL_DEF("input_devices/pointing/android/enable_long_press_as_right_click", false); GLOBAL_DEF("input_devices/pointing/android/enable_pan_and_scale_gestures", false); + GLOBAL_DEF("input_devices/pointing/android/rotary_input_scroll_axis", 1); + ProjectSettings::get_singleton()->set_custom_property_info("input_devices/pointing/android/rotary_input_scroll_axis", + PropertyInfo(Variant::INT, + "input_devices/pointing/android/rotary_input_scroll_axis", + PROPERTY_HINT_ENUM, "Horizontal,Vertical")); MAIN_PRINT("Main: Load Translations and Remaps"); diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index ac903cab5d00..c79baead83ba 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -335,6 +335,7 @@ protected void onGodotSetupCompleted() { // These properties are defined after Godot setup completion, so we retrieve them here. boolean longPressEnabled = Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click")); boolean panScaleEnabled = Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures")); + int rotaryInputAxis = java.lang.Integer.parseInt(GodotLib.getGlobal("input_devices/pointing/android/rotary_input_scroll_axis")); runOnUiThread(() -> { GodotView renderView = getRenderView(); @@ -343,6 +344,7 @@ protected void onGodotSetupCompleted() { inputHandler.enableLongPress(longPressEnabled); inputHandler.enablePanningAndScalingGestures(panScaleEnabled); } + GodotInputHandler.setRotaryInputAxis(rotaryInputAxis); }); for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java index 2e8b415dfeac..872da45c7fab 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java @@ -57,6 +57,9 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { private static final String TAG = GodotInputHandler.class.getSimpleName(); + private static final int ROTARY_INPUT_VERTICAL_AXIS = 1; + private static final int ROTARY_INPUT_HORIZONTAL_AXIS = 0; + private final SparseIntArray mJoystickIds = new SparseIntArray(4); private final SparseArray mJoysticksDevices = new SparseArray<>(4); @@ -71,6 +74,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { */ private int lastSeenToolType = MotionEvent.TOOL_TYPE_UNKNOWN; + private static int rotaryInputAxis = ROTARY_INPUT_VERTICAL_AXIS; + public GodotInputHandler(GodotView godotView) { final Context context = godotView.getContext(); this.godotView = godotView; @@ -102,6 +107,13 @@ public void enablePanningAndScalingGestures(boolean enable) { this.godotGestureHandler.setPanningAndScalingEnabled(enable); } + /** + * On Wear OS devices, sets which axis of the mouse wheel rotary input is mapped to. This is 1 (vertical axis) by default. + */ + public static void setRotaryInputAxis(int axis) { + rotaryInputAxis = axis; + } + private boolean isKeyEventGameDevice(int source) { // Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD) if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD)) @@ -473,8 +485,22 @@ static boolean handleMouseEvent(final MotionEvent event) { final float y = event.getY(); final int buttonsMask = event.getButtonState(); - final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL); - final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL); + float verticalFactor = 0; + float horizontalFactor = 0; + + // If event came from RotaryEncoder (Bezel or Crown rotate event on Wear OS smart watches), + // convert it to mouse wheel event. + if (event.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER)) { + if (rotaryInputAxis == ROTARY_INPUT_HORIZONTAL_AXIS) { + horizontalFactor = -event.getAxisValue(MotionEvent.AXIS_SCROLL); + } else { + // If rotaryInputAxis is not ROTARY_INPUT_HORIZONTAL_AXIS then use default ROTARY_INPUT_VERTICAL_AXIS axis. + verticalFactor = -event.getAxisValue(MotionEvent.AXIS_SCROLL); + } + } else { + verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL); + horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL); + } boolean sourceMouseRelative = false; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE);