Merge pull request #65434 from m4gr3d/cleanup_input_logic_main
This commit is contained in:
commit
83df155b60
|
@ -207,7 +207,9 @@ bool ProgressDialog::task_step(const String &p_task, const String &p_state, int
|
||||||
DisplayServer::get_singleton()->process_events();
|
DisplayServer::get_singleton()->process_events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ANDROID_ENABLED
|
||||||
Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor
|
Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor
|
||||||
|
#endif
|
||||||
return cancelled;
|
return cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,20 +118,31 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycod
|
||||||
Input::get_singleton()->parse_input_event(ev);
|
Input::get_singleton()->parse_input_event(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector<AndroidInputHandler::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.instantiate();
|
||||||
|
ev->set_index(touch[i].id);
|
||||||
|
ev->set_pressed(p_pressed);
|
||||||
|
ev->set_position(touch[i].pos);
|
||||||
|
Input::get_singleton()->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.instantiate();
|
|
||||||
ev->set_index(touch[i].id);
|
|
||||||
ev->set_pressed(false);
|
|
||||||
ev->set_position(touch[i].pos);
|
|
||||||
Input::get_singleton()->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++) {
|
||||||
|
@ -140,18 +151,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.instantiate();
|
|
||||||
ev->set_index(touch[i].id);
|
|
||||||
ev->set_pressed(true);
|
|
||||||
ev->set_position(touch[i].pos);
|
|
||||||
Input::get_singleton()->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;
|
||||||
|
@ -180,18 +186,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.instantiate();
|
|
||||||
ev->set_index(touch[i].id);
|
|
||||||
ev->set_pressed(false);
|
|
||||||
ev->set_position(touch[i].pos);
|
|
||||||
Input::get_singleton()->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++) {
|
||||||
|
@ -229,88 +224,118 @@ 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(MouseButton event_buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative) {
|
||||||
// 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.instantiate();
|
||||||
|
_set_key_modifier_state(ev);
|
||||||
|
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);
|
||||||
|
MouseButton changed_button_mask = MouseButton(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);
|
||||||
|
ev->set_double_click(p_double_click);
|
||||||
|
Input::get_singleton()->parse_input_event(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidInputHandler::_release_mouse_event_info(bool p_source_mouse_relative) {
|
||||||
|
_parse_mouse_event_info(MouseButton::NONE, 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, bool p_source_mouse_relative) {
|
||||||
|
MouseButton 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.instantiate();
|
ev.instantiate();
|
||||||
_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::get_singleton()->parse_input_event(ev);
|
Input::get_singleton()->parse_input_event(ev);
|
||||||
hover_prev_pos = p_pos;
|
hover_prev_pos = p_event_pos;
|
||||||
} break;
|
} break;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidInputHandler::process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) {
|
case AMOTION_EVENT_ACTION_DOWN:
|
||||||
MouseButton 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, p_source_mouse_relative);
|
||||||
|
} 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(p_source_mouse_relative);
|
||||||
ev.instantiate();
|
|
||||||
_set_key_modifier_state(ev);
|
|
||||||
if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
|
|
||||||
ev->set_position(event_pos);
|
|
||||||
ev->set_global_position(event_pos);
|
|
||||||
} else {
|
|
||||||
ev->set_position(hover_prev_pos);
|
|
||||||
ev->set_global_position(hover_prev_pos);
|
|
||||||
}
|
|
||||||
ev->set_pressed(event_action == AMOTION_EVENT_ACTION_BUTTON_PRESS);
|
|
||||||
MouseButton changed_button_mask = MouseButton(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::get_singleton()->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.instantiate();
|
ev.instantiate();
|
||||||
_set_key_modifier_state(ev);
|
_set_key_modifier_state(ev);
|
||||||
if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
|
if (p_source_mouse_relative) {
|
||||||
ev->set_position(event_pos);
|
|
||||||
ev->set_global_position(event_pos);
|
|
||||||
ev->set_relative(event_pos - hover_prev_pos);
|
|
||||||
hover_prev_pos = event_pos;
|
|
||||||
} else {
|
|
||||||
ev->set_position(hover_prev_pos);
|
ev->set_position(hover_prev_pos);
|
||||||
ev->set_global_position(hover_prev_pos);
|
ev->set_global_position(hover_prev_pos);
|
||||||
ev->set_relative(event_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);
|
ev->set_button_mask(event_buttons_mask);
|
||||||
Input::get_singleton()->parse_input_event(ev);
|
Input::get_singleton()->parse_input_event(ev);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case AMOTION_EVENT_ACTION_SCROLL: {
|
case AMOTION_EVENT_ACTION_SCROLL: {
|
||||||
Ref<InputEventMouseButton> ev;
|
Ref<InputEventMouseButton> ev;
|
||||||
ev.instantiate();
|
ev.instantiate();
|
||||||
if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
|
_set_key_modifier_state(ev);
|
||||||
ev->set_position(event_pos);
|
if (p_source_mouse_relative) {
|
||||||
ev->set_global_position(event_pos);
|
|
||||||
} else {
|
|
||||||
ev->set_position(hover_prev_pos);
|
ev->set_position(hover_prev_pos);
|
||||||
ev->set_global_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);
|
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, MouseButton::WHEEL_UP, event_vertical_factor);
|
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_UP, p_delta.y);
|
||||||
} else if (event_vertical_factor < 0) {
|
} else if (p_delta.y < 0) {
|
||||||
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_DOWN, -event_vertical_factor);
|
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_DOWN, -p_delta.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event_horizontal_factor > 0) {
|
if (p_delta.x > 0) {
|
||||||
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_RIGHT, event_horizontal_factor);
|
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_RIGHT, p_delta.x);
|
||||||
} else if (event_horizontal_factor < 0) {
|
} else if (p_delta.x < 0) {
|
||||||
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_LEFT, -event_horizontal_factor);
|
_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_LEFT, -p_delta.x);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -329,18 +354,22 @@ void AndroidInputHandler::_wheel_button_click(MouseButton event_buttons_mask, co
|
||||||
Input::get_singleton()->parse_input_event(evdd);
|
Input::get_singleton()->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) {
|
||||||
MouseButton event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask);
|
Ref<InputEventMagnifyGesture> magnify_event;
|
||||||
Ref<InputEventMouseButton> ev;
|
magnify_event.instantiate();
|
||||||
ev.instantiate();
|
_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::get_singleton()->parse_input_event(magnify_event);
|
||||||
ev->set_pressed(event_button_mask != MouseButton::NONE);
|
}
|
||||||
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_double_click(true);
|
Ref<InputEventPanGesture> pan_event;
|
||||||
Input::get_singleton()->parse_input_event(ev);
|
pan_event.instantiate();
|
||||||
|
_set_key_modifier_state(pan_event);
|
||||||
|
pan_event->set_position(p_pos);
|
||||||
|
pan_event->set_delta(p_delta);
|
||||||
|
Input::get_singleton()->parse_input_event(pan_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseButton AndroidInputHandler::_button_index_from_mask(MouseButton button_mask) {
|
MouseButton AndroidInputHandler::_button_index_from_mask(MouseButton button_mask) {
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -68,6 +73,7 @@ private:
|
||||||
MouseButton buttons_state = MouseButton::NONE;
|
MouseButton buttons_state = MouseButton::NONE;
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
void _set_key_modifier_state(Ref<InputEventWithModifiers> ev);
|
void _set_key_modifier_state(Ref<InputEventWithModifiers> ev);
|
||||||
|
@ -77,11 +83,19 @@ private:
|
||||||
|
|
||||||
void _wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor);
|
void _wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor);
|
||||||
|
|
||||||
|
void _parse_mouse_event_info(MouseButton event_buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative);
|
||||||
|
|
||||||
|
void _release_mouse_event_info(bool p_source_mouse_relative = false);
|
||||||
|
|
||||||
|
void _parse_all_touch(bool p_pressed);
|
||||||
|
|
||||||
|
void _release_all_touch();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
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, bool p_source_mouse_relative);
|
||||||
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 input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0);
|
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 process_joy_event(JoypadEvent p_event);
|
void process_joy_event(JoypadEvent p_event);
|
||||||
void process_key_event(int p_keycode, int p_physical_keycode, int p_unicode, bool p_pressed);
|
void process_key_event(int p_keycode, int p_physical_keycode, int p_unicode, bool p_pressed);
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,6 +77,12 @@ open class GodotEditor : FullScreenGodotApp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
// Enable long press, panning and scaling gestures
|
||||||
|
godotFragment?.renderView?.inputHandler?.apply {
|
||||||
|
enableLongPress(enableLongPressGestures())
|
||||||
|
enablePanningAndScalingGestures(enablePanAndScaleGestures())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateCommandLineParams(args: Array<String>?) {
|
private fun updateCommandLineParams(args: Array<String>?) {
|
||||||
|
@ -148,6 +154,16 @@ open class GodotEditor : FullScreenGodotApp() {
|
||||||
*/
|
*/
|
||||||
protected open fun overrideOrientationRequest() = true
|
protected open fun overrideOrientationRequest() = true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable long press gestures for the Godot Android editor.
|
||||||
|
*/
|
||||||
|
protected open fun enableLongPressGestures() = true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable pan and scale gestures for the Godot Android editor.
|
||||||
|
*/
|
||||||
|
protected open fun enablePanAndScaleGestures() = true
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
// Check if we got the MANAGE_EXTERNAL_STORAGE permission
|
// Check if we got the MANAGE_EXTERNAL_STORAGE permission
|
||||||
|
|
|
@ -35,4 +35,8 @@ package org.godotengine.editor
|
||||||
*/
|
*/
|
||||||
class GodotGame : GodotEditor() {
|
class GodotGame : GodotEditor() {
|
||||||
override fun overrideOrientationRequest() = false
|
override fun overrideOrientationRequest() = false
|
||||||
|
|
||||||
|
override fun enableLongPressGestures() = false
|
||||||
|
|
||||||
|
override fun enablePanAndScaleGestures() = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1023,7 +1023,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
private GodotRenderView getRenderView() { // used by native side to get renderView
|
public GodotRenderView getRenderView() { // used by native side to get renderView
|
||||||
return mRenderView;
|
return mRenderView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.gl.GodotRenderer;
|
import org.godotengine.godot.gl.GodotRenderer;
|
||||||
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;
|
||||||
|
@ -46,7 +45,6 @@ import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.GestureDetector;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.PointerIcon;
|
import android.view.PointerIcon;
|
||||||
|
@ -75,7 +73,6 @@ import androidx.annotation.Keep;
|
||||||
public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
|
public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
|
||||||
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 PointerIcon pointerIcon;
|
private PointerIcon pointerIcon;
|
||||||
|
|
||||||
|
@ -85,7 +82,6 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
|
||||||
|
|
||||||
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();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
|
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
|
||||||
|
@ -132,7 +128,6 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
|
||||||
@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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +151,24 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
|
||||||
return inputHandler.onGenericMotionEvent(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 pointer icon
|
* called from JNI to change pointer icon
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class GodotLib {
|
||||||
public static native void newcontext(Surface p_surface);
|
public static native void newcontext(Surface p_surface);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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();
|
||||||
|
|
||||||
|
@ -108,63 +108,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, boolean sourceMouseRelative);
|
||||||
|
|
||||||
|
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_keycode, int p_physical_keycode, int p_unicode, boolean p_pressed);
|
public static native void key(int p_keycode, int p_physical_keycode, 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);
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
|
|
||||||
package org.godotengine.godot;
|
package org.godotengine.godot;
|
||||||
|
|
||||||
import org.godotengine.godot.input.GodotGestureHandler;
|
|
||||||
import org.godotengine.godot.input.GodotInputHandler;
|
import org.godotengine.godot.input.GodotInputHandler;
|
||||||
import org.godotengine.godot.vulkan.VkRenderer;
|
import org.godotengine.godot.vulkan.VkRenderer;
|
||||||
import org.godotengine.godot.vulkan.VkSurfaceView;
|
import org.godotengine.godot.vulkan.VkSurfaceView;
|
||||||
|
@ -38,7 +37,6 @@ import org.godotengine.godot.vulkan.VkSurfaceView;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.GestureDetector;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.PointerIcon;
|
import android.view.PointerIcon;
|
||||||
|
@ -49,7 +47,6 @@ import androidx.annotation.Keep;
|
||||||
public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
||||||
private final Godot godot;
|
private final Godot godot;
|
||||||
private final GodotInputHandler mInputHandler;
|
private final GodotInputHandler mInputHandler;
|
||||||
private final GestureDetector mGestureDetector;
|
|
||||||
private final VkRenderer mRenderer;
|
private final VkRenderer mRenderer;
|
||||||
private PointerIcon pointerIcon;
|
private PointerIcon pointerIcon;
|
||||||
|
|
||||||
|
@ -58,7 +55,6 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
|
||||||
|
|
||||||
this.godot = godot;
|
this.godot = godot;
|
||||||
mInputHandler = new GodotInputHandler(this);
|
mInputHandler = new GodotInputHandler(this);
|
||||||
mGestureDetector = new GestureDetector(context, new GodotGestureHandler(this));
|
|
||||||
mRenderer = new VkRenderer();
|
mRenderer = new VkRenderer();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
|
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
|
||||||
|
@ -106,7 +102,6 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
super.onTouchEvent(event);
|
super.onTouchEvent(event);
|
||||||
mGestureDetector.onTouchEvent(event);
|
|
||||||
return mInputHandler.onTouchEvent(event);
|
return mInputHandler.onTouchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +125,24 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
|
||||||
return mInputHandler.onGenericMotionEvent(event);
|
return mInputHandler.onGenericMotionEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestPointerCapture() {
|
||||||
|
super.requestPointerCapture();
|
||||||
|
mInputHandler.onPointerCaptureChange(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void releasePointerCapture() {
|
||||||
|
super.releasePointerCapture();
|
||||||
|
mInputHandler.onPointerCaptureChange(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPointerCaptureChange(boolean hasCapture) {
|
||||||
|
super.onPointerCaptureChange(hasCapture);
|
||||||
|
mInputHandler.onPointerCaptureChange(hasCapture);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called from JNI to change pointer icon
|
* called from JNI to change pointer icon
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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.GodotRenderView;
|
|
||||||
|
|
||||||
import android.view.GestureDetector;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles gesture input related events for the {@link GodotRenderView} view.
|
|
||||||
* https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener
|
|
||||||
*/
|
|
||||||
public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener {
|
|
||||||
private final GodotRenderView mRenderView;
|
|
||||||
|
|
||||||
public GodotGestureHandler(GodotRenderView godotView) {
|
|
||||||
mRenderView = godotView;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void queueEvent(Runnable task) {
|
|
||||||
mRenderView.queueOnRenderThread(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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,289 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* 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.os.Build
|
||||||
|
import android.view.GestureDetector.SimpleOnGestureListener
|
||||||
|
import android.view.InputDevice
|
||||||
|
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
|
||||||
|
private var pointerCaptureInProgress = 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 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 -> {
|
||||||
|
onActionUp(event)
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_MOVE -> {
|
||||||
|
onActionMove(event)
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onActionUp(event: MotionEvent): Boolean {
|
||||||
|
val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
when {
|
||||||
|
pointerCaptureInProgress -> {
|
||||||
|
return if (event.actionMasked == MotionEvent.ACTION_CANCEL) {
|
||||||
|
// Don't dispatch the ACTION_CANCEL while a capture is in progress
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
GodotInputHandler.handleMouseEvent(
|
||||||
|
MotionEvent.ACTION_UP,
|
||||||
|
event.buttonState,
|
||||||
|
event.x,
|
||||||
|
event.y,
|
||||||
|
0f,
|
||||||
|
0f,
|
||||||
|
false,
|
||||||
|
sourceMouseRelative
|
||||||
|
)
|
||||||
|
pointerCaptureInProgress = false
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dragInProgress -> {
|
||||||
|
GodotInputHandler.handleMotionEvent(event)
|
||||||
|
dragInProgress = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
contextClickInProgress -> {
|
||||||
|
GodotInputHandler.handleMouseEvent(
|
||||||
|
event.actionMasked,
|
||||||
|
0,
|
||||||
|
event.x,
|
||||||
|
event.y,
|
||||||
|
0f,
|
||||||
|
0f,
|
||||||
|
false,
|
||||||
|
sourceMouseRelative
|
||||||
|
)
|
||||||
|
contextClickInProgress = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else -> 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,
|
||||||
|
0f,
|
||||||
|
0f,
|
||||||
|
false,
|
||||||
|
sourceMouseRelative
|
||||||
|
)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 GodotRenderView} view.
|
* Handles input related events for the {@link GodotRenderView} view.
|
||||||
*/
|
*/
|
||||||
public class GodotInputHandler implements InputManager.InputDeviceListener {
|
public class GodotInputHandler implements InputManager.InputDeviceListener {
|
||||||
private final GodotRenderView mRenderView;
|
private static final String TAG = GodotInputHandler.class.getSimpleName();
|
||||||
private final InputManager mInputManager;
|
|
||||||
|
|
||||||
private final String tag = this.getClass().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 GodotRenderView mRenderView;
|
||||||
|
private final InputManager mInputManager;
|
||||||
|
private final GestureDetector gestureDetector;
|
||||||
|
private final ScaleGestureDetector scaleGestureDetector;
|
||||||
|
private final GodotGestureHandler godotGestureHandler;
|
||||||
|
|
||||||
public GodotInputHandler(GodotRenderView godotView) {
|
public GodotInputHandler(GodotRenderView godotView) {
|
||||||
|
final Context context = godotView.getView().getContext();
|
||||||
mRenderView = godotView;
|
mRenderView = godotView;
|
||||||
mInputManager = (InputManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_SERVICE);
|
mInputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE);
|
||||||
mInputManager.registerInputDeviceListener(this, null);
|
mInputManager.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;
|
||||||
|
@ -77,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;
|
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) {
|
public boolean onKeyUp(final int keyCode, KeyEvent event) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -87,7 +119,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) {
|
||||||
|
@ -121,11 +153,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;
|
||||||
|
|
||||||
|
@ -145,47 +176,41 @@ 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 (mRenderView != 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 (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
|
// 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) {
|
||||||
|
@ -198,15 +223,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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,17 +245,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) || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
return handleMouseEvent(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -243,7 +258,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
|
||||||
for (int deviceId : deviceIds) {
|
for (int deviceId : deviceIds) {
|
||||||
InputDevice device = mInputManager.getInputDevice(deviceId);
|
InputDevice device = mInputManager.getInputDevice(deviceId);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.v("GodotInputHandler", 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 +303,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 +320,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 +352,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,39 +417,113 @@ 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());
|
||||||
case MotionEvent.ACTION_HOVER_ENTER:
|
}
|
||||||
case MotionEvent.ACTION_HOVER_MOVE:
|
|
||||||
case MotionEvent.ACTION_HOVER_EXIT: {
|
private static boolean isMouseEvent(int eventSource) {
|
||||||
final float x = event.getX();
|
boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS);
|
||||||
final float y = event.getY();
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
final int type = event.getAction();
|
mouseSource = mouseSource || ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE);
|
||||||
GodotLib.hover(type, x, y);
|
}
|
||||||
return true;
|
return mouseSource;
|
||||||
}
|
}
|
||||||
case MotionEvent.ACTION_BUTTON_PRESS:
|
|
||||||
case MotionEvent.ACTION_BUTTON_RELEASE:
|
static boolean handleMotionEvent(final MotionEvent event) {
|
||||||
case MotionEvent.ACTION_MOVE: {
|
if (isMouseEvent(event)) {
|
||||||
final float x = event.getX();
|
return handleMouseEvent(event);
|
||||||
final float y = event.getY();
|
}
|
||||||
final int buttonsMask = event.getButtonState();
|
|
||||||
final int action = event.getAction();
|
return handleTouchEvent(event);
|
||||||
GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask);
|
}
|
||||||
return true;
|
|
||||||
}
|
static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) {
|
||||||
case MotionEvent.ACTION_SCROLL: {
|
return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0);
|
||||||
final float x = event.getX();
|
}
|
||||||
final float y = event.getY();
|
|
||||||
final int buttonsMask = event.getButtonState();
|
static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY) {
|
||||||
final int action = event.getAction();
|
if (isMouseEvent(eventSource)) {
|
||||||
final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
|
return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, false, false);
|
||||||
final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
|
}
|
||||||
GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor);
|
|
||||||
}
|
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);
|
||||||
|
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, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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_DOWN:
|
||||||
case MotionEvent.ACTION_UP: {
|
case MotionEvent.ACTION_HOVER_ENTER:
|
||||||
// we can safely ignore these cases because they are always come beside ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE
|
case MotionEvent.ACTION_HOVER_EXIT:
|
||||||
|
case MotionEvent.ACTION_HOVER_MOVE:
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
case MotionEvent.ACTION_SCROLL: {
|
||||||
|
GodotLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,7 +254,17 @@ 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, jboolean p_source_mouse_relative) {
|
||||||
|
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, p_source_mouse_relative);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
@ -262,50 +272,30 @@ void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev,
|
||||||
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_device & AINPUT_SOURCE_MOUSE_RELATIVE) == AINPUT_SOURCE_MOUSE_RELATIVE) {
|
|
||||||
input_handler->process_mouse_event(input_device, ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor);
|
input_handler->process_touch_event(ev, pointer, points);
|
||||||
} 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_magnify(Point2(p_x, p_y), p_factor);
|
||||||
input_handler->process_hover(p_type, Point2(p_x, p_y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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_pan(Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y));
|
||||||
input_handler->process_double_tap(p_button_mask, Point2(p_x, p_y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called on the UI thread
|
// Called on the UI thread
|
||||||
|
|
|
@ -45,12 +45,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
|
||||||
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_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 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, jboolean p_source_mouse_relative);
|
||||||
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_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed);
|
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, 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);
|
||||||
|
|
Loading…
Reference in New Issue