diff --git a/android-project/AndroidManifest.xml b/android-project/AndroidManifest.xml
--- a/android-project/AndroidManifest.xml
+++ b/android-project/AndroidManifest.xml
@@ -34,11 +34,11 @@
-
+
-
+
-
-
+
+
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);
@@ -967,8 +968,8 @@
// 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) {
@@ -1003,70 +1004,82 @@
/* 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++) {
+
+ if (event.getSource() == InputDevice.SOURCE_MOUSE &&
+ SDLActivity.nativeGetHint("SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH").equals("1")) {
+ 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
@@ -1219,7 +1232,7 @@
public native void nativeSetComposingText(String text, int newCursorPosition);
@Override
- public boolean deleteSurroundingText(int beforeLength, int afterLength) {
+ public boolean deleteSurroundingText(int beforeLength, int afterLength) {
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
if (beforeLength == 1 && afterLength == 0) {
// backspace
@@ -1305,14 +1318,14 @@
}
}
}
-
+
mJoysticks.add(joystick);
- SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, 0, -1,
+ SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, 0, -1,
joystick.axes.size(), joystick.hats.size()/2, 0);
}
}
}
-
+
/* Check removed devices */
ArrayList removedDevices = new ArrayList();
for(int i=0; i < mJoysticks.size(); i++) {
@@ -1325,7 +1338,7 @@
removedDevices.add(Integer.valueOf(device_id));
}
}
-
+
for(int i=0; i < removedDevices.size(); i++) {
int device_id = removedDevices.get(i).intValue();
SDLActivity.nativeRemoveJoystick(device_id);
@@ -1335,9 +1348,9 @@
break;
}
}
- }
+ }
}
-
+
protected SDLJoystick getJoystick(int device_id) {
for(int i=0; i < mJoysticks.size(); i++) {
if (mJoysticks.get(i).device_id == device_id) {
@@ -1345,9 +1358,9 @@
}
}
return null;
- }
-
- @Override
+ }
+
+ @Override
public boolean handleMotionEvent(MotionEvent event) {
if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
int actionPointerIndex = event.getActionIndex();
@@ -1374,14 +1387,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/docs/README-android.md b/docs/README-android.md
--- a/docs/README-android.md
+++ b/docs/README-android.md
@@ -1,9 +1,9 @@
-Android
+Android
================================================================================
Requirements:
-Android SDK (version 12 or later)
+Android SDK (version 14 or later)
http://developer.android.com/sdk/index.html
Android NDK r7 or later
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;
}