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
#define ANDROID_KEYS_UTILS_H
#include <android/input.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 {
unsigned int keysym;
unsigned int keycode;
@ -248,8 +127,8 @@ static _WinTranslatePair _ak_to_keycode[] = {
{ KEY_BACKSLASH, AKEYCODE_BACKSLASH },
{ KEY_BRACKETLEFT, AKEYCODE_LEFT_BRACKET },
{ KEY_BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET },
{ KEY_CONTROL, AKEYCODE_CONTROL_LEFT },
{ KEY_CONTROL, AKEYCODE_CONTROL_RIGHT },
{ KEY_CONTROL, AKEYCODE_CTRL_LEFT },
{ KEY_CONTROL, AKEYCODE_CTRL_RIGHT },
{ KEY_UNKNOWN, 0 }
};
/*

View File

@ -36,6 +36,8 @@
#include "java_godot_wrapper.h"
#include "os_android.h"
#include <android/input.h>
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.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_ICON:
//case FEATURE_IME:
//case FEATURE_MOUSE:
case FEATURE_MOUSE:
//case FEATURE_MOUSE_WARP:
//case FEATURE_NATIVE_DIALOG:
//case FEATURE_NATIVE_ICON:
@ -343,7 +345,7 @@ void DisplayServerAndroid::alert(const String &p_alert, const String &p_title) {
}
void DisplayServerAndroid::process_events() {
// Nothing to do
Input::get_singleton()->flush_accumulated_events();
}
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");
buttons_state = 0;
#if defined(OPENGL_ENABLED)
if (rendering_driver == "opengl") {
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();
}
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) {
switch (p_what) {
case 0: { //gesture begin
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++) {
@ -546,7 +550,7 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(touch[i].id);
ev->set_pressed(false);
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_pressed(true);
ev->set_position(touch[i].pos);
Input::get_singleton()->parse_input_event(ev);
Input::get_singleton()->accumulate_input_event(ev);
}
} break;
case 1: { //motion
case AMOTION_EVENT_ACTION_MOVE: { //motion
ERR_FAIL_COND(touch.size() != p_points.size());
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_position(p_points[idx].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;
}
} break;
case 2: { //release
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++) {
@ -603,12 +608,12 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(touch[i].id);
ev->set_pressed(false);
ev->set_position(touch[i].pos);
Input::get_singleton()->parse_input_event(ev);
Input::get_singleton()->accumulate_input_event(ev);
}
touch.clear();
}
} break;
case 3: { // add touch
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];
@ -620,13 +625,13 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(tp.id);
ev->set_pressed(true);
ev->set_position(tp.pos);
Input::get_singleton()->parse_input_event(ev);
Input::get_singleton()->accumulate_input_event(ev);
break;
}
}
} break;
case 4: { // remove touch
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;
@ -634,7 +639,7 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
ev->set_index(touch[i].id);
ev->set_pressed(false);
ev->set_position(touch[i].pos);
Input::get_singleton()->parse_input_event(ev);
Input::get_singleton()->accumulate_input_event(ev);
touch.remove(i);
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) {
// https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
switch (p_type) {
case 7: // hover move
case 9: // hover enter
case 10: { // hover exit
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.instance();
_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);
Input::get_singleton()->accumulate_input_event(ev);
hover_prev_pos = p_pos;
} 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;
ev.instance();
_set_key_modifier_state(ev);
ev->set_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);
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) {
@ -679,7 +770,7 @@ void DisplayServerAndroid::process_scroll(Point2 p_pos) {
_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);
Input::get_singleton()->accumulate_input_event(ev);
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) {
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 meta_mem = false;
int buttons_state;
bool keep_screen_on;
Vector<TouchPos> touch;
@ -91,6 +93,12 @@ private:
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:
static DisplayServerAndroid *get_singleton();
@ -162,9 +170,10 @@ 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_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_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_joy_event(JoypadEvent p_event);
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();
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();
};

View File

@ -70,6 +70,7 @@ import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings.Secure;
import android.view.Display;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.LayoutInflater;
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) {
String s = event.getCharacters();
if (s == null || s.length() == 0)

View File

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

View File

@ -94,17 +94,19 @@ public class GodotLib {
/**
* 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.
*/
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.
*/
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.

View File

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

View File

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

View File

@ -36,6 +36,7 @@ import org.godotengine.godot.GodotLib;
import org.godotengine.godot.GodotRenderView;
import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener;
import android.os.Build;
import android.util.Log;
import android.view.InputDevice;
import android.view.InputDevice.MotionRange;
@ -156,6 +157,53 @@ public class GodotInputHandler implements InputDeviceListener {
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) {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
final int device_id = findJoystickDevice(event.getDeviceId());
@ -189,8 +237,8 @@ public class GodotInputHandler implements InputDeviceListener {
return true;
}
} else if ((event.getSource() & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS) {
final int x = Math.round(event.getX());
final int y = Math.round(event.getY());
final float x = event.getX();
final float y = event.getY();
final int type = event.getAction();
queueEvent(new Runnable() {
@Override
@ -199,6 +247,10 @@ public class GodotInputHandler implements InputDeviceListener {
}
});
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;
@ -366,4 +418,53 @@ public class GodotInputHandler implements InputDeviceListener {
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 "thread_jandroid.h"
#include <android/input.h>
#include <unistd.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)
return;
Vector<DisplayServerAndroid::TouchPos> points;
for (int i = 0; i < count; i++) {
jint p[3];
env->GetIntArrayRegion(positions, i * 3, 3, p);
for (int i = 0; i < pointer_count; i++) {
jfloat p[3];
env->GetFloatArrayRegion(positions, i * 3, 3, p);
DisplayServerAndroid::TouchPos tp;
tp.pos = Point2(p[1], p[2]);
tp.id = p[0];
tp.id = (int)p[0];
points.push_back(tp);
}
DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points);
/*
if (os_android)
os_android->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 {
DisplayServerAndroid::get_singleton()->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)
return;
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)
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) {

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_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_touch(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint count, jintArray positions);
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_doubletap(JNIEnv *env, jclass clazz, jint p_x, jint p_y);
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_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_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_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);

View File

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