aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/android/org
diff options
context:
space:
mode:
authorLauri Härsilä2012-10-07 04:53:52 +0300
committerAlyssa Milburn2012-10-19 22:50:09 +0200
commit21093175646b8d359e8108b93e28898ed9695457 (patch)
treee049dbbc84a1eb9599679dc3a254305ad7c34192 /backends/platform/android/org
parentca256a23b31ba10294cf1f426ebefbc070389357 (diff)
downloadscummvm-rg350-21093175646b8d359e8108b93e28898ed9695457.tar.gz
scummvm-rg350-21093175646b8d359e8108b93e28898ed9695457.tar.bz2
scummvm-rg350-21093175646b8d359e8108b93e28898ed9695457.zip
ANDROID: Mouse and stylus support
From pull request #285.
Diffstat (limited to 'backends/platform/android/org')
-rw-r--r--backends/platform/android/org/scummvm/scummvm/MouseHelper.java214
-rw-r--r--backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java21
-rw-r--r--backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java51
3 files changed, 282 insertions, 4 deletions
diff --git a/backends/platform/android/org/scummvm/scummvm/MouseHelper.java b/backends/platform/android/org/scummvm/scummvm/MouseHelper.java
new file mode 100644
index 0000000000..ae30bcd1da
--- /dev/null
+++ b/backends/platform/android/org/scummvm/scummvm/MouseHelper.java
@@ -0,0 +1,214 @@
+package org.scummvm.scummvm;
+
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.SurfaceView;
+import android.view.View;
+
+/**
+ * Contains helper methods for mouse/hover events that were introduced in Android 4.0.
+ *
+ * Mouse (hover) events seem to be a bit arbitrary, so here's couple of scenarios:
+ *
+ *
+ * 1. Galaxy Note 2 (4.1) + stylus:
+ * Tool type: TOOL_TYPE_STYLUS
+ *
+ * Key: 238 ACTION_DOWN (once)
+ * Key: 238 ACTION_UP (once)
+ * Hover: ACTION_HOVER_ENTER (once)
+ * Hover: ACTION_HOVER_MOVE (multiple, while hovering)
+ *
+ * touch screen with the pen:
+ * Hover: ACTION_HOVER_EXIT, ButtonState: 0 (once)
+ * Touch: ACTION_DOWN, ButtonState: 0 (once)
+ * Touch: ACTION_MOVE, ButtonState: 0 (multiple, while pressing)
+ * Touch: ACTION_UP, ButtonState: 0 (once)
+ * Hover: ACTION_HOVER_ENTER (once)
+ *
+ * press the stylus button while hovering:
+ * Hover: ACTION_HOVER_MOVE, ButtonState: 2 (multiple, while pressing button)
+ * Hover: ACTION_HOVER_MOVE, ButtonState: 0 (multiple, after release)
+ *
+ *
+ * 2. Galaxy Note 2 (4.1) + mouse (usb):
+ * Tool type: TOOL_TYPE_MOUSE
+ *
+ * Hover: ACTION_HOVER_ENTER (once)
+ * Hover: ACTION_HOVER_MOVE (multiple, while hovering)
+ *
+ * press left button:
+ * Hover: ACTION_HOVER_EXIT, ButtonState: 1 (once)
+ * Touch: ACTION_DOWN, ButtonState: 1 (once)
+ * Touch: ACTION_MOVE, ButtonState: 1 (multiple, while pressing)
+ * Touch: ACTION_UP, ButtonState: 0 (once)
+ * Hover: ACTION_HOVER_ENTER, ButtonState: 0 (once)
+ *
+ * press right button:
+ * Key: KEYCODE_BACK, ACTION_DOWN
+ * Hover: ACTION_HOVER_MOVE, ButtonState: 2 (multiple, while pressing button)
+ * Hover: ACTION_HOVER_MOVE, ButtonState: 0 (once)
+ * Key: KEYCODE_BACK, ACTION_UP
+ *
+ *
+ * 3. Asus eeePad Transformer Prime running CyanogenMod 10 (Android 4.1) + mouse (usb):
+ * Tool type: TOOL_TYPE_MOUSE
+ *
+ * Hover: ACTION_HOVER_ENTER (once)
+ * Hover: ACTION_HOVER_MOVE (multiple, while hovering)
+ *
+ * press left button:
+ * Hover: ACTION_HOVER_EXIT, ButtonState: 1 (once)
+ * Touch: ACTION_DOWN, ButtonState: 1 (once)
+ * Touch: ACTION_MOVE, ButtonState: 1 (multiple, while pressing)
+ * Touch: ACTION_UP, ButtonState: 0 (once)
+ * Hover: ACTION_HOVER_ENTER, ButtonState: 0 (once)
+ *
+ * press right button:
+ * Hover: ACTION_HOVER_EXIT, ButtonState: 2 (once)
+ * Touch: ACTION_DOWN, ButtonState: 2 (once)
+ * Touch: ACTION_MOVE, ButtonState: 2 (multiple, while pressing)
+ * Touch: ACTION_UP, ButtonState: 0 (once)
+ * Hover: ACTION_HOVER_ENTER, ButtonState: 0 (once)
+ *
+ *
+ * 4. Asus eeePad Transformer Prime running CyanogenMod 10 (Android 4.1) + touchpad:
+ * Tool type: TOOL_TYPE_FINGER
+ *
+ * Hover: ACTION_HOVER_ENTER (once)
+ * Hover: ACTION_HOVER_MOVE (multiple, while hovering)
+ *
+ * press left button:
+ * Hover: ACTION_HOVER_EXIT, ButtonState: 1 (once)
+ * Touch: ACTION_DOWN, ButtonState: 1 (once)
+ * Touch: ACTION_MOVE, ButtonState: 1 (multiple, while pressing)
+ * Touch: ACTION_UP, ButtonState: 0 (once)
+ * Hover: ACTION_HOVER_ENTER, ButtonState: 0 (once)
+ *
+ * press right button:
+ * Hover: ACTION_HOVER_EXIT, ButtonState: 2 (once)
+ * Touch: ACTION_DOWN, ButtonState: 2 (once)
+ * Touch: ACTION_MOVE, ButtonState: 2 (multiple, while pressing)
+ * Touch: ACTION_UP, ButtonState: 0 (once)
+ * Hover: ACTION_HOVER_ENTER, ButtonState: 0 (once)
+ *
+ */
+public class MouseHelper {
+ private View.OnHoverListener _listener;
+ private ScummVM _scummvm;
+ private long _rmbGuardTime;
+ private boolean _rmbPressed;
+ private boolean _lmbPressed;
+
+ /**
+ * Class initialization fails when this throws an exception.
+ * Checking hover availability is done on static class initialization for Android 1.6 compatibility.
+ */
+ static {
+ try {
+ Class.forName("android.view.View$OnHoverListener");
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ * Calling this forces class initialization
+ */
+ public static void checkHoverAvailable() {}
+
+ public MouseHelper(ScummVM scummvm) {
+ _scummvm = scummvm;
+ _listener = createListener();
+ }
+
+ private View.OnHoverListener createListener() {
+ return new View.OnHoverListener() {
+ @Override
+ public boolean onHover(View view, MotionEvent e) {
+ return onTouch(e, true);
+ }
+ };
+ }
+
+ public void attach(SurfaceView main_surface) {
+ main_surface.setOnHoverListener(_listener);
+ }
+
+ public static boolean isMouse(MotionEvent e) {
+ if (e == null) {
+ return false;
+ }
+
+ InputDevice device = e.getDevice();
+
+ if (device == null) {
+ return false;
+ }
+
+ int sources = device.getSources();
+
+ return ((sources & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) ||
+ ((sources & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS) ||
+ ((sources & InputDevice.SOURCE_TOUCHPAD) == InputDevice.SOURCE_TOUCHPAD);
+ }
+
+ public boolean onTouch(MotionEvent e, boolean hover) {
+ _scummvm.pushEvent(ScummVMEvents.JE_MOUSE_MOVE, (int)e.getX(), (int)e.getY(), 0, 0, 0);
+
+ int buttonState = e.getButtonState();
+
+ boolean lmbDown = (buttonState & MotionEvent.BUTTON_PRIMARY) == MotionEvent.BUTTON_PRIMARY;
+
+ if (e.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) {
+ // when using stylus, ButtonState is 0
+ lmbDown = !hover;
+ }
+
+ if (lmbDown) {
+ if (!_lmbPressed) {
+ // left mouse button was pressed just now
+ _scummvm.pushEvent(ScummVMEvents.JE_LMB_DOWN, (int)e.getX(), (int)e.getY(), e.getButtonState(), 0, 0);
+ }
+
+ _lmbPressed = true;
+ } else {
+ if (_lmbPressed) {
+ // left mouse button was released just now
+ _scummvm.pushEvent(ScummVMEvents.JE_LMB_UP, (int)e.getX(), (int)e.getY(), e.getButtonState(), 0, 0);
+ }
+
+ _lmbPressed = false;
+ }
+
+ boolean rmbDown = (buttonState & MotionEvent.BUTTON_SECONDARY) == MotionEvent.BUTTON_SECONDARY;
+ if (rmbDown) {
+ if (!_rmbPressed) {
+ // right mouse button was pressed just now
+ _scummvm.pushEvent(ScummVMEvents.JE_RMB_DOWN, (int)e.getX(), (int)e.getY(), e.getButtonState(), 0, 0);
+ }
+
+ _rmbPressed = true;
+ } else {
+ if (_rmbPressed) {
+ // right mouse button was released just now
+ _scummvm.pushEvent(ScummVMEvents.JE_RMB_UP, (int)e.getX(), (int)e.getY(), e.getButtonState(), 0, 0);
+ _rmbGuardTime = System.currentTimeMillis();
+ }
+
+ _rmbPressed = false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks whether right mouse button is pressed or was pressed just previously. This is used to prevent sending
+ * extra back key on right mouse click which is the default behaviour in some platforms.
+ *
+ * @return true if right mouse button is (or was in the last 200ms) pressed
+ */
+ public boolean getRmbGuard() {
+ return _rmbPressed || _rmbGuardTime + 200 > System.currentTimeMillis();
+ }
+}
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
index fbd6513761..34c6df3a3a 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
@@ -18,6 +18,18 @@ import java.io.File;
public class ScummVMActivity extends Activity {
+ /* Establish whether the hover events are available */
+ private static boolean _hoverAvailable;
+
+ static {
+ try {
+ MouseHelper.checkHoverAvailable(); // this throws exception if we're on too old version
+ _hoverAvailable = true;
+ } catch (Throwable t) {
+ _hoverAvailable = false;
+ }
+ }
+
private class MyScummVM extends ScummVM {
private boolean usingSmallScreen() {
// Multiple screen sizes came in with Android 1.6. Have
@@ -94,6 +106,7 @@ public class ScummVMActivity extends Activity {
private MyScummVM _scummvm;
private ScummVMEvents _events;
+ private MouseHelper _mouseHelper;
private Thread _scummvm_thread;
@Override
@@ -151,7 +164,13 @@ public class ScummVMActivity extends Activity {
"--savepath=" + savePath
});
- _events = new ScummVMEvents(this, _scummvm);
+ Log.d(ScummVM.LOG_TAG, "Hover available: " + _hoverAvailable);
+ if (_hoverAvailable) {
+ _mouseHelper = new MouseHelper(_scummvm);
+ _mouseHelper.attach(main_surface);
+ }
+
+ _events = new ScummVMEvents(this, _scummvm, _mouseHelper);
main_surface.setOnKeyListener(_events);
main_surface.setOnTouchListener(_events);
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java
index 86227b9352..45c1f8bcb5 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java
@@ -2,7 +2,6 @@ package org.scummvm.scummvm;
import android.os.Handler;
import android.os.Message;
-import android.util.Log;
import android.content.Context;
import android.view.KeyEvent;
import android.view.KeyCharacterMap;
@@ -27,16 +26,23 @@ public class ScummVMEvents implements
public static final int JE_DOUBLE_TAP = 6;
public static final int JE_MULTI = 7;
public static final int JE_BALL = 8;
+ public static final int JE_LMB_DOWN = 9;
+ public static final int JE_LMB_UP = 10;
+ public static final int JE_RMB_DOWN = 11;
+ public static final int JE_RMB_UP = 12;
+ public static final int JE_MOUSE_MOVE = 13;
public static final int JE_QUIT = 0x1000;
final protected Context _context;
final protected ScummVM _scummvm;
final protected GestureDetector _gd;
final protected int _longPress;
+ final protected MouseHelper _mouseHelper;
- public ScummVMEvents(Context context, ScummVM scummvm) {
+ public ScummVMEvents(Context context, ScummVM scummvm, MouseHelper mouseHelper) {
_context = context;
_scummvm = scummvm;
+ _mouseHelper = mouseHelper;
_gd = new GestureDetector(context, this);
_gd.setOnDoubleTapListener(this);
@@ -64,7 +70,7 @@ public class ScummVMEvents implements
public void handleMessage(Message msg) {
if (msg.what == MSG_MENU_LONG_PRESS) {
InputMethodManager imm = (InputMethodManager)
- _context.getSystemService(_context.INPUT_METHOD_SERVICE);
+ _context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null)
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
@@ -73,9 +79,30 @@ public class ScummVMEvents implements
};
// OnKeyListener
+ @Override
final public boolean onKey(View v, int keyCode, KeyEvent e) {
final int action = e.getAction();
+ if (keyCode == 238) {
+ // this (undocumented) event is sent when ACTION_HOVER_ENTER or ACTION_HOVER_EXIT occurs
+ return false;
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (action != KeyEvent.ACTION_UP) {
+ // only send event from back button on up event, since down event is sent on right mouse click and
+ // cannot be caught (thus rmb click would send escape key first)
+ return true;
+ }
+
+ if (_mouseHelper != null) {
+ if (_mouseHelper.getRmbGuard()) {
+ // right mouse button was just clicked which sends an extra back button press
+ return true;
+ }
+ }
+ }
+
if (e.isSystem()) {
// filter what we handle
switch (keyCode) {
@@ -160,7 +187,16 @@ public class ScummVMEvents implements
}
// OnTouchListener
+ @Override
final public boolean onTouch(View v, MotionEvent e) {
+ if (_mouseHelper != null) {
+ boolean isMouse = MouseHelper.isMouse(e);
+ if (isMouse) {
+ // mouse button is pressed
+ return _mouseHelper.onTouch(e, false);
+ }
+ }
+
final int action = e.getAction();
// constants from APIv5:
@@ -177,11 +213,13 @@ public class ScummVMEvents implements
}
// OnGestureListener
+ @Override
final public boolean onDown(MotionEvent e) {
_scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0);
return true;
}
+ @Override
final public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
//Log.d(ScummVM.LOG_TAG, String.format("onFling: %s -> %s (%.3f %.3f)",
@@ -191,10 +229,12 @@ public class ScummVMEvents implements
return true;
}
+ @Override
final public void onLongPress(MotionEvent e) {
// disabled, interferes with drag&drop
}
+ @Override
final public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
_scummvm.pushEvent(JE_SCROLL, (int)e1.getX(), (int)e1.getY(),
@@ -203,9 +243,11 @@ public class ScummVMEvents implements
return true;
}
+ @Override
final public void onShowPress(MotionEvent e) {
}
+ @Override
final public boolean onSingleTapUp(MotionEvent e) {
_scummvm.pushEvent(JE_TAP, (int)e.getX(), (int)e.getY(),
(int)(e.getEventTime() - e.getDownTime()), 0, 0);
@@ -214,10 +256,12 @@ public class ScummVMEvents implements
}
// OnDoubleTapListener
+ @Override
final public boolean onDoubleTap(MotionEvent e) {
return true;
}
+ @Override
final public boolean onDoubleTapEvent(MotionEvent e) {
_scummvm.pushEvent(JE_DOUBLE_TAP, (int)e.getX(), (int)e.getY(),
e.getAction(), 0, 0);
@@ -225,6 +269,7 @@ public class ScummVMEvents implements
return true;
}
+ @Override
final public boolean onSingleTapConfirmed(MotionEvent e) {
return true;
}