Cleanup the Android input logic implementation

This commit is contained in:
Fredia Huya-Kouadio 2022-08-14 23:07:43 -07:00
parent 92fa63886c
commit 440fa10246
9 changed files with 560 additions and 334 deletions

View File

@ -57,10 +57,6 @@ void AndroidInputHandler::_set_key_modifier_state(Ref<InputEventWithModifiers> e
ev->set_control(control_mem); ev->set_control(control_mem);
} }
void AndroidInputHandler::process_event(Ref<InputEvent> &p_event) {
input->parse_input_event(p_event);
}
void AndroidInputHandler::process_key_event(int p_scancode, int p_physical_scancode, int p_unicode, bool p_pressed) { void AndroidInputHandler::process_key_event(int p_scancode, int p_physical_scancode, int p_unicode, bool p_pressed) {
Ref<InputEventKey> ev; Ref<InputEventKey> ev;
ev.instance(); ev.instance();
@ -104,20 +100,31 @@ void AndroidInputHandler::process_key_event(int p_scancode, int p_physical_scanc
input->parse_input_event(ev); input->parse_input_event(ev);
} }
void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector<TouchPos> &p_points) { void AndroidInputHandler::_parse_all_touch(bool p_pressed) {
if (touch.size()) {
//end all if exist
for (int i = 0; i < touch.size(); i++) {
Ref<InputEventScreenTouch> ev;
ev.instance();
ev->set_index(touch[i].id);
ev->set_pressed(p_pressed);
ev->set_position(touch[i].pos);
input->parse_input_event(ev);
}
}
}
void AndroidInputHandler::_release_all_touch() {
_parse_all_touch(false);
touch.clear();
}
void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points) {
switch (p_event) { switch (p_event) {
case AMOTION_EVENT_ACTION_DOWN: { //gesture begin case AMOTION_EVENT_ACTION_DOWN: { //gesture begin
if (touch.size()) { // Release any remaining touches or mouse event
//end all if exist _release_mouse_event_info();
for (int i = 0; i < touch.size(); i++) { _release_all_touch();
Ref<InputEventScreenTouch> ev;
ev.instance();
ev->set_index(touch[i].id);
ev->set_pressed(false);
ev->set_position(touch[i].pos);
input->parse_input_event(ev);
}
}
touch.resize(p_points.size()); touch.resize(p_points.size());
for (int i = 0; i < p_points.size(); i++) { for (int i = 0; i < p_points.size(); i++) {
@ -126,18 +133,13 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector
} }
//send touch //send touch
for (int i = 0; i < touch.size(); i++) { _parse_all_touch(true);
Ref<InputEventScreenTouch> ev;
ev.instance();
ev->set_index(touch[i].id);
ev->set_pressed(true);
ev->set_position(touch[i].pos);
input->parse_input_event(ev);
}
} break; } break;
case AMOTION_EVENT_ACTION_MOVE: { //motion case AMOTION_EVENT_ACTION_MOVE: { //motion
ERR_FAIL_COND(touch.size() != p_points.size()); if (touch.size() != p_points.size()) {
return;
}
for (int i = 0; i < touch.size(); i++) { for (int i = 0; i < touch.size(); i++) {
int idx = -1; int idx = -1;
@ -166,18 +168,7 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector
} break; } break;
case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_UP: { //release case AMOTION_EVENT_ACTION_UP: { //release
if (touch.size()) { _release_all_touch();
//end all if exist
for (int i = 0; i < touch.size(); i++) {
Ref<InputEventScreenTouch> ev;
ev.instance();
ev->set_index(touch[i].id);
ev->set_pressed(false);
ev->set_position(touch[i].pos);
input->parse_input_event(ev);
}
touch.clear();
}
} break; } break;
case AMOTION_EVENT_ACTION_POINTER_DOWN: { // add touch case AMOTION_EVENT_ACTION_POINTER_DOWN: { // add touch
for (int i = 0; i < p_points.size(); i++) { for (int i = 0; i < p_points.size(); i++) {
@ -215,73 +206,102 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector
} }
} }
void AndroidInputHandler::process_hover(int p_type, Point2 p_pos) { void AndroidInputHandler::_parse_mouse_event_info(int buttons_mask, bool p_pressed, bool p_double_click) {
// https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER if (!mouse_event_info.valid) {
switch (p_type) { 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);
ev->set_pressed(p_pressed);
int changed_button_mask = buttons_state ^ buttons_mask;
buttons_state = buttons_mask;
ev->set_button_index(_button_index_from_mask(changed_button_mask));
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);
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) {
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 case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move
case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter
case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit
// https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
Ref<InputEventMouseMotion> ev; Ref<InputEventMouseMotion> ev;
ev.instance(); ev.instance();
_set_key_modifier_state(ev); _set_key_modifier_state(ev);
ev->set_position(p_pos); ev->set_position(p_event_pos);
ev->set_global_position(p_pos); ev->set_global_position(p_event_pos);
ev->set_relative(p_pos - hover_prev_pos); ev->set_relative(p_event_pos - hover_prev_pos);
input->parse_input_event(ev); input->parse_input_event(ev);
hover_prev_pos = p_pos; hover_prev_pos = p_event_pos;
} break; } break;
}
}
void AndroidInputHandler::process_mouse_event(int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) { case AMOTION_EVENT_ACTION_DOWN:
int event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask); case AMOTION_EVENT_ACTION_BUTTON_PRESS: {
switch (event_action) { // Release any remaining touches or mouse event
case AMOTION_EVENT_ACTION_BUTTON_PRESS: _release_mouse_event_info();
_release_all_touch();
mouse_event_info.valid = true;
mouse_event_info.pos = p_event_pos;
_parse_mouse_event_info(event_buttons_mask, true, p_double_click);
} break;
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {
Ref<InputEventMouseButton> ev; _release_mouse_event_info();
ev.instance();
_set_key_modifier_state(ev);
ev->set_position(event_pos);
ev->set_global_position(event_pos);
ev->set_pressed(event_action == AMOTION_EVENT_ACTION_BUTTON_PRESS);
int changed_button_mask = buttons_state ^ event_buttons_mask;
buttons_state = event_buttons_mask;
ev->set_button_index(_button_index_from_mask(changed_button_mask));
ev->set_button_mask(event_buttons_mask);
input->parse_input_event(ev);
} break; } break;
case AMOTION_EVENT_ACTION_MOVE: { case AMOTION_EVENT_ACTION_MOVE: {
if (!mouse_event_info.valid) {
return;
}
Ref<InputEventMouseMotion> ev; Ref<InputEventMouseMotion> ev;
ev.instance(); ev.instance();
_set_key_modifier_state(ev); _set_key_modifier_state(ev);
ev->set_position(event_pos); ev->set_position(p_event_pos);
ev->set_global_position(event_pos); ev->set_global_position(p_event_pos);
ev->set_relative(event_pos - hover_prev_pos); ev->set_relative(p_event_pos - hover_prev_pos);
ev->set_button_mask(event_buttons_mask); ev->set_button_mask(event_buttons_mask);
input->parse_input_event(ev); input->parse_input_event(ev);
hover_prev_pos = event_pos; mouse_event_info.pos = p_event_pos;
hover_prev_pos = p_event_pos;
} break; } break;
case AMOTION_EVENT_ACTION_SCROLL: { case AMOTION_EVENT_ACTION_SCROLL: {
Ref<InputEventMouseButton> ev; Ref<InputEventMouseButton> ev;
ev.instance(); ev.instance();
_set_key_modifier_state(ev); _set_key_modifier_state(ev);
ev->set_position(event_pos); ev->set_position(p_event_pos);
ev->set_global_position(event_pos); ev->set_global_position(p_event_pos);
ev->set_pressed(true); ev->set_pressed(true);
buttons_state = event_buttons_mask; buttons_state = event_buttons_mask;
if (event_vertical_factor > 0) { if (p_delta.y > 0) {
_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_UP, event_vertical_factor); _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_UP, p_delta.y);
} else if (event_vertical_factor < 0) { } else if (p_delta.y < 0) {
_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_DOWN, -event_vertical_factor); _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_DOWN, -p_delta.y);
} }
if (event_horizontal_factor > 0) { if (p_delta.x > 0) {
_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_RIGHT, event_horizontal_factor); _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_RIGHT, p_delta.x);
} else if (event_horizontal_factor < 0) { } else if (p_delta.x < 0) {
_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_LEFT, -event_horizontal_factor); _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_LEFT, -p_delta.x);
} }
} break; } break;
} }
@ -299,18 +319,22 @@ void AndroidInputHandler::_wheel_button_click(int event_buttons_mask, const Ref<
input->parse_input_event(evdd); input->parse_input_event(evdd);
} }
void AndroidInputHandler::process_double_tap(int event_android_button_mask, Point2 p_pos) { void AndroidInputHandler::process_magnify(Point2 p_pos, float p_factor) {
int event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask); Ref<InputEventMagnifyGesture> magnify_event;
Ref<InputEventMouseButton> ev; magnify_event.instance();
ev.instance(); _set_key_modifier_state(magnify_event);
_set_key_modifier_state(ev); magnify_event->set_position(p_pos);
ev->set_position(p_pos); magnify_event->set_factor(p_factor);
ev->set_global_position(p_pos); input->parse_input_event(magnify_event);
ev->set_pressed(event_button_mask != 0); }
ev->set_button_index(_button_index_from_mask(event_button_mask));
ev->set_button_mask(event_button_mask); void AndroidInputHandler::process_pan(Point2 p_pos, Vector2 p_delta) {
ev->set_doubleclick(true); Ref<InputEventPanGesture> pan_event;
input->parse_input_event(ev); pan_event.instance();
_set_key_modifier_state(pan_event);
pan_event->set_position(p_pos);
pan_event->set_delta(p_delta);
input->parse_input_event(pan_event);
} }
int AndroidInputHandler::_button_index_from_mask(int button_mask) { int AndroidInputHandler::_button_index_from_mask(int button_mask) {

View File

@ -44,6 +44,11 @@ public:
Point2 pos; Point2 pos;
}; };
struct MouseEventInfo {
bool valid = false;
Point2 pos;
};
enum { enum {
JOY_EVENT_BUTTON = 0, JOY_EVENT_BUTTON = 0,
JOY_EVENT_AXIS = 1, JOY_EVENT_AXIS = 1,
@ -61,6 +66,7 @@ public:
private: private:
Vector<TouchPos> touch; Vector<TouchPos> touch;
MouseEventInfo mouse_event_info;
Point2 hover_prev_pos; // needed to calculate the relative position on hover events Point2 hover_prev_pos; // needed to calculate the relative position on hover events
bool alt_mem = false; bool alt_mem = false;
@ -80,14 +86,21 @@ private:
void _wheel_button_click(int event_buttons_mask, const Ref<InputEventMouseButton> &ev, int wheel_button, float factor); 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 _release_mouse_event_info();
void _parse_all_touch(bool p_pressed);
void _release_all_touch();
public: public:
void process_event(Ref<InputEvent> &p_event);
void process_joy_event(const JoypadEvent &p_event); 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_key_event(int p_scancode, int p_physical_scancode, int p_unicode, bool p_pressed);
void process_touch(int p_event, int p_pointer, const Vector<TouchPos> &p_points); 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_hover(int p_type, Point2 p_pos); void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points);
void process_mouse_event(int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor); void process_magnify(Point2 p_pos, float p_factor);
void process_double_tap(int event_android_button_mask, Point2 p_pos); void process_pan(Point2 p_pos, Vector2 p_delta);
void joy_connection_changed(int p_device, bool p_connected, String p_name); void joy_connection_changed(int p_device, bool p_connected, String p_name);
}; };

View File

@ -82,7 +82,7 @@ public class GodotLib {
public static native void newcontext(); public static native void newcontext();
/** /**
* Forward {@link Activity#onBackPressed()} event from the main thread to the GL thread. * Forward {@link Activity#onBackPressed()} event.
*/ */
public static native void back(); public static native void back();
@ -98,63 +98,60 @@ public class GodotLib {
public static native void ttsCallback(int event, int id, int pos); public static native void ttsCallback(int event, int id, int pos);
/** /**
* Forward touch events from the main thread to the GL thread. * Forward touch events.
*/ */
public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions); public static native void dispatchTouchEvent(int event, int pointer, int pointerCount, float[] positions);
public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions, int buttonsMask);
public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions, int buttonsMask, float verticalFactor, float horizontalFactor);
/** /**
* Forward hover events from the main thread to the GL thread. * Dispatch mouse events
*/ */
public static native void hover(int type, float x, float y); public static native void dispatchMouseEvent(int event, int buttonMask, float x, float y, float deltaX, float deltaY, boolean doubleClick);
public static native void magnify(float x, float y, float factor);
public static native void pan(float x, float y, float deltaX, float deltaY);
/** /**
* Forward double_tap events from the main thread to the GL thread. * Forward accelerometer sensor events.
*/
public static native void doubleTap(int buttonMask, int x, int y);
/**
* Forward accelerometer sensor events from the main thread to the GL thread.
* @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
*/ */
public static native void accelerometer(float x, float y, float z); public static native void accelerometer(float x, float y, float z);
/** /**
* Forward gravity sensor events from the main thread to the GL thread. * Forward gravity sensor events.
* @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
*/ */
public static native void gravity(float x, float y, float z); public static native void gravity(float x, float y, float z);
/** /**
* Forward magnetometer sensor events from the main thread to the GL thread. * Forward magnetometer sensor events.
* @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
*/ */
public static native void magnetometer(float x, float y, float z); public static native void magnetometer(float x, float y, float z);
/** /**
* Forward gyroscope sensor events from the main thread to the GL thread. * Forward gyroscope sensor events.
* @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
*/ */
public static native void gyroscope(float x, float y, float z); public static native void gyroscope(float x, float y, float z);
/** /**
* Forward regular key events from the main thread to the GL thread. * Forward regular key events.
*/ */
public static native void key(int p_scancode, int p_physical_scancode, int p_unicode, boolean p_pressed); public static native void key(int p_scancode, int p_physical_scancode, int p_unicode, boolean p_pressed);
/** /**
* Forward game device's key events from the main thread to the GL thread. * Forward game device's key events.
*/ */
public static native void joybutton(int p_device, int p_but, boolean p_pressed); public static native void joybutton(int p_device, int p_but, boolean p_pressed);
/** /**
* Forward joystick devices axis motion events from the main thread to the GL thread. * Forward joystick devices axis motion events.
*/ */
public static native void joyaxis(int p_device, int p_axis, float p_value); public static native void joyaxis(int p_device, int p_axis, float p_value);
/** /**
* Forward joystick devices hat motion events from the main thread to the GL thread. * Forward joystick devices hat motion events.
*/ */
public static native void joyhat(int p_device, int p_hat_x, int p_hat_y); public static native void joyhat(int p_device, int p_hat_x, int p_hat_y);

View File

@ -31,7 +31,6 @@
package org.godotengine.godot; package org.godotengine.godot;
import org.godotengine.godot.gl.GLSurfaceView; import org.godotengine.godot.gl.GLSurfaceView;
import org.godotengine.godot.input.GodotGestureHandler;
import org.godotengine.godot.input.GodotInputHandler; import org.godotengine.godot.input.GodotInputHandler;
import org.godotengine.godot.utils.GLUtils; import org.godotengine.godot.utils.GLUtils;
import org.godotengine.godot.xr.XRMode; import org.godotengine.godot.xr.XRMode;
@ -45,7 +44,6 @@ import org.godotengine.godot.xr.regular.RegularFallbackConfigChooser;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.view.GestureDetector;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -76,7 +74,6 @@ public class GodotView extends GLSurfaceView {
private final Godot godot; private final Godot godot;
private final GodotInputHandler inputHandler; private final GodotInputHandler inputHandler;
private final GestureDetector detector;
private final GodotRenderer godotRenderer; private final GodotRenderer godotRenderer;
private EGLConfigChooser eglConfigChooser; private EGLConfigChooser eglConfigChooser;
@ -90,7 +87,6 @@ public class GodotView extends GLSurfaceView {
this.godot = godot; this.godot = godot;
this.inputHandler = new GodotInputHandler(this); this.inputHandler = new GodotInputHandler(this);
this.detector = new GestureDetector(context, new GodotGestureHandler(this));
this.godotRenderer = new GodotRenderer(); this.godotRenderer = new GodotRenderer();
init(xrMode, p_translucent); init(xrMode, p_translucent);
@ -104,7 +100,6 @@ public class GodotView extends GLSurfaceView {
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event); super.onTouchEvent(event);
this.detector.onTouchEvent(event);
return inputHandler.onTouchEvent(event); return inputHandler.onTouchEvent(event);
} }

View File

@ -1,87 +0,0 @@
/*************************************************************************/
/* GodotGestureHandler.java */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
package org.godotengine.godot.input;
import org.godotengine.godot.GodotLib;
import org.godotengine.godot.GodotView;
import android.view.GestureDetector;
import android.view.MotionEvent;
/**
* Handles gesture input related events for the {@link GodotView} view.
* https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener
*/
public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener {
private final GodotView godotView;
public GodotGestureHandler(GodotView godotView) {
this.godotView = godotView;
}
private void queueEvent(Runnable task) {
godotView.queueEvent(task);
}
@Override
public boolean onDown(MotionEvent event) {
super.onDown(event);
//Log.i("GodotGesture", "onDown");
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
super.onSingleTapConfirmed(event);
return true;
}
@Override
public void onLongPress(MotionEvent event) {
//Log.i("GodotGesture", "onLongPress");
}
@Override
public boolean onDoubleTap(MotionEvent event) {
//Log.i("GodotGesture", "onDoubleTap");
final int x = Math.round(event.getX());
final int y = Math.round(event.getY());
final int buttonMask = event.getButtonState();
GodotLib.doubleTap(buttonMask, x, y);
return true;
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
//Log.i("GodotGesture", "onFling");
return true;
}
}

View File

@ -0,0 +1,225 @@
/*************************************************************************/
/* GodotGestureHandler.kt */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
package org.godotengine.godot.input
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.ScaleGestureDetector.OnScaleGestureListener
import org.godotengine.godot.GodotLib
/**
* Handles regular and scale gesture input related events for the [GodotView] view.
*
* @See https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener
* @See https://developer.android.com/reference/android/view/ScaleGestureDetector.OnScaleGestureListener
*/
internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureListener {
companion object {
private val TAG = GodotGestureHandler::class.java.simpleName
}
/**
* Enable pan and scale gestures
*/
var panningAndScalingEnabled = false
private var doubleTapInProgress = false
private var dragInProgress = false
private var scaleInProgress = false
private var contextClickInProgress = false
override fun onDown(event: MotionEvent): Boolean {
// Don't send / register a down event while we're in the middle of a double-tap
if (!doubleTapInProgress) {
// Send the down event
GodotInputHandler.handleMotionEvent(event)
}
return true
}
override fun onSingleTapUp(event: MotionEvent): Boolean {
GodotInputHandler.handleMotionEvent(event)
return true
}
override fun onLongPress(event: MotionEvent) {
contextClickRouter(event)
}
private fun contextClickRouter(event: MotionEvent) {
if (scaleInProgress) {
return
}
// Cancel the previous down event
GodotInputHandler.handleMotionEvent(
event.source,
MotionEvent.ACTION_CANCEL,
event.buttonState,
event.x,
event.y
)
// Turn a context click into a single tap right mouse button click.
GodotInputHandler.handleMouseEvent(
MotionEvent.ACTION_DOWN,
MotionEvent.BUTTON_SECONDARY,
event.x,
event.y
)
contextClickInProgress = true
}
fun onMotionEvent(event: MotionEvent): Boolean {
return when (event.actionMasked) {
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_BUTTON_RELEASE -> {
onActionUp(event)
}
MotionEvent.ACTION_MOVE -> {
onActionMove(event)
}
else -> false
}
}
private fun onActionUp(event: MotionEvent): Boolean {
if (dragInProgress) {
GodotInputHandler.handleMotionEvent(event)
dragInProgress = false
return true
} else if (contextClickInProgress) {
GodotInputHandler.handleMouseEvent(
event.actionMasked,
0,
event.x,
event.y
)
contextClickInProgress = false
return true
}
return false
}
private fun onActionMove(event: MotionEvent): Boolean {
if (contextClickInProgress) {
GodotInputHandler.handleMouseEvent(
event.actionMasked,
MotionEvent.BUTTON_SECONDARY,
event.x,
event.y
)
return true
}
return false
}
override fun onDoubleTapEvent(event: MotionEvent): Boolean {
if (event.actionMasked == MotionEvent.ACTION_UP) {
doubleTapInProgress = false
}
return true
}
override fun onDoubleTap(event: MotionEvent): Boolean {
doubleTapInProgress = true
val x = event.x
val y = event.y
val buttonMask =
if (GodotInputHandler.isMouseEvent(event)) {
event.buttonState
} else {
MotionEvent.BUTTON_PRIMARY
}
GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_DOWN, buttonMask, x, y, true)
GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, 0, x, y, false)
return true
}
override fun onScroll(
originEvent: MotionEvent,
terminusEvent: MotionEvent,
distanceX: Float,
distanceY: Float
): Boolean {
if (scaleInProgress) {
if (dragInProgress) {
// Cancel the drag
GodotInputHandler.handleMotionEvent(
originEvent.source,
MotionEvent.ACTION_CANCEL,
originEvent.buttonState,
originEvent.x,
originEvent.y
)
dragInProgress = false
}
return true
}
dragInProgress = true
val x = terminusEvent.x
val y = terminusEvent.y
if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled) {
GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f)
} else {
GodotInputHandler.handleMotionEvent(terminusEvent)
}
return true
}
override fun onScale(detector: ScaleGestureDetector?): Boolean {
if (detector == null || !panningAndScalingEnabled) {
return false
}
GodotLib.magnify(
detector.focusX,
detector.focusY,
detector.scaleFactor
)
return true
}
override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
if (detector == null || !panningAndScalingEnabled) {
return false
}
scaleInProgress = true
return true
}
override fun onScaleEnd(detector: ScaleGestureDetector?) {
scaleInProgress = false
}
}

View File

@ -41,13 +41,13 @@ import android.os.Build;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import android.view.GestureDetector;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.InputDevice.MotionRange;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -55,21 +55,49 @@ import java.util.Set;
* Handles input related events for the {@link GodotView} view. * Handles input related events for the {@link GodotView} view.
*/ */
public class GodotInputHandler implements InputManager.InputDeviceListener { public class GodotInputHandler implements InputManager.InputDeviceListener {
private final String tag = this.getClass().getSimpleName(); private static final String TAG = GodotInputHandler.class.getSimpleName();
private final SparseIntArray mJoystickIds = new SparseIntArray(4); private final SparseIntArray mJoystickIds = new SparseIntArray(4);
private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4); private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4);
private final GodotView godotView; private final GodotView godotView;
private final InputManager inputManager; private final InputManager inputManager;
private final GestureDetector gestureDetector;
private final ScaleGestureDetector scaleGestureDetector;
private final GodotGestureHandler godotGestureHandler;
public GodotInputHandler(GodotView godotView) { public GodotInputHandler(GodotView godotView) {
final Context context = godotView.getContext();
this.godotView = godotView; this.godotView = godotView;
this.inputManager = (InputManager)godotView.getContext().getSystemService(Context.INPUT_SERVICE); this.inputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE);
this.inputManager.registerInputDeviceListener(this, null); this.inputManager.registerInputDeviceListener(this, null);
this.godotGestureHandler = new GodotGestureHandler();
this.gestureDetector = new GestureDetector(context, godotGestureHandler);
this.gestureDetector.setIsLongpressEnabled(false);
this.scaleGestureDetector = new ScaleGestureDetector(context, godotGestureHandler);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.scaleGestureDetector.setStylusScaleEnabled(true);
}
} }
private boolean isKeyEvent_GameDevice(int source) { /**
* Enable long press events. This is false by default.
*/
public void enableLongPress(boolean enable) {
this.gestureDetector.setIsLongpressEnabled(enable);
}
/**
* Enable multi-fingers pan & scale gestures. This is false by default.
*
* Note: This may interfere with multi-touch handling / support.
*/
public void enablePanningAndScalingGestures(boolean enable) {
this.godotGestureHandler.setPanningAndScalingEnabled(enable);
}
private boolean isKeyEventGameDevice(int source) {
// Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD) // Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD)
if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD)) if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD))
return false; return false;
@ -87,7 +115,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
} }
int source = event.getSource(); int source = event.getSource();
if (isKeyEvent_GameDevice(source)) { if (isKeyEventGameDevice(source)) {
// Check if the device exists // Check if the device exists
final int deviceId = event.getDeviceId(); final int deviceId = event.getDeviceId();
if (mJoystickIds.indexOfKey(deviceId) >= 0) { if (mJoystickIds.indexOfKey(deviceId) >= 0) {
@ -122,11 +150,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
} }
int source = event.getSource(); int source = event.getSource();
//Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD)));
final int deviceId = event.getDeviceId(); final int deviceId = event.getDeviceId();
// Check if source is a game device and that the device is a registered gamepad // Check if source is a game device and that the device is a registered gamepad
if (isKeyEvent_GameDevice(source)) { if (isKeyEventGameDevice(source)) {
if (event.getRepeatCount() > 0) // ignore key echo if (event.getRepeatCount() > 0) // ignore key echo
return true; return true;
@ -146,47 +173,36 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
} }
public boolean onTouchEvent(final MotionEvent event) { public boolean onTouchEvent(final MotionEvent event) {
// Mouse drag (mouse pressed and move) doesn't fire onGenericMotionEvent so this is needed this.scaleGestureDetector.onTouchEvent(event);
if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { if (this.gestureDetector.onTouchEvent(event)) {
if (event.getAction() != MotionEvent.ACTION_MOVE) { // The gesture detector has handled the event.
// we return true because every time a mouse event is fired, the event is already handled return true;
// in onGenericMotionEvent, so by touch event we can say that the event is also handled }
return true;
} if (godotGestureHandler.onMotionEvent(event)) {
// The gesture handler has handled the event.
return true;
}
// Drag events are handled by the [GodotGestureHandler]
if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
return true;
}
if (isMouseEvent(event)) {
return handleMouseEvent(event); return handleMouseEvent(event);
} }
final int evcount = event.getPointerCount(); return handleTouchEvent(event);
if (evcount == 0)
return true;
if (godotView != null) {
final float[] arr = new float[event.getPointerCount() * 3]; // pointerId1, x1, y1, pointerId2, etc...
for (int i = 0; i < event.getPointerCount(); i++) {
arr[i * 3 + 0] = event.getPointerId(i);
arr[i * 3 + 1] = event.getX(i);
arr[i * 3 + 2] = event.getY(i);
}
final int action = event.getActionMasked();
final int pointer_idx = event.getPointerId(event.getActionIndex());
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN: {
GodotLib.touch(event.getSource(), action, pointer_idx, evcount, arr);
} break;
}
}
return true;
} }
public boolean onGenericMotionEvent(MotionEvent event) { public boolean onGenericMotionEvent(MotionEvent event) {
if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getAction() == MotionEvent.ACTION_MOVE) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) {
// The gesture detector has handled the event.
return true;
}
if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getActionMasked() == MotionEvent.ACTION_MOVE) {
// Check if the device exists // Check if the device exists
final int deviceId = event.getDeviceId(); final int deviceId = event.getDeviceId();
if (mJoystickIds.indexOfKey(deviceId) >= 0) { if (mJoystickIds.indexOfKey(deviceId) >= 0) {
@ -199,15 +215,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
for (int i = 0; i < joystick.axes.size(); i++) { for (int i = 0; i < joystick.axes.size(); i++) {
final int axis = joystick.axes.get(i); final int axis = joystick.axes.get(i);
final float value = event.getAxisValue(axis); final float value = event.getAxisValue(axis);
/** /*
* As all axes are polled for each event, only fire an axis event if the value has actually changed. As all axes are polled for each event, only fire an axis event if the value has actually changed.
* Prevents flooding Godot with repeated events. Prevents flooding Godot with repeated events.
*/ */
if (joystick.axesValues.indexOfKey(axis) < 0 || (float)joystick.axesValues.get(axis) != value) { if (joystick.axesValues.indexOfKey(axis) < 0 || (float)joystick.axesValues.get(axis) != value) {
// save value to prevent repeats // save value to prevent repeats
joystick.axesValues.put(axis, value); joystick.axesValues.put(axis, value);
final int godotAxisIdx = i; GodotLib.joyaxis(godotJoyId, i, value);
GodotLib.joyaxis(godotJoyId, godotAxisIdx, value);
} }
} }
@ -222,16 +237,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
} }
return true; return true;
} }
} else if (event.isFromSource(InputDevice.SOURCE_STYLUS)) { } else if (isMouseEvent(event)) {
final float x = event.getX(); return handleMouseEvent(event);
final float y = event.getY();
final int type = event.getAction();
GodotLib.hover(type, x, y);
return true;
} else if ((event.isFromSource(InputDevice.SOURCE_MOUSE))) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return handleMouseEvent(event);
}
} }
return false; return false;
@ -243,7 +250,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
for (int deviceId : deviceIds) { for (int deviceId : deviceIds) {
InputDevice device = inputManager.getInputDevice(deviceId); InputDevice device = inputManager.getInputDevice(deviceId);
if (DEBUG) { if (DEBUG) {
Log.v(tag, String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName())); Log.v(TAG, String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName()));
} }
onInputDeviceAdded(deviceId); onInputDeviceAdded(deviceId);
} }
@ -288,13 +295,12 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
joystick.name = device.getName(); joystick.name = device.getName();
//Helps with creating new joypad mappings. //Helps with creating new joypad mappings.
Log.i(tag, "=== New Input Device: " + joystick.name); Log.i(TAG, "=== New Input Device: " + joystick.name);
Set<Integer> already = new HashSet<>(); Set<Integer> already = new HashSet<>();
for (InputDevice.MotionRange range : device.getMotionRanges()) { for (InputDevice.MotionRange range : device.getMotionRanges()) {
boolean isJoystick = range.isFromSource(InputDevice.SOURCE_JOYSTICK); boolean isJoystick = range.isFromSource(InputDevice.SOURCE_JOYSTICK);
boolean isGamepad = range.isFromSource(InputDevice.SOURCE_GAMEPAD); boolean isGamepad = range.isFromSource(InputDevice.SOURCE_GAMEPAD);
//Log.i(tag, "axis: "+range.getAxis()+ ", isJoystick: "+isJoystick+", isGamepad: "+isGamepad);
if (!isJoystick && !isGamepad) { if (!isJoystick && !isGamepad) {
continue; continue;
} }
@ -306,14 +312,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
already.add(axis); already.add(axis);
joystick.axes.add(axis); joystick.axes.add(axis);
} else { } else {
Log.w(tag, " - DUPLICATE AXIS VALUE IN LIST: " + axis); Log.w(TAG, " - DUPLICATE AXIS VALUE IN LIST: " + axis);
} }
} }
} }
Collections.sort(joystick.axes); Collections.sort(joystick.axes);
for (int idx = 0; idx < joystick.axes.size(); idx++) { for (int idx = 0; idx < joystick.axes.size(); idx++) {
//Helps with creating new joypad mappings. //Helps with creating new joypad mappings.
Log.i(tag, " - Mapping Android axis " + joystick.axes.get(idx) + " to Godot axis " + idx); Log.i(TAG, " - Mapping Android axis " + joystick.axes.get(idx) + " to Godot axis " + idx);
} }
mJoysticksDevices.put(deviceId, joystick); mJoysticksDevices.put(deviceId, joystick);
@ -338,13 +344,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
onInputDeviceAdded(deviceId); onInputDeviceAdded(deviceId);
} }
private static class RangeComparator implements Comparator<MotionRange> {
@Override
public int compare(MotionRange arg0, MotionRange arg1) {
return arg0.getAxis() - arg1.getAxis();
}
}
public static int getGodotButton(int keyCode) { public static int getGodotButton(int keyCode) {
int button; int button;
switch (keyCode) { switch (keyCode) {
@ -410,35 +409,106 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return button; return button;
} }
private boolean handleMouseEvent(final MotionEvent event) { static boolean isMouseEvent(MotionEvent event) {
switch (event.getActionMasked()) { return isMouseEvent(event.getSource());
}
private static boolean isMouseEvent(int eventSource) {
return ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS);
}
static boolean handleMotionEvent(final MotionEvent event) {
if (isMouseEvent(event)) {
return handleMouseEvent(event);
}
return handleTouchEvent(event);
}
static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) {
return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0);
}
static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY) {
if (isMouseEvent(eventSource)) {
return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, false);
}
return handleTouchEvent(eventAction, x, y);
}
static boolean handleMouseEvent(final MotionEvent event) {
final int eventAction = event.getActionMasked();
final float x = event.getX();
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);
return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false);
}
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y) {
return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false);
}
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, boolean doubleClick) {
return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, doubleClick);
}
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick) {
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_ENTER:
case MotionEvent.ACTION_HOVER_EXIT:
case MotionEvent.ACTION_HOVER_MOVE: case MotionEvent.ACTION_HOVER_MOVE:
case MotionEvent.ACTION_HOVER_EXIT: { case MotionEvent.ACTION_MOVE:
final float x = event.getX();
final float y = event.getY();
final int type = event.getAction();
GodotLib.hover(type, x, y);
return true;
}
case MotionEvent.ACTION_BUTTON_PRESS:
case MotionEvent.ACTION_BUTTON_RELEASE:
case MotionEvent.ACTION_MOVE: {
final float x = event.getX();
final float y = event.getY();
final int buttonsMask = event.getButtonState();
final int action = event.getAction();
GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask);
return true;
}
case MotionEvent.ACTION_SCROLL: { case MotionEvent.ACTION_SCROLL: {
final float x = event.getX(); GodotLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick);
final float y = event.getY(); return true;
final int buttonsMask = event.getButtonState(); }
final int action = event.getAction(); }
final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL); return false;
final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL); }
GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor);
static boolean handleTouchEvent(final MotionEvent event) {
final int pointerCount = event.getPointerCount();
if (pointerCount == 0) {
return true;
}
final float[] positions = new float[pointerCount * 3]; // pointerId1, x1, y1, pointerId2, etc...
for (int i = 0; i < pointerCount; i++) {
positions[i * 3 + 0] = event.getPointerId(i);
positions[i * 3 + 1] = event.getX(i);
positions[i * 3 + 2] = event.getY(i);
}
final int action = event.getActionMasked();
final int actionPointerId = event.getPointerId(event.getActionIndex());
return handleTouchEvent(action, actionPointerId, pointerCount, positions);
}
static boolean handleTouchEvent(int eventAction, float x, float y) {
return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y });
}
static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions) {
switch (eventAction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN: {
GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions);
return true;
} }
} }
return false; return false;

View File

@ -281,56 +281,47 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env,
return should_swap_buffers; return should_swap_buffers;
} }
void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) { // Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click) {
if (step.get() <= 0) {
return;
}
input_handler->process_mouse_event(p_event_type, p_button_mask, Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y), p_double_click);
}
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position) {
if (step.get() <= 0) { if (step.get() <= 0) {
return; return;
} }
Vector<AndroidInputHandler::TouchPos> points; Vector<AndroidInputHandler::TouchPos> points;
for (int i = 0; i < pointer_count; i++) { for (int i = 0; i < pointer_count; i++) {
jfloat p[3]; jfloat p[3];
env->GetFloatArrayRegion(positions, i * 3, 3, p); env->GetFloatArrayRegion(position, i * 3, 3, p);
AndroidInputHandler::TouchPos tp; AndroidInputHandler::TouchPos tp;
tp.pos = Point2(p[1], p[2]); tp.pos = Point2(p[1], p[2]);
tp.id = (int)p[0]; tp.id = (int)p[0];
points.push_back(tp); points.push_back(tp);
} }
if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { input_handler->process_touch_event(ev, pointer, points);
input_handler->process_mouse_event(ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor);
} else {
input_handler->process_touch(ev, pointer, points);
}
} }
// Called on the UI thread // Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position) { JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor) {
touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position);
}
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position, jint buttons_mask) {
touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position, buttons_mask);
}
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) {
touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position, buttons_mask, vertical_factor, horizontal_factor);
}
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y) {
if (step.get() <= 0) { if (step.get() <= 0) {
return; return;
} }
input_handler->process_hover(p_type, Point2(p_x, p_y)); input_handler->process_magnify(Point2(p_x, p_y), p_factor);
} }
// Called on the UI thread // Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y) { JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y) {
if (step.get() <= 0) { if (step.get() <= 0) {
return; return;
} }
input_handler->process_double_tap(p_button_mask, Point2(p_x, p_y)); input_handler->process_pan(Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y));
} }
// Called on the UI thread // Called on the UI thread

View File

@ -45,12 +45,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos);
JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz); JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask = 0, jfloat vertical_factor = 0, jfloat horizontal_factor = 0); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_scancode, jint p_physical_scancode, jint p_unicode, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_scancode, jint p_physical_scancode, jint p_unicode, jboolean p_pressed);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value);