diff options
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/SCsub | 1 | ||||
-rw-r--r-- | platform/android/android_input_handler.cpp | 395 | ||||
-rw-r--r-- | platform/android/android_input_handler.h | 91 | ||||
-rw-r--r-- | platform/android/display_server_android.cpp | 377 | ||||
-rw-r--r-- | platform/android/display_server_android.h | 52 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java | 4 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java | 53 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java | 48 | ||||
-rw-r--r-- | platform/android/java_godot_lib_jni.cpp | 99 | ||||
-rw-r--r-- | platform/android/os_android.cpp | 4 | ||||
-rw-r--r-- | platform/android/os_android.h | 1 |
11 files changed, 604 insertions, 521 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub index 56fbd2f7e4..ecc72019e5 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -4,6 +4,7 @@ Import("env") android_files = [ "os_android.cpp", + "android_input_handler.cpp", "file_access_android.cpp", "audio_driver_opensl.cpp", "dir_access_jandroid.cpp", diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp new file mode 100644 index 0000000000..b9004c4989 --- /dev/null +++ b/platform/android/android_input_handler.cpp @@ -0,0 +1,395 @@ +/*************************************************************************/ +/* android_input_handler.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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. */ +/*************************************************************************/ + +#include "android_input_handler.h" + +#include "android_keys_utils.h" +#include "display_server_android.h" + +void AndroidInputHandler::process_joy_event(AndroidInputHandler::JoypadEvent p_event) { + switch (p_event.type) { + case JOY_EVENT_BUTTON: + Input::get_singleton()->joy_button(p_event.device, (JoyButton)p_event.index, p_event.pressed); + break; + case JOY_EVENT_AXIS: + Input::JoyAxisValue value; + value.min = -1; + value.value = p_event.value; + Input::get_singleton()->joy_axis(p_event.device, (JoyAxis)p_event.index, value); + break; + case JOY_EVENT_HAT: + Input::get_singleton()->joy_hat(p_event.device, (HatMask)p_event.hat); + break; + default: + return; + } +} + +void AndroidInputHandler::_set_key_modifier_state(Ref<InputEventWithModifiers> ev) { + ev->set_shift_pressed(shift_mem); + ev->set_alt_pressed(alt_mem); + ev->set_meta_pressed(meta_mem); + ev->set_ctrl_pressed(control_mem); +} + +void AndroidInputHandler::process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed) { + static char32_t prev_wc = 0; + char32_t unicode = p_unicode_char; + if ((p_unicode_char & 0xfffffc00) == 0xd800) { + if (prev_wc != 0) { + ERR_PRINT("invalid utf16 surrogate input"); + } + prev_wc = unicode; + return; // Skip surrogate. + } else if ((unicode & 0xfffffc00) == 0xdc00) { + if (prev_wc == 0) { + ERR_PRINT("invalid utf16 surrogate input"); + return; // Skip invalid surrogate. + } + unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000); + prev_wc = 0; + } else { + prev_wc = 0; + } + + Ref<InputEventKey> ev; + ev.instantiate(); + int val = unicode; + int keycode = android_get_keysym(p_keycode); + int phy_keycode = android_get_keysym(p_scancode); + + if (keycode == KEY_SHIFT) { + shift_mem = p_pressed; + } + if (keycode == KEY_ALT) { + alt_mem = p_pressed; + } + if (keycode == KEY_CTRL) { + control_mem = p_pressed; + } + if (keycode == KEY_META) { + meta_mem = p_pressed; + } + + ev->set_keycode((Key)keycode); + ev->set_physical_keycode((Key)phy_keycode); + ev->set_unicode(val); + ev->set_pressed(p_pressed); + + _set_key_modifier_state(ev); + + if (val == '\n') { + ev->set_keycode(KEY_ENTER); + } else if (val == 61448) { + ev->set_keycode(KEY_BACKSPACE); + ev->set_unicode(KEY_BACKSPACE); + } else if (val == 61453) { + ev->set_keycode(KEY_ENTER); + ev->set_unicode(KEY_ENTER); + } else if (p_keycode == 4) { + if (DisplayServerAndroid *dsa = Object::cast_to<DisplayServerAndroid>(DisplayServer::get_singleton())) { + dsa->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST, true); + } + } + + Input::get_singleton()->parse_input_event(ev); +} + +void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector<AndroidInputHandler::TouchPos> &p_points) { + switch (p_event) { + case AMOTION_EVENT_ACTION_DOWN: { //gesture begin + 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(false); + ev->set_position(touch[i].pos); + Input::get_singleton()->parse_input_event(ev); + } + } + + touch.resize(p_points.size()); + for (int i = 0; i < p_points.size(); i++) { + touch.write[i].id = p_points[i].id; + touch.write[i].pos = p_points[i].pos; + } + + //send touch + for (int i = 0; i < touch.size(); i++) { + 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; + case AMOTION_EVENT_ACTION_MOVE: { //motion + ERR_FAIL_COND(touch.size() != p_points.size()); + + for (int i = 0; i < touch.size(); i++) { + int idx = -1; + for (int j = 0; j < p_points.size(); j++) { + if (touch[i].id == p_points[j].id) { + idx = j; + break; + } + } + + ERR_CONTINUE(idx == -1); + + if (touch[i].pos == p_points[idx].pos) + continue; //no move unncesearily + + Ref<InputEventScreenDrag> ev; + ev.instantiate(); + ev->set_index(touch[i].id); + ev->set_position(p_points[idx].pos); + ev->set_relative(p_points[idx].pos - touch[i].pos); + Input::get_singleton()->parse_input_event(ev); + touch.write[i].pos = p_points[idx].pos; + } + + } break; + case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_UP: { //release + 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(false); + ev->set_position(touch[i].pos); + Input::get_singleton()->parse_input_event(ev); + } + touch.clear(); + } + } break; + case AMOTION_EVENT_ACTION_POINTER_DOWN: { // add touch + for (int i = 0; i < p_points.size(); i++) { + if (p_points[i].id == p_pointer) { + TouchPos tp = p_points[i]; + touch.push_back(tp); + + Ref<InputEventScreenTouch> ev; + ev.instantiate(); + + ev->set_index(tp.id); + ev->set_pressed(true); + ev->set_position(tp.pos); + Input::get_singleton()->parse_input_event(ev); + + break; + } + } + } break; + case AMOTION_EVENT_ACTION_POINTER_UP: { // remove touch + for (int i = 0; i < touch.size(); i++) { + if (touch[i].id == p_pointer) { + 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.remove(i); + + break; + } + } + } break; + } +} + +void AndroidInputHandler::process_hover(int p_type, Point2 p_pos) { + // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER + switch (p_type) { + case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move + case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter + case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit + Ref<InputEventMouseMotion> ev; + ev.instantiate(); + _set_key_modifier_state(ev); + ev->set_position(p_pos); + ev->set_global_position(p_pos); + ev->set_relative(p_pos - hover_prev_pos); + Input::get_singleton()->parse_input_event(ev); + hover_prev_pos = p_pos; + } 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) { + MouseButton event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask); + switch (event_action) { + case AMOTION_EVENT_ACTION_BUTTON_PRESS: + case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { + Ref<InputEventMouseButton> ev; + 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; + + case AMOTION_EVENT_ACTION_MOVE: { + Ref<InputEventMouseMotion> ev; + 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); + ev->set_relative(event_pos - hover_prev_pos); + hover_prev_pos = event_pos; + } else { + ev->set_position(hover_prev_pos); + ev->set_global_position(hover_prev_pos); + ev->set_relative(event_pos); + } + ev->set_button_mask(event_buttons_mask); + Input::get_singleton()->parse_input_event(ev); + } break; + case AMOTION_EVENT_ACTION_SCROLL: { + Ref<InputEventMouseButton> ev; + ev.instantiate(); + 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(true); + buttons_state = event_buttons_mask; + if (event_vertical_factor > 0) { + _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_UP, event_vertical_factor); + } else if (event_vertical_factor < 0) { + _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_DOWN, -event_vertical_factor); + } + + if (event_horizontal_factor > 0) { + _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_RIGHT, event_horizontal_factor); + } else if (event_horizontal_factor < 0) { + _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_LEFT, -event_horizontal_factor); + } + } break; + } +} + +void AndroidInputHandler::_wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor) { + Ref<InputEventMouseButton> evd = ev->duplicate(); + _set_key_modifier_state(evd); + evd->set_button_index(wheel_button); + evd->set_button_mask(MouseButton(event_buttons_mask ^ (1 << (wheel_button - 1)))); + evd->set_factor(factor); + Input::get_singleton()->parse_input_event(evd); + Ref<InputEventMouseButton> evdd = evd->duplicate(); + evdd->set_pressed(false); + evdd->set_button_mask(event_buttons_mask); + Input::get_singleton()->parse_input_event(evdd); +} + +void AndroidInputHandler::process_double_tap(int event_android_button_mask, Point2 p_pos) { + MouseButton event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask); + Ref<InputEventMouseButton> ev; + ev.instantiate(); + _set_key_modifier_state(ev); + ev->set_position(p_pos); + ev->set_global_position(p_pos); + 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); + ev->set_double_click(true); + Input::get_singleton()->parse_input_event(ev); +} + +MouseButton AndroidInputHandler::_button_index_from_mask(MouseButton button_mask) { + switch (button_mask) { + case MOUSE_BUTTON_MASK_LEFT: + return MOUSE_BUTTON_LEFT; + case MOUSE_BUTTON_MASK_RIGHT: + return MOUSE_BUTTON_RIGHT; + case MOUSE_BUTTON_MASK_MIDDLE: + return MOUSE_BUTTON_MIDDLE; + case MOUSE_BUTTON_MASK_XBUTTON1: + return MOUSE_BUTTON_XBUTTON1; + case MOUSE_BUTTON_MASK_XBUTTON2: + return MOUSE_BUTTON_XBUTTON2; + default: + return MOUSE_BUTTON_NONE; + } +} + +MouseButton AndroidInputHandler::_android_button_mask_to_godot_button_mask(int android_button_mask) { + MouseButton godot_button_mask = MOUSE_BUTTON_NONE; + if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) { + godot_button_mask |= MOUSE_BUTTON_MASK_LEFT; + } + if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) { + godot_button_mask |= MOUSE_BUTTON_MASK_RIGHT; + } + if (android_button_mask & AMOTION_EVENT_BUTTON_TERTIARY) { + godot_button_mask |= MOUSE_BUTTON_MASK_MIDDLE; + } + if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) { + godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON1; + } + if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) { + godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON2; + } + + return godot_button_mask; +} + +void AndroidInputHandler::process_scroll(Point2 p_pos) { + Ref<InputEventPanGesture> ev; + ev.instantiate(); + _set_key_modifier_state(ev); + ev->set_position(p_pos); + ev->set_delta(p_pos - scroll_prev_pos); + Input::get_singleton()->parse_input_event(ev); + scroll_prev_pos = p_pos; +} diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h new file mode 100644 index 0000000000..2918ca300b --- /dev/null +++ b/platform/android/android_input_handler.h @@ -0,0 +1,91 @@ +/*************************************************************************/ +/* android_input_handler.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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. */ +/*************************************************************************/ + +#ifndef ANDROID_INPUT_HANDLER_H +#define ANDROID_INPUT_HANDLER_H + +#include "core/input/input.h" + +// This class encapsulates all the handling of input events that come from the Android UI thread. +// Remarks: +// - It's not thread-safe by itself, so its functions must only be called on a single thread, which is the Android UI thread. +// - Its functions must only call thread-safe methods. +class AndroidInputHandler { +public: + struct TouchPos { + int id = 0; + Point2 pos; + }; + + enum { + JOY_EVENT_BUTTON = 0, + JOY_EVENT_AXIS = 1, + JOY_EVENT_HAT = 2 + }; + + struct JoypadEvent { + int device = 0; + int type = 0; + int index = 0; + bool pressed = false; + float value = 0; + int hat = 0; + }; + +private: + bool alt_mem = false; + bool shift_mem = false; + bool control_mem = false; + bool meta_mem = false; + + MouseButton buttons_state = MOUSE_BUTTON_NONE; + + Vector<TouchPos> touch; + Point2 hover_prev_pos; // needed to calculate the relative position on hover events + Point2 scroll_prev_pos; // needed to calculate the relative position on scroll events + + void _set_key_modifier_state(Ref<InputEventWithModifiers> ev); + + static MouseButton _button_index_from_mask(MouseButton button_mask); + static MouseButton _android_button_mask_to_godot_button_mask(int android_button_mask); + + void _wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor); + +public: + void process_touch(int p_event, int p_pointer, const Vector<TouchPos> &p_points); + void process_hover(int p_type, Point2 p_pos); + 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_double_tap(int event_android_button_mask, Point2 p_pos); + void process_scroll(Point2 p_pos); + void process_joy_event(JoypadEvent p_event); + void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); +}; + +#endif diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 7be4235876..720752d28f 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -30,7 +30,6 @@ #include "display_server_android.h" -#include "android_keys_utils.h" #include "core/config/project_settings.h" #include "java_godot_io_wrapper.h" #include "java_godot_wrapper.h" @@ -203,17 +202,21 @@ void DisplayServerAndroid::window_set_drop_files_callback(const Callable &p_call // Not supported on Android. } -void DisplayServerAndroid::_window_callback(const Callable &p_callable, const Variant &p_arg) const { +void DisplayServerAndroid::_window_callback(const Callable &p_callable, const Variant &p_arg, bool p_deferred) const { if (!p_callable.is_null()) { const Variant *argp = &p_arg; Variant ret; Callable::CallError ce; - p_callable.call((const Variant **)&argp, 1, ret, ce); + if (p_deferred) { + p_callable.call((const Variant **)&argp, 1, ret, ce); + } else { + p_callable.call_deferred((const Variant **)&argp, 1); + } } } -void DisplayServerAndroid::send_window_event(DisplayServer::WindowEvent p_event) const { - _window_callback(window_event_callback, int(p_event)); +void DisplayServerAndroid::send_window_event(DisplayServer::WindowEvent p_event, bool p_deferred) const { + _window_callback(window_event_callback, int(p_event), p_deferred); } void DisplayServerAndroid::send_input_event(const Ref<InputEvent> &p_event) const { @@ -454,6 +457,7 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis #endif Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); + Input::get_singleton()->set_use_input_buffering(true); // Needed because events will come directly from the UI thread r_error = OK; } @@ -473,344 +477,6 @@ DisplayServerAndroid::~DisplayServerAndroid() { #endif } -void DisplayServerAndroid::process_joy_event(DisplayServerAndroid::JoypadEvent p_event) { - switch (p_event.type) { - case JOY_EVENT_BUTTON: - Input::get_singleton()->joy_button(p_event.device, (JoyButton)p_event.index, p_event.pressed); - break; - case JOY_EVENT_AXIS: - Input::JoyAxisValue value; - value.min = -1; - value.value = p_event.value; - Input::get_singleton()->joy_axis(p_event.device, (JoyAxis)p_event.index, value); - break; - case JOY_EVENT_HAT: - Input::get_singleton()->joy_hat(p_event.device, (HatMask)p_event.hat); - break; - default: - return; - } -} - -void DisplayServerAndroid::_set_key_modifier_state(Ref<InputEventWithModifiers> ev) { - ev->set_shift_pressed(shift_mem); - ev->set_alt_pressed(alt_mem); - ev->set_meta_pressed(meta_mem); - ev->set_ctrl_pressed(control_mem); -} - -void DisplayServerAndroid::process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed) { - static char32_t prev_wc = 0; - char32_t unicode = p_unicode_char; - if ((p_unicode_char & 0xfffffc00) == 0xd800) { - if (prev_wc != 0) { - ERR_PRINT("invalid utf16 surrogate input"); - } - prev_wc = unicode; - return; // Skip surrogate. - } else if ((unicode & 0xfffffc00) == 0xdc00) { - if (prev_wc == 0) { - ERR_PRINT("invalid utf16 surrogate input"); - return; // Skip invalid surrogate. - } - unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000); - prev_wc = 0; - } else { - prev_wc = 0; - } - - Ref<InputEventKey> ev; - ev.instantiate(); - int val = unicode; - int keycode = android_get_keysym(p_keycode); - int phy_keycode = android_get_keysym(p_scancode); - - if (keycode == KEY_SHIFT) { - shift_mem = p_pressed; - } - if (keycode == KEY_ALT) { - alt_mem = p_pressed; - } - if (keycode == KEY_CTRL) { - control_mem = p_pressed; - } - if (keycode == KEY_META) { - meta_mem = p_pressed; - } - - ev->set_keycode((Key)keycode); - ev->set_physical_keycode((Key)phy_keycode); - ev->set_unicode(val); - ev->set_pressed(p_pressed); - - _set_key_modifier_state(ev); - - if (val == '\n') { - ev->set_keycode(KEY_ENTER); - } else if (val == 61448) { - ev->set_keycode(KEY_BACKSPACE); - ev->set_unicode(KEY_BACKSPACE); - } else if (val == 61453) { - ev->set_keycode(KEY_ENTER); - ev->set_unicode(KEY_ENTER); - } else if (p_keycode == 4) { - OS_Android::get_singleton()->main_loop_request_go_back(); - } - - Input::get_singleton()->parse_input_event(ev); -} - -void DisplayServerAndroid::process_touch(int p_event, int p_pointer, const Vector<DisplayServerAndroid::TouchPos> &p_points) { - switch (p_event) { - case AMOTION_EVENT_ACTION_DOWN: { //gesture begin - 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(false); - ev->set_position(touch[i].pos); - Input::get_singleton()->parse_input_event(ev); - } - } - - touch.resize(p_points.size()); - for (int i = 0; i < p_points.size(); i++) { - touch.write[i].id = p_points[i].id; - touch.write[i].pos = p_points[i].pos; - } - - //send touch - for (int i = 0; i < touch.size(); i++) { - 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; - case AMOTION_EVENT_ACTION_MOVE: { //motion - ERR_FAIL_COND(touch.size() != p_points.size()); - - for (int i = 0; i < touch.size(); i++) { - int idx = -1; - for (int j = 0; j < p_points.size(); j++) { - if (touch[i].id == p_points[j].id) { - idx = j; - break; - } - } - - ERR_CONTINUE(idx == -1); - - if (touch[i].pos == p_points[idx].pos) - continue; //no move unncesearily - - Ref<InputEventScreenDrag> ev; - ev.instantiate(); - ev->set_index(touch[i].id); - ev->set_position(p_points[idx].pos); - ev->set_relative(p_points[idx].pos - touch[i].pos); - Input::get_singleton()->parse_input_event(ev); - touch.write[i].pos = p_points[idx].pos; - } - - } break; - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_UP: { //release - 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(false); - ev->set_position(touch[i].pos); - Input::get_singleton()->parse_input_event(ev); - } - touch.clear(); - } - } break; - case AMOTION_EVENT_ACTION_POINTER_DOWN: { // add touch - for (int i = 0; i < p_points.size(); i++) { - if (p_points[i].id == p_pointer) { - TouchPos tp = p_points[i]; - touch.push_back(tp); - - Ref<InputEventScreenTouch> ev; - ev.instantiate(); - - ev->set_index(tp.id); - ev->set_pressed(true); - ev->set_position(tp.pos); - Input::get_singleton()->parse_input_event(ev); - - break; - } - } - } break; - case AMOTION_EVENT_ACTION_POINTER_UP: { // remove touch - for (int i = 0; i < touch.size(); i++) { - if (touch[i].id == p_pointer) { - 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.remove(i); - - break; - } - } - } break; - } -} - -void DisplayServerAndroid::process_hover(int p_type, Point2 p_pos) { - // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER - switch (p_type) { - case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move - case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter - case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit - Ref<InputEventMouseMotion> ev; - ev.instantiate(); - _set_key_modifier_state(ev); - ev->set_position(p_pos); - ev->set_global_position(p_pos); - ev->set_relative(p_pos - hover_prev_pos); - Input::get_singleton()->parse_input_event(ev); - hover_prev_pos = p_pos; - } break; - } -} - -void DisplayServerAndroid::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) { - MouseButton event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask); - switch (event_action) { - case AMOTION_EVENT_ACTION_BUTTON_PRESS: - case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { - Ref<InputEventMouseButton> ev; - 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; - - case AMOTION_EVENT_ACTION_MOVE: { - Ref<InputEventMouseMotion> ev; - 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); - ev->set_relative(event_pos - hover_prev_pos); - hover_prev_pos = event_pos; - } else { - ev->set_position(hover_prev_pos); - ev->set_global_position(hover_prev_pos); - ev->set_relative(event_pos); - } - ev->set_button_mask(event_buttons_mask); - Input::get_singleton()->parse_input_event(ev); - } break; - case AMOTION_EVENT_ACTION_SCROLL: { - Ref<InputEventMouseButton> ev; - ev.instantiate(); - 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(true); - buttons_state = event_buttons_mask; - if (event_vertical_factor > 0) { - _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_UP, event_vertical_factor); - } else if (event_vertical_factor < 0) { - _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_DOWN, -event_vertical_factor); - } - - if (event_horizontal_factor > 0) { - _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_RIGHT, event_horizontal_factor); - } else if (event_horizontal_factor < 0) { - _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_LEFT, -event_horizontal_factor); - } - } break; - } -} - -void DisplayServerAndroid::_wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor) { - Ref<InputEventMouseButton> evd = ev->duplicate(); - _set_key_modifier_state(evd); - evd->set_button_index(wheel_button); - evd->set_button_mask(MouseButton(event_buttons_mask ^ (1 << (wheel_button - 1)))); - evd->set_factor(factor); - Input::get_singleton()->parse_input_event(evd); - Ref<InputEventMouseButton> evdd = evd->duplicate(); - evdd->set_pressed(false); - evdd->set_button_mask(event_buttons_mask); - Input::get_singleton()->parse_input_event(evdd); -} - -void DisplayServerAndroid::process_double_tap(int event_android_button_mask, Point2 p_pos) { - MouseButton event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask); - Ref<InputEventMouseButton> ev; - ev.instantiate(); - _set_key_modifier_state(ev); - ev->set_position(p_pos); - ev->set_global_position(p_pos); - 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); - ev->set_double_click(true); - Input::get_singleton()->parse_input_event(ev); -} - -MouseButton DisplayServerAndroid::_button_index_from_mask(MouseButton button_mask) { - switch (button_mask) { - case MOUSE_BUTTON_MASK_LEFT: - return MOUSE_BUTTON_LEFT; - case MOUSE_BUTTON_MASK_RIGHT: - return MOUSE_BUTTON_RIGHT; - case MOUSE_BUTTON_MASK_MIDDLE: - return MOUSE_BUTTON_MIDDLE; - case MOUSE_BUTTON_MASK_XBUTTON1: - return MOUSE_BUTTON_XBUTTON1; - case MOUSE_BUTTON_MASK_XBUTTON2: - return MOUSE_BUTTON_XBUTTON2; - default: - return MOUSE_BUTTON_NONE; - } -} - -void DisplayServerAndroid::process_scroll(Point2 p_pos) { - Ref<InputEventPanGesture> ev; - ev.instantiate(); - _set_key_modifier_state(ev); - ev->set_position(p_pos); - ev->set_delta(p_pos - scroll_prev_pos); - Input::get_singleton()->parse_input_event(ev); - scroll_prev_pos = p_pos; -} - void DisplayServerAndroid::process_accelerometer(const Vector3 &p_accelerometer) { Input::get_singleton()->set_accelerometer(p_accelerometer); } @@ -852,32 +518,11 @@ DisplayServer::MouseMode DisplayServerAndroid::mouse_get_mode() const { } Point2i DisplayServerAndroid::mouse_get_position() const { - return hover_prev_pos; + return Input::get_singleton()->get_mouse_position(); } MouseButton DisplayServerAndroid::mouse_get_button_state() const { - return buttons_state; -} - -MouseButton DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_button_mask) { - MouseButton godot_button_mask = MOUSE_BUTTON_NONE; - if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) { - godot_button_mask |= MOUSE_BUTTON_MASK_LEFT; - } - if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) { - godot_button_mask |= MOUSE_BUTTON_MASK_RIGHT; - } - if (android_button_mask & AMOTION_EVENT_BUTTON_TERTIARY) { - godot_button_mask |= MOUSE_BUTTON_MASK_MIDDLE; - } - if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) { - godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON1; - } - if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) { - godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON2; - } - - return godot_button_mask; + return (MouseButton)Input::get_singleton()->get_mouse_button_mask(); } void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) { diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index 9b9f5e99f6..669a1c80e4 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -39,37 +39,8 @@ class RenderingDeviceVulkan; #endif class DisplayServerAndroid : public DisplayServer { -public: - struct TouchPos { - int id = 0; - Point2 pos; - }; - - enum { - JOY_EVENT_BUTTON = 0, - JOY_EVENT_AXIS = 1, - JOY_EVENT_HAT = 2 - }; - - struct JoypadEvent { - int device = 0; - int type = 0; - int index = 0; - bool pressed = false; - float value = 0; - int hat = 0; - }; - -private: String rendering_driver; - bool alt_mem = false; - bool shift_mem = false; - bool control_mem = false; - bool meta_mem = false; - - MouseButton buttons_state = MOUSE_BUTTON_NONE; - // https://developer.android.com/reference/android/view/PointerIcon // mapping between Godot's cursor shape to Android's' int android_cursors[CURSOR_MAX] = { @@ -96,10 +67,6 @@ private: bool keep_screen_on; - Vector<TouchPos> touch; - Point2 hover_prev_pos; // needed to calculate the relative position on hover events - Point2 scroll_prev_pos; // needed to calculate the relative position on scroll events - CursorShape cursor_shape = CursorShape::CURSOR_ARROW; #if defined(VULKAN_ENABLED) @@ -114,18 +81,10 @@ private: Callable input_text_callback; Callable rect_changed_callback; - void _window_callback(const Callable &p_callable, const Variant &p_arg) const; + void _window_callback(const Callable &p_callable, const Variant &p_arg, bool p_deferred = false) const; static void _dispatch_input_events(const Ref<InputEvent> &p_event); - void _set_key_modifier_state(Ref<InputEventWithModifiers> ev); - - static MouseButton _button_index_from_mask(MouseButton button_mask); - - static MouseButton _android_button_mask_to_godot_button_mask(int android_button_mask); - - void _wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor); - public: static DisplayServerAndroid *get_singleton(); @@ -158,7 +117,7 @@ public: virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; - void send_window_event(WindowEvent p_event) const; + void send_window_event(WindowEvent p_event, bool p_deferred = false) const; void send_input_event(const Ref<InputEvent> &p_event) const; void send_input_text(const String &p_text) const; @@ -210,13 +169,6 @@ public: void process_gravity(const Vector3 &p_gravity); void process_magnetometer(const Vector3 &p_magnetometer); void process_gyroscope(const Vector3 &p_gyroscope); - void process_touch(int p_event, int p_pointer, const Vector<TouchPos> &p_points); - void process_hover(int p_type, Point2 p_pos); - 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_double_tap(int event_android_button_mask, Point2 p_pos); - void process_scroll(Point2 p_pos); - void process_joy_event(JoypadEvent p_event); - void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java index 1d60c21c60..6b248fd034 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java @@ -75,7 +75,7 @@ public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener final int x = Math.round(event.getX()); final int y = Math.round(event.getY()); final int buttonMask = event.getButtonState(); - queueEvent(() -> GodotLib.doubleTap(buttonMask, x, y)); + GodotLib.doubleTap(buttonMask, x, y); return true; } @@ -84,7 +84,7 @@ public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener //Log.i("GodotGesture", "onScroll"); final int x = Math.round(distanceX); final int y = Math.round(distanceY); - queueEvent(() -> GodotLib.scroll(x, y)); + GodotLib.scroll(x, y); return true; } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java index 4dc9157545..fc0b84b392 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java @@ -68,10 +68,6 @@ public class GodotInputHandler implements InputDeviceListener { mInputManager.registerInputDeviceListener(this, null); } - private void queueEvent(Runnable task) { - mRenderView.queueOnRenderThread(task); - } - private boolean isKeyEvent_GameDevice(int source) { // Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD) if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD)) @@ -96,13 +92,12 @@ public class GodotInputHandler implements InputDeviceListener { if (mJoystickIds.indexOfKey(deviceId) >= 0) { final int button = getGodotButton(keyCode); final int godotJoyId = mJoystickIds.get(deviceId); - - queueEvent(() -> GodotLib.joybutton(godotJoyId, button, false)); + GodotLib.joybutton(godotJoyId, button, false); } } else { final int scanCode = event.getScanCode(); final int chr = event.getUnicodeChar(0); - queueEvent(() -> GodotLib.key(keyCode, scanCode, chr, false)); + GodotLib.key(keyCode, scanCode, chr, false); } return true; @@ -132,13 +127,12 @@ public class GodotInputHandler implements InputDeviceListener { if (mJoystickIds.indexOfKey(deviceId) >= 0) { final int button = getGodotButton(keyCode); final int godotJoyId = mJoystickIds.get(deviceId); - - queueEvent(() -> GodotLib.joybutton(godotJoyId, button, true)); + GodotLib.joybutton(godotJoyId, button, true); } } else { final int scanCode = event.getScanCode(); final int chr = event.getUnicodeChar(0); - queueEvent(() -> GodotLib.key(keyCode, scanCode, chr, true)); + GodotLib.key(keyCode, scanCode, chr, true); } return true; @@ -170,18 +164,16 @@ public class GodotInputHandler implements InputDeviceListener { final int action = event.getActionMasked(); final int pointer_idx = event.getPointerId(event.getActionIndex()); - mRenderView.queueOnRenderThread(() -> { - 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; - } - }); + 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; } @@ -205,7 +197,7 @@ public class GodotInputHandler implements InputDeviceListener { // save value to prevent repeats joystick.axesValues.put(axis, value); final int godotAxisIdx = i; - queueEvent(() -> GodotLib.joyaxis(godotJoyId, godotAxisIdx, value)); + GodotLib.joyaxis(godotJoyId, godotAxisIdx, value); } } @@ -215,7 +207,7 @@ public class GodotInputHandler implements InputDeviceListener { if (joystick.hatX != hatX || joystick.hatY != hatY) { joystick.hatX = hatX; joystick.hatY = hatY; - queueEvent(() -> GodotLib.joyhat(godotJoyId, hatX, hatY)); + GodotLib.joyhat(godotJoyId, hatX, hatY); } } return true; @@ -224,7 +216,7 @@ public class GodotInputHandler implements InputDeviceListener { final float x = event.getX(); final float y = event.getY(); final int type = event.getAction(); - queueEvent(() -> GodotLib.hover(type, x, y)); + GodotLib.hover(type, x, y); return true; } else if (event.isFromSource(InputDevice.SOURCE_MOUSE) || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) { @@ -316,7 +308,7 @@ public class GodotInputHandler implements InputDeviceListener { } mJoysticksDevices.put(deviceId, joystick); - queueEvent(() -> GodotLib.joyconnectionchanged(id, true, joystick.name)); + GodotLib.joyconnectionchanged(id, true, joystick.name); } @Override @@ -328,8 +320,7 @@ public class GodotInputHandler implements InputDeviceListener { final int godotJoyId = mJoystickIds.get(deviceId); mJoystickIds.delete(deviceId); mJoysticksDevices.delete(deviceId); - - queueEvent(() -> GodotLib.joyconnectionchanged(godotJoyId, false, "")); + GodotLib.joyconnectionchanged(godotJoyId, false, ""); } @Override @@ -418,7 +409,7 @@ public class GodotInputHandler implements InputDeviceListener { final float x = event.getX(); final float y = event.getY(); final int type = event.getAction(); - queueEvent(() -> GodotLib.hover(type, x, y)); + GodotLib.hover(type, x, y); return true; } case MotionEvent.ACTION_BUTTON_PRESS: @@ -428,7 +419,7 @@ public class GodotInputHandler implements InputDeviceListener { final float y = event.getY(); final int buttonsMask = event.getButtonState(); final int action = event.getAction(); - queueEvent(() -> GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask)); + GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask); return true; } case MotionEvent.ACTION_SCROLL: { @@ -438,7 +429,7 @@ public class GodotInputHandler implements InputDeviceListener { final int action = event.getAction(); final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL); final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL); - queueEvent(() -> GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor)); + GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor); } case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_UP: { diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java index 020870a110..002a75277d 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -94,17 +94,15 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) { //Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after); - mRenderView.queueOnRenderThread(() -> { - for (int i = 0; i < count; ++i) { - GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true); - GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false); - - if (mHasSelection) { - mHasSelection = false; - break; - } + for (int i = 0; i < count; ++i) { + GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true); + GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false); + + if (mHasSelection) { + mHasSelection = false; + break; } - }); + } } @Override @@ -115,17 +113,15 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene for (int i = start; i < start + count; ++i) { newChars[i - start] = pCharSequence.charAt(i); } - mRenderView.queueOnRenderThread(() -> { - for (int i = 0; i < count; ++i) { - int key = newChars[i]; - if ((key == '\n') && !mEdit.isMultiline()) { - // Return keys are handled through action events - continue; - } - GodotLib.key(0, 0, key, true); - GodotLib.key(0, 0, key, false); + for (int i = 0; i < count; ++i) { + int key = newChars[i]; + if ((key == '\n') && !mEdit.isMultiline()) { + // Return keys are handled through action events + continue; } - }); + GodotLib.key(0, 0, key, true); + GodotLib.key(0, 0, key, false); + } } @Override @@ -133,13 +129,11 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene if (mEdit == pTextView && isFullScreenEdit()) { final String characters = pKeyEvent.getCharacters(); - mRenderView.queueOnRenderThread(() -> { - for (int i = 0; i < characters.length(); i++) { - final int ch = characters.codePointAt(i); - GodotLib.key(0, 0, ch, true); - GodotLib.key(0, 0, ch, false); - } - }); + for (int i = 0; i < characters.length(); i++) { + final int ch = characters.codePointAt(i); + GodotLib.key(0, 0, ch, true); + GodotLib.key(0, 0, ch, false); + } } if (pActionID == EditorInfo.IME_ACTION_DONE) { diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index ce7a49e53c..d971727269 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -34,6 +34,7 @@ #include "java_godot_wrapper.h" #include "android/asset_manager_jni.h" +#include "android_input_handler.h" #include "api/java_class_wrapper.h" #include "api/jni_singleton.h" #include "core/config/engine.h" @@ -56,11 +57,12 @@ static JavaClassWrapper *java_class_wrapper = nullptr; static OS_Android *os_android = nullptr; +static AndroidInputHandler *input_handler = nullptr; static GodotJavaWrapper *godot_java = nullptr; static GodotIOJavaWrapper *godot_io_java = nullptr; static bool initialized = false; -static int step = 0; +static SafeNumeric<int> step; // Shared between UI and render threads static Size2 new_size; static Vector3 accelerometer; @@ -111,6 +113,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env if (godot_java) { delete godot_java; } + if (input_handler) { + delete input_handler; + } if (os_android) { delete os_android; } @@ -165,7 +170,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j os_android->set_display_size(Size2i(p_width, p_height)); // No need to reset the surface during startup - if (step > 0) { + if (step.get() > 0) { if (p_surface) { ANativeWindow *native_window = ANativeWindow_fromSurface(env, p_surface); os_android->set_native_window(native_window); @@ -179,7 +184,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits) { if (os_android) { - if (step == 0) { + if (step.get() == 0) { // During startup os_android->set_context_is_16_bits(!p_32_bits); if (p_surface) { @@ -188,33 +193,36 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en } } else { // Rendering context recreated because it was lost; restart app to let it reload everything + step.set(-1); // Ensure no further steps are attempted and no further events are sent os_android->main_loop_end(); godot_java->restart(env); - step = -1; // Ensure no further steps are attempted } } } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz) { - if (step == 0) + if (step.get() == 0) return; - os_android->main_loop_request_go_back(); + if (DisplayServerAndroid *dsa = Object::cast_to<DisplayServerAndroid>(DisplayServer::get_singleton())) { + dsa->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST); + } } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz) { - if (step == -1) + if (step.get() == -1) return; - if (step == 0) { + if (step.get() == 0) { // Since Godot is initialized on the UI thread, main_thread_id was set to that thread's id, // but for Godot purposes, the main thread is the one running the game loop Main::setup2(Thread::get_caller_id()); - ++step; + input_handler = new AndroidInputHandler(); + step.increment(); return; } - if (step == 1) { + if (step.get() == 1) { if (!Main::start()) { return; // should exit instead and print the error } @@ -222,7 +230,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl godot_java->on_godot_setup_completed(env); os_android->main_loop_begin(); godot_java->on_godot_main_loop_started(env); - ++step; + step.increment(); } DisplayServerAndroid::get_singleton()->process_accelerometer(accelerometer); @@ -236,91 +244,100 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl } 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) { - if (step == 0) + if (step.get() <= 0) return; - Vector<DisplayServerAndroid::TouchPos> points; + Vector<AndroidInputHandler::TouchPos> points; for (int i = 0; i < pointer_count; i++) { jfloat p[3]; env->GetFloatArrayRegion(positions, i * 3, 3, p); - DisplayServerAndroid::TouchPos tp; + AndroidInputHandler::TouchPos tp; tp.pos = Point2(p[1], p[2]); tp.id = (int)p[0]; points.push_back(tp); } if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE || (input_device & AINPUT_SOURCE_MOUSE_RELATIVE) == AINPUT_SOURCE_MOUSE_RELATIVE) { - DisplayServerAndroid::get_singleton()->process_mouse_event(input_device, ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor); + input_handler->process_mouse_event(input_device, ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor); } else { - DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points); + input_handler->process_touch(ev, pointer, points); } } +// 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) { 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 == 0) + if (step.get() <= 0) return; - DisplayServerAndroid::get_singleton()->process_hover(p_type, Point2(p_x, p_y)); + input_handler->process_hover(p_type, Point2(p_x, p_y)); } +// 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) { - if (step == 0) + if (step.get() <= 0) return; - DisplayServerAndroid::get_singleton()->process_double_tap(p_button_mask, Point2(p_x, p_y)); + input_handler->process_double_tap(p_button_mask, Point2(p_x, p_y)); } +// Called on the UI thread JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) { - if (step == 0) + if (step.get() <= 0) return; - DisplayServerAndroid::get_singleton()->process_scroll(Point2(p_x, p_y)); + input_handler->process_scroll(Point2(p_x, p_y)); } +// Called on the UI thread JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed) { - if (step == 0) + if (step.get() <= 0) return; - DisplayServerAndroid::JoypadEvent jevent; + AndroidInputHandler::JoypadEvent jevent; jevent.device = p_device; - jevent.type = DisplayServerAndroid::JOY_EVENT_BUTTON; + jevent.type = AndroidInputHandler::JOY_EVENT_BUTTON; jevent.index = p_button; jevent.pressed = p_pressed; - DisplayServerAndroid::get_singleton()->process_joy_event(jevent); + input_handler->process_joy_event(jevent); } +// Called on the UI thread JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value) { - if (step == 0) + if (step.get() <= 0) return; - DisplayServerAndroid::JoypadEvent jevent; + AndroidInputHandler::JoypadEvent jevent; jevent.device = p_device; - jevent.type = DisplayServerAndroid::JOY_EVENT_AXIS; + jevent.type = AndroidInputHandler::JOY_EVENT_AXIS; jevent.index = p_axis; jevent.value = p_value; - DisplayServerAndroid::get_singleton()->process_joy_event(jevent); + input_handler->process_joy_event(jevent); } +// Called on the UI thread JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y) { - if (step == 0) + if (step.get() <= 0) return; - DisplayServerAndroid::JoypadEvent jevent; + AndroidInputHandler::JoypadEvent jevent; jevent.device = p_device; - jevent.type = DisplayServerAndroid::JOY_EVENT_HAT; + jevent.type = AndroidInputHandler::JOY_EVENT_HAT; int hat = 0; if (p_hat_x != 0) { if (p_hat_x < 0) @@ -336,9 +353,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j } jevent.hat = hat; - DisplayServerAndroid::get_singleton()->process_joy_event(jevent); + input_handler->process_joy_event(jevent); } +// Called on the UI thread JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jclass clazz, jint p_device, jboolean p_connected, jstring p_name) { if (os_android) { String name = jstring_to_string(p_name, env); @@ -346,11 +364,12 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged( } } +// Called on the UI thread JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed) { - if (step == 0) + if (step.get() <= 0) return; - DisplayServerAndroid::get_singleton()->process_key_event(p_keycode, p_scancode, p_unicode_char, p_pressed); + input_handler->process_key_event(p_keycode, p_scancode, p_unicode_char, p_pressed); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) { @@ -370,14 +389,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jclass clazz) { - if (step == 0) + if (step.get() <= 0) return; os_android->main_loop_focusin(); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jclass clazz) { - if (step == 0) + if (step.get() <= 0) return; os_android->main_loop_focusout(); @@ -456,7 +475,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResu } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz) { - if (step == 0) + if (step.get() <= 0) return; if (os_android->get_main_loop()) { @@ -465,7 +484,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNI } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz) { - if (step == 0) + if (step.get() <= 0) return; if (os_android->get_main_loop()) { diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 792a390e36..c2e12442b3 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -188,10 +188,6 @@ void OS_Android::main_loop_focusin() { audio_driver_android.set_pause(false); } -void OS_Android::main_loop_request_go_back() { - DisplayServerAndroid::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST); -} - Error OS_Android::shell_open(String p_uri) { return godot_io_java->open_uri(p_uri); } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 38f0f3edc7..a5b995a775 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -95,7 +95,6 @@ public: void main_loop_begin(); bool main_loop_iterate(); - void main_loop_request_go_back(); void main_loop_end(); void main_loop_focusout(); void main_loop_focusin(); |