Merge pull request #37158 from thebestnom/android-click-support

Support mouse events on Android
This commit is contained in:
Rémi Verschelde 2020-10-30 16:00:03 +01:00 committed by GitHub
commit 41f66761fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 311 additions and 237 deletions

View File

@ -31,130 +31,9 @@
#ifndef ANDROID_KEYS_UTILS_H #ifndef ANDROID_KEYS_UTILS_H
#define ANDROID_KEYS_UTILS_H #define ANDROID_KEYS_UTILS_H
#include <android/input.h>
#include <core/os/keyboard.h> #include <core/os/keyboard.h>
/*
* Android Key codes.
*/
enum {
AKEYCODE_UNKNOWN = 0,
AKEYCODE_SOFT_LEFT = 1,
AKEYCODE_SOFT_RIGHT = 2,
AKEYCODE_HOME = 3,
AKEYCODE_BACK = 4,
AKEYCODE_CALL = 5,
AKEYCODE_ENDCALL = 6,
AKEYCODE_0 = 7,
AKEYCODE_1 = 8,
AKEYCODE_2 = 9,
AKEYCODE_3 = 10,
AKEYCODE_4 = 11,
AKEYCODE_5 = 12,
AKEYCODE_6 = 13,
AKEYCODE_7 = 14,
AKEYCODE_8 = 15,
AKEYCODE_9 = 16,
AKEYCODE_STAR = 17,
AKEYCODE_POUND = 18,
AKEYCODE_DPAD_UP = 19,
AKEYCODE_DPAD_DOWN = 20,
AKEYCODE_DPAD_LEFT = 21,
AKEYCODE_DPAD_RIGHT = 22,
AKEYCODE_DPAD_CENTER = 23,
AKEYCODE_VOLUME_UP = 24,
AKEYCODE_VOLUME_DOWN = 25,
AKEYCODE_POWER = 26,
AKEYCODE_CAMERA = 27,
AKEYCODE_CLEAR = 28,
AKEYCODE_A = 29,
AKEYCODE_B = 30,
AKEYCODE_C = 31,
AKEYCODE_D = 32,
AKEYCODE_E = 33,
AKEYCODE_F = 34,
AKEYCODE_G = 35,
AKEYCODE_H = 36,
AKEYCODE_I = 37,
AKEYCODE_J = 38,
AKEYCODE_K = 39,
AKEYCODE_L = 40,
AKEYCODE_M = 41,
AKEYCODE_N = 42,
AKEYCODE_O = 43,
AKEYCODE_P = 44,
AKEYCODE_Q = 45,
AKEYCODE_R = 46,
AKEYCODE_S = 47,
AKEYCODE_T = 48,
AKEYCODE_U = 49,
AKEYCODE_V = 50,
AKEYCODE_W = 51,
AKEYCODE_X = 52,
AKEYCODE_Y = 53,
AKEYCODE_Z = 54,
AKEYCODE_COMMA = 55,
AKEYCODE_PERIOD = 56,
AKEYCODE_ALT_LEFT = 57,
AKEYCODE_ALT_RIGHT = 58,
AKEYCODE_SHIFT_LEFT = 59,
AKEYCODE_SHIFT_RIGHT = 60,
AKEYCODE_TAB = 61,
AKEYCODE_SPACE = 62,
AKEYCODE_SYM = 63,
AKEYCODE_EXPLORER = 64,
AKEYCODE_ENVELOPE = 65,
AKEYCODE_ENTER = 66,
AKEYCODE_DEL = 67,
AKEYCODE_GRAVE = 68,
AKEYCODE_MINUS = 69,
AKEYCODE_EQUALS = 70,
AKEYCODE_LEFT_BRACKET = 71,
AKEYCODE_RIGHT_BRACKET = 72,
AKEYCODE_BACKSLASH = 73,
AKEYCODE_SEMICOLON = 74,
AKEYCODE_APOSTROPHE = 75,
AKEYCODE_SLASH = 76,
AKEYCODE_AT = 77,
AKEYCODE_NUM = 78,
AKEYCODE_HEADSETHOOK = 79,
AKEYCODE_FOCUS = 80, // *Camera* focus
AKEYCODE_PLUS = 81,
AKEYCODE_MENU = 82,
AKEYCODE_NOTIFICATION = 83,
AKEYCODE_SEARCH = 84,
AKEYCODE_MEDIA_PLAY_PAUSE = 85,
AKEYCODE_MEDIA_STOP = 86,
AKEYCODE_MEDIA_NEXT = 87,
AKEYCODE_MEDIA_PREVIOUS = 88,
AKEYCODE_MEDIA_REWIND = 89,
AKEYCODE_MEDIA_FAST_FORWARD = 90,
AKEYCODE_MUTE = 91,
AKEYCODE_PAGE_UP = 92,
AKEYCODE_PAGE_DOWN = 93,
AKEYCODE_PICTSYMBOLS = 94,
AKEYCODE_SWITCH_CHARSET = 95,
AKEYCODE_BUTTON_A = 96,
AKEYCODE_BUTTON_B = 97,
AKEYCODE_BUTTON_C = 98,
AKEYCODE_BUTTON_X = 99,
AKEYCODE_BUTTON_Y = 100,
AKEYCODE_BUTTON_Z = 101,
AKEYCODE_BUTTON_L1 = 102,
AKEYCODE_BUTTON_R1 = 103,
AKEYCODE_BUTTON_L2 = 104,
AKEYCODE_BUTTON_R2 = 105,
AKEYCODE_BUTTON_THUMBL = 106,
AKEYCODE_BUTTON_THUMBR = 107,
AKEYCODE_BUTTON_START = 108,
AKEYCODE_BUTTON_SELECT = 109,
AKEYCODE_BUTTON_MODE = 110,
AKEYCODE_CONTROL_LEFT = 113,
AKEYCODE_CONTROL_RIGHT = 114,
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
};
struct _WinTranslatePair { struct _WinTranslatePair {
unsigned int keysym; unsigned int keysym;
unsigned int keycode; unsigned int keycode;
@ -248,8 +127,8 @@ static _WinTranslatePair _ak_to_keycode[] = {
{ KEY_BACKSLASH, AKEYCODE_BACKSLASH }, { KEY_BACKSLASH, AKEYCODE_BACKSLASH },
{ KEY_BRACKETLEFT, AKEYCODE_LEFT_BRACKET }, { KEY_BRACKETLEFT, AKEYCODE_LEFT_BRACKET },
{ KEY_BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET }, { KEY_BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET },
{ KEY_CONTROL, AKEYCODE_CONTROL_LEFT }, { KEY_CONTROL, AKEYCODE_CTRL_LEFT },
{ KEY_CONTROL, AKEYCODE_CONTROL_RIGHT }, { KEY_CONTROL, AKEYCODE_CTRL_RIGHT },
{ KEY_UNKNOWN, 0 } { KEY_UNKNOWN, 0 }
}; };
/* /*

View File

@ -36,6 +36,8 @@
#include "java_godot_wrapper.h" #include "java_godot_wrapper.h"
#include "os_android.h" #include "os_android.h"
#include <android/input.h>
#if defined(VULKAN_ENABLED) #if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h" #include "drivers/vulkan/rendering_device_vulkan.h"
#include "platform/android/vulkan/vulkan_context_android.h" #include "platform/android/vulkan/vulkan_context_android.h"
@ -55,7 +57,7 @@ bool DisplayServerAndroid::has_feature(Feature p_feature) const {
//case FEATURE_HIDPI: //case FEATURE_HIDPI:
//case FEATURE_ICON: //case FEATURE_ICON:
//case FEATURE_IME: //case FEATURE_IME:
//case FEATURE_MOUSE: case FEATURE_MOUSE:
//case FEATURE_MOUSE_WARP: //case FEATURE_MOUSE_WARP:
//case FEATURE_NATIVE_DIALOG: //case FEATURE_NATIVE_DIALOG:
//case FEATURE_NATIVE_ICON: //case FEATURE_NATIVE_ICON:
@ -343,7 +345,7 @@ void DisplayServerAndroid::alert(const String &p_alert, const String &p_title) {
} }
void DisplayServerAndroid::process_events() { void DisplayServerAndroid::process_events() {
// Nothing to do Input::get_singleton()->flush_accumulated_events();
} }
Vector<String> DisplayServerAndroid::get_rendering_drivers_func() { Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
@ -398,6 +400,8 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on"); keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on");
buttons_state = 0;
#if defined(OPENGL_ENABLED) #if defined(OPENGL_ENABLED)
if (rendering_driver == "opengl") { if (rendering_driver == "opengl") {
bool gl_initialization_error = false; bool gl_initialization_error = false;
@ -532,12 +536,12 @@ void DisplayServerAndroid::process_key_event(int p_keycode, int p_scancode, int
OS_Android::get_singleton()->main_loop_request_go_back(); OS_Android::get_singleton()->main_loop_request_go_back();
} }
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
} }
void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector<DisplayServerAndroid::TouchPos> &p_points) { void DisplayServerAndroid::process_touch(int p_event, int p_pointer, const Vector<DisplayServerAndroid::TouchPos> &p_points) {
switch (p_what) { switch (p_event) {
case 0: { //gesture begin case AMOTION_EVENT_ACTION_DOWN: { //gesture begin
if (touch.size()) { if (touch.size()) {
//end all if exist //end all if exist
for (int i = 0; i < touch.size(); i++) { for (int i = 0; i < touch.size(); i++) {
@ -546,7 +550,7 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(touch[i].id); ev->set_index(touch[i].id);
ev->set_pressed(false); ev->set_pressed(false);
ev->set_position(touch[i].pos); ev->set_position(touch[i].pos);
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
} }
} }
@ -563,11 +567,11 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(touch[i].id); ev->set_index(touch[i].id);
ev->set_pressed(true); ev->set_pressed(true);
ev->set_position(touch[i].pos); ev->set_position(touch[i].pos);
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
} }
} break; } break;
case 1: { //motion case AMOTION_EVENT_ACTION_MOVE: { //motion
ERR_FAIL_COND(touch.size() != p_points.size()); ERR_FAIL_COND(touch.size() != p_points.size());
for (int i = 0; i < touch.size(); i++) { for (int i = 0; i < touch.size(); i++) {
@ -589,12 +593,13 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(touch[i].id); ev->set_index(touch[i].id);
ev->set_position(p_points[idx].pos); ev->set_position(p_points[idx].pos);
ev->set_relative(p_points[idx].pos - touch[i].pos); ev->set_relative(p_points[idx].pos - touch[i].pos);
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
touch.write[i].pos = p_points[idx].pos; touch.write[i].pos = p_points[idx].pos;
} }
} break; } break;
case 2: { //release case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_UP: { //release
if (touch.size()) { if (touch.size()) {
//end all if exist //end all if exist
for (int i = 0; i < touch.size(); i++) { for (int i = 0; i < touch.size(); i++) {
@ -603,12 +608,12 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(touch[i].id); ev->set_index(touch[i].id);
ev->set_pressed(false); ev->set_pressed(false);
ev->set_position(touch[i].pos); ev->set_position(touch[i].pos);
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
} }
touch.clear(); touch.clear();
} }
} break; } break;
case 3: { // 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++) {
if (p_points[i].id == p_pointer) { if (p_points[i].id == p_pointer) {
TouchPos tp = p_points[i]; TouchPos tp = p_points[i];
@ -620,13 +625,13 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(tp.id); ev->set_index(tp.id);
ev->set_pressed(true); ev->set_pressed(true);
ev->set_position(tp.pos); ev->set_position(tp.pos);
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
break; break;
} }
} }
} break; } break;
case 4: { // remove touch case AMOTION_EVENT_ACTION_POINTER_UP: { // remove touch
for (int i = 0; i < touch.size(); i++) { for (int i = 0; i < touch.size(); i++) {
if (touch[i].id == p_pointer) { if (touch[i].id == p_pointer) {
Ref<InputEventScreenTouch> ev; Ref<InputEventScreenTouch> ev;
@ -634,7 +639,7 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(touch[i].id); ev->set_index(touch[i].id);
ev->set_pressed(false); ev->set_pressed(false);
ev->set_position(touch[i].pos); ev->set_position(touch[i].pos);
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
touch.remove(i); touch.remove(i);
break; break;
@ -647,30 +652,116 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
void DisplayServerAndroid::process_hover(int p_type, Point2 p_pos) { void DisplayServerAndroid::process_hover(int p_type, Point2 p_pos) {
// https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
switch (p_type) { switch (p_type) {
case 7: // hover move case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move
case 9: // hover enter case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter
case 10: { // hover exit case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit
Ref<InputEventMouseMotion> ev; Ref<InputEventMouseMotion> ev;
ev.instance(); ev.instance();
_set_key_modifier_state(ev); _set_key_modifier_state(ev);
ev->set_position(p_pos); ev->set_position(p_pos);
ev->set_global_position(p_pos); ev->set_global_position(p_pos);
ev->set_relative(p_pos - hover_prev_pos); ev->set_relative(p_pos - hover_prev_pos);
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
hover_prev_pos = p_pos; hover_prev_pos = p_pos;
} break; } break;
} }
} }
void DisplayServerAndroid::process_double_tap(Point2 p_pos) { void DisplayServerAndroid::process_mouse_event(int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) {
int 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.instance();
_set_key_modifier_state(ev);
ev->set_position(event_pos);
ev->set_global_position(event_pos);
ev->set_pressed(event_action == AMOTION_EVENT_ACTION_BUTTON_PRESS);
int changed_button_mask = buttons_state ^ event_buttons_mask;
buttons_state = event_buttons_mask;
ev->set_button_index(_button_index_from_mask(changed_button_mask));
ev->set_button_mask(event_buttons_mask);
Input::get_singleton()->accumulate_input_event(ev);
} break;
case AMOTION_EVENT_ACTION_MOVE: {
Ref<InputEventMouseMotion> ev;
ev.instance();
_set_key_modifier_state(ev);
ev->set_position(event_pos);
ev->set_global_position(event_pos);
ev->set_relative(event_pos - hover_prev_pos);
ev->set_button_mask(event_buttons_mask);
Input::get_singleton()->accumulate_input_event(ev);
hover_prev_pos = event_pos;
} break;
case AMOTION_EVENT_ACTION_SCROLL: {
Ref<InputEventMouseButton> ev;
ev.instance();
ev->set_position(event_pos);
ev->set_global_position(event_pos);
ev->set_pressed(true);
buttons_state = event_buttons_mask;
if (event_vertical_factor > 0) {
_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_UP, event_vertical_factor);
} else if (event_vertical_factor < 0) {
_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_DOWN, -event_vertical_factor);
}
if (event_horizontal_factor > 0) {
_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_RIGHT, event_horizontal_factor);
} else if (event_horizontal_factor < 0) {
_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_LEFT, -event_horizontal_factor);
}
} break;
}
}
void DisplayServerAndroid::_wheel_button_click(int event_buttons_mask, const Ref<InputEventMouseButton> &ev, int wheel_button, float factor) {
Ref<InputEventMouseButton> evd = ev->duplicate();
_set_key_modifier_state(evd);
evd->set_button_index(wheel_button);
evd->set_button_mask(event_buttons_mask ^ (1 << (wheel_button - 1)));
evd->set_factor(factor);
Input::get_singleton()->accumulate_input_event(evd);
Ref<InputEventMouseButton> evdd = evd->duplicate();
evdd->set_pressed(false);
evdd->set_button_mask(event_buttons_mask);
Input::get_singleton()->accumulate_input_event(evdd);
}
void DisplayServerAndroid::process_double_tap(int event_android_button_mask, Point2 p_pos) {
int event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask);
Ref<InputEventMouseButton> ev; Ref<InputEventMouseButton> ev;
ev.instance(); ev.instance();
_set_key_modifier_state(ev); _set_key_modifier_state(ev);
ev->set_position(p_pos); ev->set_position(p_pos);
ev->set_global_position(p_pos); ev->set_global_position(p_pos);
ev->set_pressed(false); 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_doubleclick(true); ev->set_doubleclick(true);
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
}
int DisplayServerAndroid::_button_index_from_mask(int button_mask) {
switch (button_mask) {
case BUTTON_MASK_LEFT:
return BUTTON_LEFT;
case BUTTON_MASK_RIGHT:
return BUTTON_RIGHT;
case BUTTON_MASK_MIDDLE:
return BUTTON_MIDDLE;
case BUTTON_MASK_XBUTTON1:
return BUTTON_XBUTTON1;
case BUTTON_MASK_XBUTTON2:
return BUTTON_XBUTTON2;
default:
return 0;
}
} }
void DisplayServerAndroid::process_scroll(Point2 p_pos) { void DisplayServerAndroid::process_scroll(Point2 p_pos) {
@ -679,7 +770,7 @@ void DisplayServerAndroid::process_scroll(Point2 p_pos) {
_set_key_modifier_state(ev); _set_key_modifier_state(ev);
ev->set_position(p_pos); ev->set_position(p_pos);
ev->set_delta(p_pos - scroll_prev_pos); ev->set_delta(p_pos - scroll_prev_pos);
Input::get_singleton()->parse_input_event(ev); Input::get_singleton()->accumulate_input_event(ev);
scroll_prev_pos = p_pos; scroll_prev_pos = p_pos;
} }
@ -698,3 +789,32 @@ void DisplayServerAndroid::process_magnetometer(const Vector3 &p_magnetometer) {
void DisplayServerAndroid::process_gyroscope(const Vector3 &p_gyroscope) { void DisplayServerAndroid::process_gyroscope(const Vector3 &p_gyroscope) {
Input::get_singleton()->set_gyroscope(p_gyroscope); Input::get_singleton()->set_gyroscope(p_gyroscope);
} }
Point2i DisplayServerAndroid::mouse_get_position() const {
return hover_prev_pos;
}
int DisplayServerAndroid::mouse_get_button_state() const {
return buttons_state;
}
int DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_button_mask) {
int godot_button_mask = 0;
if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) {
godot_button_mask |= BUTTON_MASK_LEFT;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
godot_button_mask |= BUTTON_MASK_RIGHT;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_TERTIARY) {
godot_button_mask |= BUTTON_MASK_MIDDLE;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) {
godot_button_mask |= BUTTON_MASK_XBUTTON1;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
godot_button_mask |= BUTTON_MASK_XBUTTON2;
}
return godot_button_mask;
}

View File

@ -68,6 +68,8 @@ private:
bool control_mem = false; bool control_mem = false;
bool meta_mem = false; bool meta_mem = false;
int buttons_state;
bool keep_screen_on; bool keep_screen_on;
Vector<TouchPos> touch; Vector<TouchPos> touch;
@ -91,6 +93,12 @@ private:
void _set_key_modifier_state(Ref<InputEventWithModifiers> ev); void _set_key_modifier_state(Ref<InputEventWithModifiers> ev);
static int _button_index_from_mask(int button_mask);
static int _android_button_mask_to_godot_button_mask(int android_button_mask);
void _wheel_button_click(int event_buttons_mask, const Ref<InputEventMouseButton> &ev, int wheel_button, float factor);
public: public:
static DisplayServerAndroid *get_singleton(); static DisplayServerAndroid *get_singleton();
@ -162,9 +170,10 @@ public:
void process_gravity(const Vector3 &p_gravity); void process_gravity(const Vector3 &p_gravity);
void process_magnetometer(const Vector3 &p_magnetometer); void process_magnetometer(const Vector3 &p_magnetometer);
void process_gyroscope(const Vector3 &p_gyroscope); void process_gyroscope(const Vector3 &p_gyroscope);
void process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points); 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_hover(int p_type, Point2 p_pos);
void process_double_tap(Point2 p_pos); void process_mouse_event(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_scroll(Point2 p_pos);
void process_joy_event(JoypadEvent p_event); void process_joy_event(JoypadEvent p_event);
void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed);
@ -175,6 +184,9 @@ public:
void reset_window(); void reset_window();
virtual Point2i mouse_get_position() const;
virtual int mouse_get_button_state() const;
DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
~DisplayServerAndroid(); ~DisplayServerAndroid();
}; };

View File

@ -70,6 +70,7 @@ import android.os.VibrationEffect;
import android.os.Vibrator; import android.os.Vibrator;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
import android.view.Display; import android.view.Display;
import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -854,63 +855,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
} }
} }
public boolean gotTouchEvent(final MotionEvent event) {
final int evcount = event.getPointerCount();
if (evcount == 0)
return true;
if (mRenderView != null) {
final int[] arr = new int[event.getPointerCount() * 3];
for (int i = 0; i < event.getPointerCount(); i++) {
arr[i * 3 + 0] = (int)event.getPointerId(i);
arr[i * 3 + 1] = (int)event.getX(i);
arr[i * 3 + 2] = (int)event.getY(i);
}
final int pointer_idx = event.getPointerId(event.getActionIndex());
//System.out.printf("gaction: %d\n",event.getAction());
final int action = event.getAction() & MotionEvent.ACTION_MASK;
mRenderView.queueOnRenderThread(new Runnable() {
@Override
public void run() {
switch (action) {
case MotionEvent.ACTION_DOWN: {
GodotLib.touch(0, 0, evcount, arr);
//System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
} break;
case MotionEvent.ACTION_MOVE: {
GodotLib.touch(1, 0, evcount, arr);
/*
for(int i=0;i<event.getPointerCount();i++) {
System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
}
*/
} break;
case MotionEvent.ACTION_POINTER_UP: {
GodotLib.touch(4, pointer_idx, evcount, arr);
//System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
} break;
case MotionEvent.ACTION_POINTER_DOWN: {
GodotLib.touch(3, pointer_idx, evcount, arr);
//System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
} break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
GodotLib.touch(2, 0, evcount, arr);
/*
for(int i=0;i<event.getPointerCount();i++) {
System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
}
*/
} break;
}
}
});
}
return true;
}
public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) { public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) {
String s = event.getCharacters(); String s = event.getCharacters();
if (s == null || s.length() == 0) if (s == null || s.length() == 0)

View File

@ -29,7 +29,6 @@
/*************************************************************************/ /*************************************************************************/
package org.godotengine.godot; package org.godotengine.godot;
import org.godotengine.godot.input.GodotGestureHandler; 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;
@ -127,7 +126,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event); super.onTouchEvent(event);
this.detector.onTouchEvent(event); this.detector.onTouchEvent(event);
return godot.gotTouchEvent(event); return inputHandler.onTouchEvent(event);
} }
@Override @Override

View File

@ -94,17 +94,19 @@ public class GodotLib {
/** /**
* Forward touch events from the main thread to the GL thread. * Forward touch events from the main thread to the GL thread.
*/ */
public static native void touch(int what, int pointer, int howmany, int[] arr); public static native void touch(int inputDevice, 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. * Forward hover events from the main thread to the GL thread.
*/ */
public static native void hover(int type, int x, int y); public static native void hover(int type, float x, float y);
/** /**
* Forward double_tap events from the main thread to the GL thread. * Forward double_tap events from the main thread to the GL thread.
*/ */
public static native void doubletap(int x, int y); public static native void doubleTap(int buttonMask, int x, int y);
/** /**
* Forward scroll events from the main thread to the GL thread. * Forward scroll events from the main thread to the GL thread.

View File

@ -38,6 +38,7 @@ import org.godotengine.godot.vulkan.VkSurfaceView;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SurfaceView; import android.view.SurfaceView;
@ -100,22 +101,22 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event); super.onTouchEvent(event);
mGestureDetector.onTouchEvent(event); mGestureDetector.onTouchEvent(event);
return godot.gotTouchEvent(event); return mInputHandler.onTouchEvent(event);
} }
@Override @Override
public boolean onKeyUp(final int keyCode, KeyEvent event) { public boolean onKeyUp(final int keyCode, KeyEvent event) {
return mInputHandler.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event); return mInputHandler.onKeyUp(keyCode, event);
} }
@Override @Override
public boolean onKeyDown(final int keyCode, KeyEvent event) { public boolean onKeyDown(final int keyCode, KeyEvent event) {
return mInputHandler.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); return mInputHandler.onKeyDown(keyCode, event);
} }
@Override @Override
public boolean onGenericMotionEvent(MotionEvent event) { public boolean onGenericMotionEvent(MotionEvent event) {
return mInputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event); return mInputHandler.onGenericMotionEvent(event);
} }
@Override @Override

View File

@ -33,7 +33,6 @@ package org.godotengine.godot.input;
import org.godotengine.godot.GodotLib; import org.godotengine.godot.GodotLib;
import org.godotengine.godot.GodotRenderView; import org.godotengine.godot.GodotRenderView;
import android.util.Log;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -75,10 +74,11 @@ public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener
//Log.i("GodotGesture", "onDoubleTap"); //Log.i("GodotGesture", "onDoubleTap");
final int x = Math.round(event.getX()); final int x = Math.round(event.getX());
final int y = Math.round(event.getY()); final int y = Math.round(event.getY());
final int buttonMask = event.getButtonState();
queueEvent(new Runnable() { queueEvent(new Runnable() {
@Override @Override
public void run() { public void run() {
GodotLib.doubletap(x, y); GodotLib.doubleTap(buttonMask, x, y);
} }
}); });
return true; return true;

View File

@ -36,6 +36,7 @@ import org.godotengine.godot.GodotLib;
import org.godotengine.godot.GodotRenderView; import org.godotengine.godot.GodotRenderView;
import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener; import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener;
import android.os.Build;
import android.util.Log; import android.util.Log;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.InputDevice.MotionRange; import android.view.InputDevice.MotionRange;
@ -156,6 +157,53 @@ public class GodotInputHandler implements InputDeviceListener {
return true; return true;
} }
public boolean onTouchEvent(final MotionEvent event) {
// Mouse drag (mouse pressed and move) doesn't fire onGenericMotionEvent so this is needed
if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
if (event.getAction() != MotionEvent.ACTION_MOVE) {
// we return true because every time a mouse event is fired, the event is already handled
// in onGenericMotionEvent, so by touch event we can say that the event is also handled
return true;
}
return handleMouseEvent(event);
}
final int evcount = event.getPointerCount();
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();
mRenderView.queueOnRenderThread(new Runnable() {
@Override
public void run() {
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE: {
GodotLib.touch(event.getSource(), action, 0, evcount, arr);
} break;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN: {
int pointer_idx = event.getPointerId(event.getActionIndex());
GodotLib.touch(event.getSource(), action, pointer_idx, evcount, arr);
} break;
}
}
});
}
return true;
}
public boolean onGenericMotionEvent(MotionEvent event) { public boolean onGenericMotionEvent(MotionEvent event) {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) { if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
final int device_id = findJoystickDevice(event.getDeviceId()); final int device_id = findJoystickDevice(event.getDeviceId());
@ -189,8 +237,8 @@ public class GodotInputHandler implements InputDeviceListener {
return true; return true;
} }
} else if ((event.getSource() & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS) { } else if ((event.getSource() & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS) {
final int x = Math.round(event.getX()); final float x = event.getX();
final int y = Math.round(event.getY()); final float y = event.getY();
final int type = event.getAction(); final int type = event.getAction();
queueEvent(new Runnable() { queueEvent(new Runnable() {
@Override @Override
@ -199,6 +247,10 @@ public class GodotInputHandler implements InputDeviceListener {
} }
}); });
return true; return true;
} else if ((event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return handleMouseEvent(event);
}
} }
return false; return false;
@ -366,4 +418,53 @@ public class GodotInputHandler implements InputDeviceListener {
return -1; return -1;
} }
private boolean handleMouseEvent(final MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_HOVER_ENTER:
case MotionEvent.ACTION_HOVER_MOVE:
case MotionEvent.ACTION_HOVER_EXIT: {
final float x = event.getX();
final float y = event.getY();
final int type = event.getAction();
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.hover(type, x, y);
}
});
return true;
}
case MotionEvent.ACTION_BUTTON_PRESS:
case MotionEvent.ACTION_BUTTON_RELEASE:
case MotionEvent.ACTION_MOVE: {
final float x = event.getX();
final float y = event.getY();
final int buttonsMask = event.getButtonState();
final int action = event.getAction();
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask);
}
});
return true;
}
case MotionEvent.ACTION_SCROLL: {
final float x = event.getX();
final float y = event.getY();
final int buttonsMask = event.getButtonState();
final int action = event.getAction();
final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
queueEvent(new Runnable() {
@Override
public void run() {
GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor);
}
});
}
}
return false;
}
} }

View File

@ -51,6 +51,7 @@
#include "string_android.h" #include "string_android.h"
#include "thread_jandroid.h" #include "thread_jandroid.h"
#include <android/input.h>
#include <unistd.h> #include <unistd.h>
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
@ -237,40 +238,51 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
} }
} }
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint count, jintArray positions) { 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 == 0)
return; return;
Vector<DisplayServerAndroid::TouchPos> points; Vector<DisplayServerAndroid::TouchPos> points;
for (int i = 0; i < count; i++) { for (int i = 0; i < pointer_count; i++) {
jint p[3]; jfloat p[3];
env->GetIntArrayRegion(positions, i * 3, 3, p); env->GetFloatArrayRegion(positions, i * 3, 3, p);
DisplayServerAndroid::TouchPos tp; DisplayServerAndroid::TouchPos tp;
tp.pos = Point2(p[1], p[2]); tp.pos = Point2(p[1], p[2]);
tp.id = p[0]; tp.id = (int)p[0];
points.push_back(tp); points.push_back(tp);
} }
DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points); if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
DisplayServerAndroid::get_singleton()->process_mouse_event(ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor);
/* } else {
if (os_android) DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points);
os_android->process_touch(ev,pointer,points); }
*/
} }
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jint p_x, jint p_y) { 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);
}
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);
}
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);
}
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 == 0)
return; return;
DisplayServerAndroid::get_singleton()->process_hover(p_type, Point2(p_x, p_y)); DisplayServerAndroid::get_singleton()->process_hover(p_type, Point2(p_x, p_y));
} }
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubletap(JNIEnv *env, jclass clazz, jint p_x, jint 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) {
if (step == 0) if (step == 0)
return; return;
DisplayServerAndroid::get_singleton()->process_double_tap(Point2(p_x, p_y)); DisplayServerAndroid::get_singleton()->process_double_tap(p_button_mask, Point2(p_x, p_y));
} }
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) { JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) {

View File

@ -44,9 +44,12 @@ 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); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint count, jintArray positions); 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_hover(JNIEnv *env, jclass clazz, jint p_type, jint p_x, jint p_y); 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_doubletap(JNIEnv *env, jclass clazz, jint p_x, jint p_y); 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_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_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_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y);
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); 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);
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);

View File

@ -153,6 +153,7 @@ void OS_Android::main_loop_begin() {
bool OS_Android::main_loop_iterate() { bool OS_Android::main_loop_iterate() {
if (!main_loop) if (!main_loop)
return false; return false;
DisplayServerAndroid::get_singleton()->process_events();
return Main::iteration(); return Main::iteration();
} }