diff --git a/Common/Input/InputState.h b/Common/Input/InputState.h
index 2edb14210e9c..c5683b13f87c 100644
--- a/Common/Input/InputState.h
+++ b/Common/Input/InputState.h
@@ -138,7 +138,7 @@ enum {
TOUCH_RELEASE_ALL = 1 << 6, // Useful for app focus switches when events may be lost.
TOUCH_HOVER = 1 << 7,
- // These are the Android getToolType() codes, shifted by 10.
+ // These are the Android getToolType() codes, shifted by 10. Unused currently.
TOUCH_TOOL_MASK = 7 << 10,
TOUCH_TOOL_UNKNOWN = 0 << 10,
TOUCH_TOOL_FINGER = 1 << 10,
diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp
index d95ad660c394..9c87411f370e 100644
--- a/Qt/QtMain.cpp
+++ b/Qt/QtMain.cpp
@@ -613,7 +613,7 @@ bool MainUI::event(QEvent *e) {
case Qt::LeftButton:
input.x = ((QMouseEvent*)e)->pos().x() * g_display.dpi_scale_x * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_display.dpi_scale_y * yscale;
- input.flags = (e->type() == QEvent::MouseButtonPress) ? TOUCH_DOWN : TOUCH_UP;
+ input.flags = ((e->type() == QEvent::MouseButtonPress) ? TOUCH_DOWN : TOUCH_UP) | TOUCH_MOUSE;
input.id = 0;
NativeTouch(input);
break;
@@ -636,7 +636,7 @@ bool MainUI::event(QEvent *e) {
case QEvent::MouseMove:
input.x = ((QMouseEvent*)e)->pos().x() * g_display.dpi_scale_x * xscale;
input.y = ((QMouseEvent*)e)->pos().y() * g_display.dpi_scale_y * yscale;
- input.flags = TOUCH_MOVE;
+ input.flags = TOUCH_MOVE | TOUCH_MOUSE;
input.id = 0;
NativeTouch(input);
break;
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 34ee89a07889..2484b808a074 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -16,6 +16,7 @@
+
diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp
index 7b91cfd5c271..c5b6318a130f 100644
--- a/android/jni/app-android.cpp
+++ b/android/jni/app-android.cpp
@@ -1252,6 +1252,70 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_joystickAxis(
env->ReleaseFloatArrayElements(values, valueBuffer, JNI_ABORT); // ABORT just means we don't want changes copied back!
}
+extern "C" jboolean Java_org_ppsspp_ppsspp_NativeApp_mouse(
+ JNIEnv *env, jclass, jfloat x, jfloat y, int button, int action) {
+ if (!renderer_inited)
+ return false;
+ TouchInput input{};
+
+ static float last_x = 0.0f;
+ static float last_y = 0.0f;
+
+ if (x == -1.0f) {
+ x = last_x;
+ } else {
+ last_x = x;
+ }
+ if (y == -1.0f) {
+ y = last_y;
+ } else {
+ last_y = y;
+ }
+
+ x *= g_display.dpi_scale_x;
+ y *= g_display.dpi_scale_y;
+
+ if (button == 0) {
+ // It's a pure mouse move.
+ input.flags = TOUCH_MOUSE | TOUCH_MOVE;
+ input.x = x;
+ input.y = y;
+ input.id = 0;
+ } else {
+ input.buttons = button;
+ input.x = x;
+ input.y = y;
+ switch (action) {
+ case 1:
+ input.flags = TOUCH_MOUSE | TOUCH_DOWN;
+ break;
+ case 2:
+ input.flags = TOUCH_MOUSE | TOUCH_UP;
+ break;
+ }
+ input.id = 0;
+ }
+ INFO_LOG(Log::System, "New-style mouse event: %f %f %d %d -> x: %f y: %f buttons: %d flags: %04x", x, y, button, action, input.x, input.y, input.buttons, input.flags);
+ NativeTouch(input);
+
+ // Also send mouse button key events, for binding.
+ if (button) {
+ KeyInput input{};
+ input.deviceId = DEVICE_ID_MOUSE;
+ switch (button) {
+ case 1: input.keyCode = NKCODE_EXT_MOUSEBUTTON_1; break;
+ case 2: input.keyCode = NKCODE_EXT_MOUSEBUTTON_2; break;
+ case 3: input.keyCode = NKCODE_EXT_MOUSEBUTTON_3; break;
+ default: WARN_LOG(Log::System, "Unexpected mouse button %d", button);
+ }
+ input.flags = action == 1 ? KEY_DOWN : KEY_UP;
+ if (input.keyCode != 0) {
+ NativeKey(input);
+ }
+ }
+ return true;
+}
+
extern "C" jboolean Java_org_ppsspp_ppsspp_NativeApp_mouseWheelEvent(
JNIEnv *env, jclass, jfloat x, jfloat y) {
if (!renderer_inited)
diff --git a/android/src/org/ppsspp/ppsspp/MogaHack.java b/android/src/org/ppsspp/ppsspp/MogaHack.java
index fdced81755d0..9b09d3a86ef4 100644
--- a/android/src/org/ppsspp/ppsspp/MogaHack.java
+++ b/android/src/org/ppsspp/ppsspp/MogaHack.java
@@ -68,7 +68,7 @@ public static void init(Controller controller, Context context) {
// Convert implicit intent to explicit intent, see http://stackoverflow.com/a/26318757
Intent intent = new Intent(IControllerService.class.getName());
List resolveInfos = context.getPackageManager().queryIntentServices(intent, 0);
- if (resolveInfos == null || resolveInfos.size() != 1) {
+ if (resolveInfos.size() != 1) {
// What? this doesn't do anything.
// Log.e("MogaHack", "Somebody is trying to intercept our intent. Disabling MOGA controller for security.");
}
diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java
index e5394565d349..ab4a11fc1982 100644
--- a/android/src/org/ppsspp/ppsspp/NativeActivity.java
+++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java
@@ -275,7 +275,7 @@ private static ArrayList getSdCardPaths(final Context context) {
for (String var : varNames) {
Log.i(TAG, "getSdCardPaths: Checking env " + var);
String secStore = System.getenv("SECONDARY_STORAGE");
- if (secStore != null && secStore.length() > 0) {
+ if (secStore != null && !secStore.isEmpty()) {
list = new ArrayList();
list.add(secStore);
break;
@@ -573,10 +573,8 @@ private void updateSystemUiVisibility() {
// Need API 11 to check for existence of a vibrator? Zany.
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void checkForVibrator() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- if (!vibrator.hasVibrator()) {
- vibrator = null;
- }
+ if (!vibrator.hasVibrator()) {
+ vibrator = null;
}
}
@@ -786,7 +784,7 @@ protected void onDestroy() {
do {
try {
Thread.sleep(10);
- } catch (InterruptedException e) {
+ } catch (InterruptedException ignored) {
}
tries--;
} while (nativeRenderer.isRenderingFrame() && tries > 0);
@@ -979,7 +977,7 @@ protected String getInputDeviceDebugString() {
for (InputDeviceState input : inputPlayers) {
buffer += input.getDebugString();
}
- if (buffer.length() == 0) {
+ if (buffer.isEmpty()) {
buffer = "(no devices)";
}
return buffer;
@@ -997,6 +995,23 @@ public boolean IsXperiaPlay() {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1 && !isXperiaPlay) {
+ Log.i(TAG, "key event" + event.getSource());
+ if (NativeSurfaceView.isFromSource(event, InputDevice.SOURCE_MOUSE)) {
+ Log.i(TAG, "Forwarding key event from mouse");
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ // Probably a right click
+ switch (event.getAction()) {
+ case KeyEvent.ACTION_DOWN:
+ NativeApp.mouse(-1, -1, 2, 1);
+ break;
+ case KeyEvent.ACTION_UP:
+ NativeApp.mouse(-1, -1, 2, 2);
+ break;
+ }
+ }
+ return true;
+ }
+
InputDeviceState state = getInputDeviceState(event);
if (state == null) {
return super.dispatchKeyEvent(event);
@@ -1067,17 +1082,15 @@ void sendMouseDelta(float dx, float dy) {
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
public boolean onGenericMotionEvent(MotionEvent event) {
- // Log.d(TAG, "onGenericMotionEvent: " + event);
+ // Log.i(TAG, "NativeActivity onGenericMotionEvent: " + event);
if (InputDeviceState.inputSourceIsJoystick(event.getSource())) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
- InputDeviceState state = getInputDeviceState(event);
- if (state == null) {
- Log.w(TAG, "Joystick event but failed to get input device state.");
- return super.onGenericMotionEvent(event);
- }
- state.onJoystickMotion(event);
- return true;
+ InputDeviceState state = getInputDeviceState(event);
+ if (state == null) {
+ Log.w(TAG, "Joystick event but failed to get input device state.");
+ return super.onGenericMotionEvent(event);
}
+ state.onJoystickMotion(event);
+ return true;
}
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
@@ -1092,12 +1105,30 @@ public boolean onGenericMotionEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_HOVER_MOVE:
// process the mouse hover movement...
+ NativeApp.mouse(event.getX(), event.getY(), 0, 0);
return true;
case MotionEvent.ACTION_SCROLL:
NativeApp.mouseWheelEvent(event.getAxisValue(MotionEvent.AXIS_HSCROLL), event.getAxisValue(MotionEvent.AXIS_VSCROLL));
return true;
}
}
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_BUTTON_PRESS: {
+ int button = event.getActionButton();
+ NativeApp.mouse(event.getX(), event.getY(), button, 1);
+ return true;
+ }
+ case MotionEvent.ACTION_BUTTON_RELEASE: {
+ int button = event.getActionButton();
+ NativeApp.mouse(event.getX(), event.getY(), button, 2);
+ return true;
+ }
+ default:
+ break;
+ }
+ }
return super.onGenericMotionEvent(event);
}
diff --git a/android/src/org/ppsspp/ppsspp/NativeApp.java b/android/src/org/ppsspp/ppsspp/NativeApp.java
index 3944fe73a358..a58a6a86e48a 100644
--- a/android/src/org/ppsspp/ppsspp/NativeApp.java
+++ b/android/src/org/ppsspp/ppsspp/NativeApp.java
@@ -50,6 +50,7 @@ public class NativeApp {
public static native void accelerometer(float x, float y, float z);
+ public static native void mouse(float x, float y, int button, int action);
public static native void mouseDelta(float x, float y);
public static native void sendMessageFromJava(String msg, String arg);
public static native void sendRequestResult(int seqID, boolean result, String value, int iValue);
diff --git a/android/src/org/ppsspp/ppsspp/NativeGLView.java b/android/src/org/ppsspp/ppsspp/NativeGLView.java
index 8686ca7593c0..6451bb822743 100644
--- a/android/src/org/ppsspp/ppsspp/NativeGLView.java
+++ b/android/src/org/ppsspp/ppsspp/NativeGLView.java
@@ -17,6 +17,7 @@
import android.os.Build;
import android.os.Handler;
import android.util.Log;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -60,11 +61,48 @@ private int getToolType(final MotionEvent ev, int pointer) {
return ev.getToolType(pointer);
}
+
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
+ private boolean onMouseEventModern(final MotionEvent ev) {
+ if (!NativeSurfaceView.isFromSource(ev, InputDevice.SOURCE_MOUSE)) {
+ return false;
+ }
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ // Log.i(TAG, "Action down. button state: " + ev.getButtonState());
+ NativeApp.mouse(ev.getX(), ev.getY(), 1, 1);
+ break;
+ }
+ case MotionEvent.ACTION_UP: {
+ // Log.i(TAG, "Action up. button state: " + ev.getButtonState());
+ NativeApp.mouse(ev.getX(), ev.getY(), 1, 2);
+ break;
+ }
+ case MotionEvent.ACTION_MOVE: {
+ // Log.i(TAG, "Action move. button state: " + ev.getButtonState());
+ NativeApp.mouse(ev.getX(), ev.getY(), 0, 0);
+ break;
+ }
+ default: {
+ Log.i(TAG, "Unhandled modern mouse action: " + ev.getAction());
+ break;
+ }
+ }
+ return true;
+ }
+
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(final MotionEvent ev) {
boolean canReadToolType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+ // This is where workable mouse support arrived.
+ if (onMouseEventModern(ev)) {
+ return true;
+ }
+ }
+
for (int i = 0; i < ev.getPointerCount(); i++) {
int pid = ev.getPointerId(i);
int code = 0;
diff --git a/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java
index 3dee26703f2c..398c96c43776 100644
--- a/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java
+++ b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java
@@ -16,6 +16,7 @@
import android.os.Handler;
import android.util.Log;
import android.view.InputDevice;
+import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -66,15 +67,56 @@ private void processMouseDelta(final MotionEvent ev) {
if ((ev.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
float dx = ev.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
float dy = ev.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
+ Log.i(TAG, "Mouse delta: " + dx + " " + dy);
NativeApp.mouseDelta(dx, dy);
}
}
+ public static boolean isFromSource(final InputEvent ev, int source) {
+ return (ev.getSource() & source) == source;
+ }
+
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
+ private boolean onMouseEventModern(final MotionEvent ev) {
+ if (!isFromSource(ev, InputDevice.SOURCE_MOUSE)) {
+ return false;
+ }
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ // Log.i(TAG, "Action down. button state: " + ev.getButtonState());
+ NativeApp.mouse(ev.getX(), ev.getY(), 1, 1);
+ break;
+ }
+ case MotionEvent.ACTION_UP: {
+ // Log.i(TAG, "Action up. button state: " + ev.getButtonState());
+ NativeApp.mouse(ev.getX(), ev.getY(), 1, 2);
+ break;
+ }
+ case MotionEvent.ACTION_MOVE: {
+ // Log.i(TAG, "Action move. button state: " + ev.getButtonState());
+ NativeApp.mouse(ev.getX(), ev.getY(), 0, 0);
+ break;
+ }
+ default: {
+ Log.i(TAG, "Unhandled modern mouse action: " + ev.getAction());
+ break;
+ }
+ }
+ return true;
+ }
+
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(final MotionEvent ev) {
boolean canReadToolType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+ // This is where workable mouse support arrived.
+ if (onMouseEventModern(ev)) {
+ return true;
+ }
+ }
+
for (int i = 0; i < ev.getPointerCount(); i++) {
int pid = ev.getPointerId(i);
int code = 0;
@@ -109,7 +151,6 @@ public boolean onTouchEvent(final MotionEvent ev) {
int tool = getToolType(ev, i);
code |= tool << 10; // We use the Android tool type codes
}
- // Can't use || due to short circuit evaluation
NativeApp.touch(ev.getX(i), ev.getY(i), code, pid);
}
}