From 387fa5dcfbe7fc20a06f0bf8654f110ca61dd393 Mon Sep 17 00:00:00 2001 From: Joseba Garc?a Etxebarria Date: Tue, 24 Mar 2015 20:45:29 +0100 Subject: [PATCH] * Improve mouse support in Android. These changes require Android API v12 to compile --- .../src/org/libsdl/app/SDLActivity.java | 123 ++++++++++++------ include/SDL_hints.h | 12 ++ src/core/android/SDL_android.c | 17 +++ src/video/android/SDL_androidmouse.c | 85 ++++++++++++ src/video/android/SDL_androidmouse.h | 31 +++++ src/video/android/SDL_androidtouch.c | 32 +++-- 6 files changed, 249 insertions(+), 51 deletions(-) create mode 100644 src/video/android/SDL_androidmouse.c create mode 100644 src/video/android/SDL_androidmouse.h diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java index a39d05ef1..71280d1b3 100644 --- a/android-project/src/org/libsdl/app/SDLActivity.java +++ b/android-project/src/org/libsdl/app/SDLActivity.java @@ -401,6 +401,7 @@ public class SDLActivity extends Activity { public static native void onNativeKeyDown(int keycode); public static native void onNativeKeyUp(int keycode); public static native void onNativeKeyboardFocusLost(); + public static native void onNativeMouse(int button, int action, float x, float y); public static native void onNativeTouch(int touchDevId, int pointerFingerId, int action, float x, float y, float p); @@ -1087,8 +1088,8 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, // Dispatch the different events depending on where they come from // Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD // So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD - - if ( (event.getSource() & 0x00000401) != 0 || /* API 12: SOURCE_GAMEPAD */ + + if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 || (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) { @@ -1125,50 +1126,58 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, final int pointerCount = event.getPointerCount(); int action = event.getActionMasked(); int pointerFingerId; + int mouseButton; int i = -1; float x,y,p; - - switch(action) { - case MotionEvent.ACTION_MOVE: - for (i = 0; i < pointerCount; i++) { + + if (event.getSource() == InputDevice.SOURCE_MOUSE && + SDLActivity.nativeGetHint("SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH").equals("1")) { + mouseButton = 1; // For Android==12 all mouse buttons are the left button + + SDLActivity.onNativeMouse(mouseButton, action, event.getX(0), event.getY(0)); + } else { + switch(action) { + case MotionEvent.ACTION_MOVE: + for (i = 0; i < pointerCount; i++) { + pointerFingerId = event.getPointerId(i); + x = event.getX(i) / mWidth; + y = event.getY(i) / mHeight; + p = event.getPressure(i); + SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); + } + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_DOWN: + // Primary pointer up/down, the index is always zero + i = 0; + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_POINTER_DOWN: + // Non primary pointer up/down + if (i == -1) { + i = event.getActionIndex(); + } + pointerFingerId = event.getPointerId(i); x = event.getX(i) / mWidth; y = event.getY(i) / mHeight; p = event.getPressure(i); SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); - } - break; - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_DOWN: - // Primary pointer up/down, the index is always zero - i = 0; - case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_POINTER_DOWN: - // Non primary pointer up/down - if (i == -1) { - i = event.getActionIndex(); - } + break; - pointerFingerId = event.getPointerId(i); - x = event.getX(i) / mWidth; - y = event.getY(i) / mHeight; - p = event.getPressure(i); - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); - break; - - case MotionEvent.ACTION_CANCEL: - for (i = 0; i < pointerCount; i++) { - pointerFingerId = event.getPointerId(i); - x = event.getX(i) / mWidth; - y = event.getY(i) / mHeight; - p = event.getPressure(i); - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p); - } - break; + case MotionEvent.ACTION_CANCEL: + for (i = 0; i < pointerCount; i++) { + pointerFingerId = event.getPointerId(i); + x = event.getX(i) / mWidth; + y = event.getY(i) / mHeight; + p = event.getPressure(i); + SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p); + } + break; - default: - break; + default: + break; + } } return true; @@ -1497,11 +1506,47 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler { } } -class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener { +class SDLGenericMotionListener implements View.OnGenericMotionListener { // Generic Motion (mouse hover, joystick...) events go here // We only have joysticks yet @Override public boolean onGenericMotion(View v, MotionEvent event) { - return SDLActivity.handleJoystickMotionEvent(event); + float x, y; + int mouseButton; + int action; + + switch ( event.getSource() ) { + case InputDevice.SOURCE_JOYSTICK: + case InputDevice.SOURCE_GAMEPAD: + case InputDevice.SOURCE_DPAD: + SDLActivity.handleJoystickMotionEvent(event); + return true; + + case InputDevice.SOURCE_MOUSE: + action = event.getActionMasked(); + switch(event.getActionMasked()) { + case MotionEvent.ACTION_SCROLL: + x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0); + y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0); + SDLActivity.onNativeMouse(0, action, x, y); + return true; + + case MotionEvent.ACTION_HOVER_MOVE: + x = event.getX(0); + y = event.getY(0); + + SDLActivity.onNativeMouse(0, action, x, y); + return true; + + default: + break; + } + + default: + break; + } + + // Event was not managed + return false; } } diff --git a/include/SDL_hints.h b/include/SDL_hints.h index 04a75f1a6..ecc3ba0fd 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -532,6 +532,18 @@ extern "C" { */ #define SDL_HINT_IME_INTERNAL_EDITING "SDL_IME_INTERNAL_EDITING" + /** + * \brief A variable to control whether mouse and touch events are to be treated together or separately + * + * The variable can be set to the following values: + * "0" - Mouse events will be handled as touch events, and touch will raise fake mouse + * events. This is the behaviour of SDL <= 2.0.3. (default) + * "1" - Mouse events will be handled separately from pure touch events. + * + * The value of this hint is used at runtime, so it can be changed at any time. + */ +#define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH" + /** * \brief override the binding element for keyboard inputs for Emscripten builds * diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index b29f7e4ee..8e3d87391 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -32,6 +32,7 @@ #include "../../events/SDL_events_c.h" #include "../../video/android/SDL_androidkeyboard.h" +#include "../../video/android/SDL_androidmouse.h" #include "../../video/android/SDL_androidtouch.h" #include "../../video/android/SDL_androidvideo.h" #include "../../video/android/SDL_androidwindow.h" @@ -293,6 +294,22 @@ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeTouch( Android_OnTouch(touch_device_id_in, pointer_finger_id_in, action, x, y, p); } +/* Mouse */ +JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeMouse( + JNIEnv* env, jclass jcls, + jint button, jint action, jfloat x, jfloat y) +{ + Android_OnMouse(button, action, x, y); +} + +/* Mouse */ +JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeMouse( + JNIEnv* env, jclass jcls, + jint button, jint action, jfloat x, jfloat y) +{ + Android_OnMouse(button, action, x, y); +} + /* Accelerometer */ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeAccel( JNIEnv* env, jclass jcls, diff --git a/src/video/android/SDL_androidmouse.c b/src/video/android/SDL_androidmouse.c new file mode 100644 index 000000000..35bc67555 --- /dev/null +++ b/src/video/android/SDL_androidmouse.c @@ -0,0 +1,85 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_ANDROID + +#include "SDL_androidmouse.h" +#include "SDL_Log.h" + +#include "SDL_events.h" +#include "../../events/SDL_mouse_c.h" + +#include "../../core/android/SDL_android.h" + +#define ACTION_DOWN 0 +#define ACTION_UP 1 +#define ACTION_HOVER_MOVE 7 +#define ACTION_SCROLL 8 +#define BUTTON_PRIMARY 1 +#define BUTTON_SECONDARY 2 +#define BUTTON_TERTIARY 4 + +void Android_OnMouse( int androidButton, int action, float x, float y) { + static Uint8 SDLButton; + + if (!Android_Window) { + return; + } + + switch(action) { + case ACTION_DOWN: + // Determine which button originated the event, and store it for ACTION_UP + SDLButton = SDL_BUTTON_LEFT; + if (androidButton == BUTTON_SECONDARY) { + SDLButton = SDL_BUTTON_RIGHT; + } else if (androidButton == BUTTON_TERTIARY) { + SDLButton = SDL_BUTTON_MIDDLE; + } + SDL_SendMouseMotion(Android_Window, 0, 0, x, y); + SDL_SendMouseButton(Android_Window, 0, SDL_PRESSED, SDLButton); + break; + + case ACTION_UP: + // Android won't give us the button that originated the ACTION_DOWN event, so we'll + // assume it's the one we stored + SDL_SendMouseMotion(Android_Window, 0, 0, x, y); + SDL_SendMouseButton(Android_Window, 0, SDL_RELEASED, SDLButton); + break; + + case ACTION_HOVER_MOVE: + SDL_SendMouseMotion(Android_Window, 0, 0, x, y); + break; + + case ACTION_SCROLL: + SDL_SendMouseWheel(Android_Window, 0, x, y); + break; + + default: + break; + } +} + +#endif /* SDL_VIDEO_DRIVER_ANDROID */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/android/SDL_androidmouse.h b/src/video/android/SDL_androidmouse.h new file mode 100644 index 000000000..ebc6a7a1c --- /dev/null +++ b/src/video/android/SDL_androidmouse.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef _SDL_androidmouse_h +#define _SDL_androidmouse_h + +#include "SDL_androidvideo.h" + +extern void Android_OnMouse( int button, int action, float x, float y); + +#endif /* _SDL_androidmouse_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidtouch.c b/src/video/android/SDL_androidtouch.c index 5f33429b5..4a9266e3f 100644 --- a/src/video/android/SDL_androidtouch.c +++ b/src/video/android/SDL_androidtouch.c @@ -69,6 +69,7 @@ void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int actio SDL_TouchID touchDeviceId = 0; SDL_FingerID fingerId = 0; int window_x, window_y; + char * hint; static SDL_FingerID pointerFingerID = 0; if (!Android_Window) { @@ -81,40 +82,47 @@ void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int actio } fingerId = (SDL_FingerID)pointer_finger_id_in; + hint = SDL_GetHint("SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"); switch (action) { case ACTION_DOWN: /* Primary pointer down */ Android_GetWindowCoordinates(x, y, &window_x, &window_y); - /* send moved event */ - SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y); - /* send mouse down event */ - SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT); + if ((!hint) || (hint && SDL_strcmp(hint, "1") != 0)) { + /* send moved event */ + SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y); + /* send mouse down event */ + SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT); + } pointerFingerID = fingerId; case ACTION_POINTER_DOWN: /* Non primary pointer down */ SDL_SendTouch(touchDeviceId, fingerId, SDL_TRUE, x, y, p); break; - + case ACTION_MOVE: if (!pointerFingerID) { Android_GetWindowCoordinates(x, y, &window_x, &window_y); - /* send moved event */ - SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y); + if ((!hint) || (hint && SDL_strcmp(hint, "1") != 0)) { + /* send moved event */ + SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y); + } } SDL_SendTouchMotion(touchDeviceId, fingerId, x, y, p); break; - + case ACTION_UP: /* Primary pointer up */ - /* send mouse up */ - pointerFingerID = (SDL_FingerID) 0; - SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); + if ((!hint) || (hint && SDL_strcmp(hint, "1") != 0)) { + /* send mouse up */ + pointerFingerID = (SDL_FingerID) 0; + SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); + } case ACTION_POINTER_UP: /* Non primary pointer up */ SDL_SendTouch(touchDeviceId, fingerId, SDL_FALSE, x, y, p); break; - + default: break; }