# HG changeset patch # User Joseba GarcĂ­a Etxebarria # Date 1410923155 -7200 # Node ID e91573254e9ba894c5fcb5ce57182ea99ca87bed # Parent b664273a455c5db3f6e7b1a408e085872768db69 * Added a SDL_HINT to control if mouse and touch events are to be handled together or separately * Dispatch mouse events as such, if mentioned hint is set diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java --- a/android-project/src/org/libsdl/app/SDLActivity.java +++ b/android-project/src/org/libsdl/app/SDLActivity.java @@ -291,15 +291,16 @@ 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, + int action, float x, float y, float p); public static native void onNativeAccel(float x, float y, float z); public static native void onNativeSurfaceChanged(); public static native void onNativeSurfaceDestroyed(); public static native void nativeFlipBuffers(); - public static native int nativeAddJoystick(int device_id, String name, - int is_accelerometer, int nbuttons, + public static native int nativeAddJoystick(int device_id, String name, + int is_accelerometer, int nbuttons, int naxes, int nhats, int nballs); public static native int nativeRemoveJoystick(int device_id); public static native String nativeGetHint(String name); @@ -814,29 +815,29 @@ // Keep track of the surface size to normalize touch events protected static float mWidth, mHeight; - // Startup + // Startup public SDLSurface(Context context) { super(context); - getHolder().addCallback(this); - + getHolder().addCallback(this); + setFocusable(true); setFocusableInTouchMode(true); requestFocus(); - setOnKeyListener(this); - setOnTouchListener(this); + setOnKeyListener(this); + setOnTouchListener(this); mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); - + if(Build.VERSION.SDK_INT >= 12) { - setOnGenericMotionListener(new SDLGenericMotionListener_API12()); + setOnGenericMotionListener(new SDLGenericMotionListener()); } // Some arbitrary defaults to avoid a potential division by zero mWidth = 1.0f; mHeight = 1.0f; } - + public void handleResume() { setFocusable(true); setFocusableInTouchMode(true); @@ -1002,70 +1003,87 @@ /* Ref: http://developer.android.com/training/gestures/multi.html */ final int touchDevId = event.getDeviceId(); final int pointerCount = event.getPointerCount(); + int hint; 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++) { + + /* Handle mouse and touch events separately if told to do so */ + hint = 0; + if(SDLActivity.nativeGetHint("SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH").equals("1")) { + hint = 1; + } + + if (hint == 1 && event.getSource() == InputDevice.SOURCE_MOUSE) { + mouseButton = 1; // MotionEvent.BUTTON_PRIMARY (API >= 14) + if(Build.VERSION.SDK_INT >= 14) { + mouseButton = event.getButtonState(); + } + + 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(); - } - - 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; + break; - default: - 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; + } } return true; - } + } // Sensor events public void enableSensor(int sensortype, boolean enabled) { // TODO: This uses getDefaultSensor - what if we have >1 accels? if (enabled) { - mSensorManager.registerListener(this, - mSensorManager.getDefaultSensor(sensortype), + mSensorManager.registerListener(this, + mSensorManager.getDefaultSensor(sensortype), SensorManager.SENSOR_DELAY_GAME, null); } else { - mSensorManager.unregisterListener(this, + mSensorManager.unregisterListener(this, mSensorManager.getDefaultSensor(sensortype)); } } - + @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO @@ -1344,9 +1362,9 @@ } } return null; - } - - @Override + } + + @Override public boolean handleMotionEvent(MotionEvent event) { if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) { int actionPointerIndex = event.getActionIndex(); @@ -1360,7 +1378,7 @@ /* Normalize the value to -1...1 */ float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f; SDLActivity.onNativeJoy(joystick.device_id, i, value ); - } + } for (int i = 0; i < joystick.hats.size(); i+=2) { int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) ); int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) ); @@ -1373,14 +1391,50 @@ } } return true; - } + } } -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 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -482,13 +482,25 @@ * * The variable can be set to the following values: * "0" - SDL_TEXTEDITING events are sent, and it is the application's - * responsibility to render the text from these events and + * responsibility to render the text from these events and * differentiate it somehow from committed text. (default) - * "1" - If supported by the IME then SDL_TEXTEDITING events are not sent, + * "1" - If supported by the IME then SDL_TEXTEDITING events are not sent, * and text that is being composed will be rendered in its own UI. */ #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 An enumeration of hint priorities */ diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c --- 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" @@ -294,6 +295,14 @@ 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); +} + /* 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 --- /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 --- /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 --- a/src/video/android/SDL_androidtouch.c +++ b/src/video/android/SDL_androidtouch.c @@ -69,6 +69,7 @@ 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 @@ } 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; }