Ported: Cleanup the Android input logic implementation - m4gr3d

440fa10246
This commit is contained in:
Relintai 2022-09-17 11:35:25 +02:00
parent 93eb41c69e
commit ccba47dc7c
9 changed files with 569 additions and 342 deletions

View File

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

View File

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

View File

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

View File

@ -31,8 +31,6 @@
package net.relintai.pandemonium.pandemonium; package net.relintai.pandemonium.pandemonium;
import net.relintai.pandemonium.pandemonium.gl.PandemoniumGLSurfaceView; import net.relintai.pandemonium.pandemonium.gl.PandemoniumGLSurfaceView;
import net.relintai.pandemonium.pandemonium.input.PandemoniumGestureHandler;
import net.relintai.pandemonium.pandemonium.input.PandemoniumInputHandler; import net.relintai.pandemonium.pandemonium.input.PandemoniumInputHandler;
import net.relintai.pandemonium.pandemonium.utils.GLUtils; import net.relintai.pandemonium.pandemonium.utils.GLUtils;
import net.relintai.pandemonium.pandemonium.config.RegularConfigChooser; import net.relintai.pandemonium.pandemonium.config.RegularConfigChooser;
@ -42,7 +40,6 @@ import net.relintai.pandemonium.pandemonium.config.RegularFallbackConfigChooser;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.view.GestureDetector;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -73,7 +70,6 @@ public class PandemoniumView extends PandemoniumGLSurfaceView {
private final Pandemonium pandemonium; private final Pandemonium pandemonium;
private final PandemoniumInputHandler inputHandler; private final PandemoniumInputHandler inputHandler;
private final GestureDetector detector;
private final PandemoniumRenderer pandemoniumRenderer; private final PandemoniumRenderer pandemoniumRenderer;
private EGLConfigChooser eglConfigChooser; private EGLConfigChooser eglConfigChooser;
@ -87,7 +83,6 @@ public class PandemoniumView extends PandemoniumGLSurfaceView {
this.pandemonium = pandemonium; this.pandemonium = pandemonium;
this.inputHandler = new PandemoniumInputHandler(this); this.inputHandler = new PandemoniumInputHandler(this);
this.detector = new GestureDetector(context, new PandemoniumGestureHandler(this));
this.pandemoniumRenderer = new PandemoniumRenderer(); this.pandemoniumRenderer = new PandemoniumRenderer();
init(p_translucent); init(p_translucent);
@ -101,7 +96,6 @@ public class PandemoniumView extends PandemoniumGLSurfaceView {
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event); super.onTouchEvent(event);
this.detector.onTouchEvent(event);
return inputHandler.onTouchEvent(event); return inputHandler.onTouchEvent(event);
} }

View File

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

View File

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

View File

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

View File

@ -276,62 +276,56 @@ JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_
} }
} }
void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) { // Called on the UI thread
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click) {
if (step.get() <= 0) {
return;
}
input_handler->process_mouse_event(p_event_type, p_button_mask, Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y), p_double_click);
}
// Called on the UI thread
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position) {
if (step.get() <= 0) if (step.get() <= 0)
return; return;
Vector<AndroidInputHandler::TouchPos> points; Vector<AndroidInputHandler::TouchPos> points;
for (int i = 0; i < pointer_count; i++) { for (int i = 0; i < pointer_count; i++) {
jfloat p[3]; jfloat p[3];
env->GetFloatArrayRegion(positions, i * 3, 3, p); env->GetFloatArrayRegion(position, i * 3, 3, p);
AndroidInputHandler::TouchPos tp; AndroidInputHandler::TouchPos tp;
tp.pos = Point2(p[1], p[2]); tp.pos = Point2(p[1], p[2]);
tp.id = (int)p[0]; tp.id = (int)p[0];
points.push_back(tp); points.push_back(tp);
} }
if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { input_handler->process_touch_event(ev, pointer, points);
input_handler->process_mouse_event(ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor); }
} else {
input_handler->process_touch(ev, pointer, points); // Called on the UI thread
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor) {
if (step.get() <= 0) {
return;
} }
input_handler->process_magnify(Point2(p_x, p_y), p_factor);
} }
// Called on the UI thread // Called on the UI thread
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position) { JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y) {
touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position); if (step.get() <= 0) {
}
// Called on the UI thread
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_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_net_relintai_pandemonium_pandemonium_PandemoniumLib_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_net_relintai_pandemonium_pandemonium_PandemoniumLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y) {
if (step.get() <= 0)
return; return;
}
input_handler->process_hover(p_type, Point2(p_x, p_y)); input_handler->process_pan(Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y));
}
// Called on the UI thread
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y) {
if (step.get() <= 0)
return;
input_handler->process_double_tap(p_button_mask, Point2(p_x, p_y));
} }
// Called on the UI thread // Called on the UI thread
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed) { JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed) {
if (step.get() <= 0) if (step.get() <= 0) {
return; return;
}
AndroidInputHandler::JoypadEvent jevent; AndroidInputHandler::JoypadEvent jevent;
jevent.device = p_device; jevent.device = p_device;

View File

@ -44,12 +44,10 @@ JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_newcontext(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_newcontext(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_step(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_step(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_back(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_back(JNIEnv *env, jclass clazz);
void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask = 0, jfloat vertical_factor = 0, jfloat horizontal_factor = 0); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_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_net_relintai_pandemonium_pandemonium_PandemoniumLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_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_net_relintai_pandemonium_pandemonium_PandemoniumLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed);
JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value);