[Scummvm-git-logs] scummvm master -> 64eb1c0afe0bd8af9cf331b8ec62c0c6eee927d2

antoniou79 a.antoniou79 at gmail.com
Sat Oct 24 23:30:42 UTC 2020


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
64eb1c0afe ANDROID: A tentative handling of handling joystick control


Commit: 64eb1c0afe0bd8af9cf331b8ec62c0c6eee927d2
    https://github.com/scummvm/scummvm/commit/64eb1c0afe0bd8af9cf331b8ec62c0c6eee927d2
Author: antoniou (a.antoniou79 at gmail.com)
Date: 2020-10-25T02:30:32+03:00

Commit Message:
ANDROID: A tentative handling of handling joystick control

Basically as a virtual mouse

Changed paths:
    backends/platform/android/android.cpp
    backends/platform/android/android.h
    backends/platform/android/events.cpp
    backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
    backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java
    backends/platform/android/org/scummvm/scummvm/ScummVMEventsModern.java


diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index 37757bf4ae..69e014e500 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -499,6 +499,24 @@ bool OSystem_Android::getFeatureState(Feature f) {
 	}
 }
 
+// TODO Re-eval if we need this here
+Common::HardwareInputSet *OSystem_Android::getHardwareInputSet() {
+	using namespace Common;
+
+	CompositeHardwareInputSet *inputSet = new CompositeHardwareInputSet();
+	inputSet->addHardwareInputSet(new MouseHardwareInputSet(defaultMouseButtons));
+	inputSet->addHardwareInputSet(new KeyboardHardwareInputSet(defaultKeys, defaultModifiers));
+	inputSet->addHardwareInputSet(new JoystickHardwareInputSet(defaultJoystickButtons, defaultJoystickAxes));
+
+	return inputSet;
+}
+
+// TODO Re-eval if we need this here
+Common::KeymapArray OSystem_Android::getGlobalKeymaps() {
+	Common::KeymapArray globalMaps = BaseBackend::getGlobalKeymaps();
+	return globalMaps;
+}
+
 Common::KeymapperDefaultBindings *OSystem_Android::getKeymapperDefaultBindings() {
 	Common::KeymapperDefaultBindings *keymapperDefaultBindings = new Common::KeymapperDefaultBindings();
 
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index fcd6a89f9a..4dcaea07bc 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -115,6 +115,8 @@ private:
 
 public:
 	virtual bool pollEvent(Common::Event &event) override;
+	virtual Common::HardwareInputSet *getHardwareInputSet() override;
+	virtual Common::KeymapArray getGlobalKeymaps() override;
 	virtual Common::KeymapperDefaultBindings *getKeymapperDefaultBindings() override;
 
 	virtual uint32 getMillis(bool skipRecord = false) override;
diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp
index 42e6045c0a..2a4972e9cb 100644
--- a/backends/platform/android/events.cpp
+++ b/backends/platform/android/events.cpp
@@ -902,22 +902,65 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
 		break;
 
 	case JE_JOYSTICK:
-		e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
 
 		switch (arg1) {
+		// AMOTION_EVENT_ACTION_MOVE is 2 in NDK (https://developer.android.com/ndk/reference/group/input)
 		case AMOTION_EVENT_ACTION_MOVE:
+			e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
 			e.type = Common::EVENT_MOUSEMOVE;
 
 			// already multiplied by 100
 			e.mouse.x += arg2 * _joystick_scale / _eventScaleX;
 			e.mouse.y += arg3 * _joystick_scale / _eventScaleY;
 
+			break;
+		case AKEY_EVENT_ACTION_DOWN:
+			e.type = Common::EVENT_KEYDOWN;
+			break;
+		case AKEY_EVENT_ACTION_UP:
+			e.type = Common::EVENT_KEYUP;
 			break;
 		default:
 			LOGE("unhandled jaction on joystick: %d", arg1);
 			return;
 		}
 
+		if (arg1 != AMOTION_EVENT_ACTION_MOVE) {
+			switch (arg2) {
+			case AKEYCODE_BUTTON_1:
+			case AKEYCODE_BUTTON_2:
+				switch (arg1) {
+				case AKEY_EVENT_ACTION_DOWN:
+					e.type = (arg2 == AKEYCODE_BUTTON_1?
+						  Common::EVENT_LBUTTONDOWN :
+						  Common::EVENT_RBUTTONDOWN);
+					break;
+				case AKEY_EVENT_ACTION_UP:
+					e.type = (arg2 == AKEYCODE_BUTTON_1?
+						  Common::EVENT_LBUTTONUP :
+						  Common::EVENT_RBUTTONUP);
+					break;
+				}
+
+				e.mouse = dynamic_cast<AndroidGraphicsManager *>(_graphicsManager)->getMousePosition();
+
+				break;
+
+			case AKEYCODE_BUTTON_3:
+				e.kbd.keycode = Common::KEYCODE_ESCAPE;
+				e.kbd.ascii = Common::ASCII_ESCAPE;
+				break;
+
+			case AKEYCODE_BUTTON_4:
+				e.type = Common::EVENT_MAINMENU;
+				break;
+
+			default:
+				LOGW("unmapped gamepad key: %d", arg2);
+				return;
+			}
+		}
+
 		pushEvent(e);
 
 		return;
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
index 86901e12f0..ee9453aa8a 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
@@ -404,6 +404,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 
 								public void onText(CharSequence p1) {}
 
+								// TODO - "Swipe" behavior does not seem to work currently. Should we support it?
 								public void swipeLeft() {
 									//Log.d(ScummVM.LOG_TAG, "SHOW KEYBOARD - 001 - swipeLeft");
 								}
@@ -451,7 +452,7 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
 							_screenKeyboard = builtinKeyboard;
 							// TODO better to have specific dimensions in dp and not adjusted to parent
 							//		it may resolve the issue of resizing the keyboard wrongly (smaller) when returning to the suspended Activity in low resolution
-							FrameLayout.LayoutParams sKeyboardLayout = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL | Gravity.FILL_HORIZONTAL);
+							FrameLayout.LayoutParams sKeyboardLayout = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
 
 							_videoLayout.addView(_screenKeyboard, sKeyboardLayout);
 							_videoLayout.bringChildToFront(_screenKeyboard);
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java
index 9080829ff4..79b1ab2c8f 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsBase.java
@@ -4,7 +4,6 @@ import android.os.Handler;
 import android.os.Message;
 import android.content.Context;
 //import android.util.Log;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.KeyCharacterMap;
 import android.view.MotionEvent;
@@ -328,6 +327,13 @@ public class ScummVMEventsBase implements
 		case KeyEvent.KEYCODE_BUTTON_MODE:
 			type = JE_GAMEPAD;
 			break;
+		case KeyEvent.KEYCODE_BUTTON_1:
+		case KeyEvent.KEYCODE_BUTTON_2:
+		case KeyEvent.KEYCODE_BUTTON_3:
+		case KeyEvent.KEYCODE_BUTTON_4:
+			// These are oddly detected with SOURCE_KEYBOARD for joystick so don't bother checking the e.getSource()
+			type = JE_JOYSTICK;
+			break;
 		default:
 			if (e.isSystem()) {
 				type = JE_SYS_KEY;
@@ -337,7 +343,7 @@ public class ScummVMEventsBase implements
 			break;
 		}
 
-//		_scummvm.displayMessageOnOSD("GetKey: " + keyCode + " unic=" + eventUnicodeChar+ " arg3= " + (eventUnicodeChar& KeyCharacterMap.COMBINING_ACCENT_MASK));
+		//_scummvm.displayMessageOnOSD("GetKey: " + keyCode + " unic=" + eventUnicodeChar+ " arg3= " + (eventUnicodeChar& KeyCharacterMap.COMBINING_ACCENT_MASK));
 
 		// look in events.cpp for how this is handled
 		_scummvm.pushEvent(type,
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsModern.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsModern.java
index ccaf7e1167..5ea0e42c9d 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMEventsModern.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEventsModern.java
@@ -1,26 +1,202 @@
 package org.scummvm.scummvm;
 
 import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.InputDevice;
 
+import androidx.annotation.NonNull;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
 // A class that extends the basic ScummVMEventsBase, supporting Android APIs > HONEYCOMB_MR1 (API 12)
 public class ScummVMEventsModern extends ScummVMEventsBase {
 
+	private static final int MSG_REPEAT = 3;
+	private static final int REPEAT_INTERVAL = 20; // ~50 keys per second
+	private static final int REPEAT_START_DELAY = 40;
+
 	public ScummVMEventsModern(Context context, ScummVM scummvm, MouseHelper mouseHelper) {
 		super(context, scummvm, mouseHelper);
 	}
 
+	// Custom handler code (to avoid mem leaks, see warning "This Handler Class Should Be Static Or Leaks Might Occur”) based on:
+	// https://stackoverflow.com/a/27826094
+	public static class ScummVMEventsModernHandler extends Handler {
+
+		private final WeakReference<ScummVMEventsModern> mListenerReference;
+
+		public ScummVMEventsModernHandler(ScummVMEventsModern listener) {
+			mListenerReference = new WeakReference<>(listener);
+		}
+
+		@Override
+		public synchronized void handleMessage(@NonNull Message msg) {
+			ScummVMEventsModern listener = mListenerReference.get();
+			if(listener != null) {
+				switch (msg.what) {
+					case MSG_REPEAT:
+						if (listener.repeatMove()) {
+							Message repeat = Message.obtain(this, MSG_REPEAT);
+							sendMessageDelayed(repeat, REPEAT_INTERVAL);
+						}
+						break;
+				}
+			}
+		}
+
+		public void clear() {
+			this.removeCallbacksAndMessages(null);
+		}
+	}
+
 	@Override
-	public boolean onGenericMotionEvent(MotionEvent e) {
-		if ((e.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
-			_scummvm.pushEvent(JE_JOYSTICK, e.getAction(),
-					   (int)(e.getAxisValue(MotionEvent.AXIS_X)*100),
-					   (int)(e.getAxisValue(MotionEvent.AXIS_Y)*100),
-					   0, 0, 0);
-			return true;
+	public void clearEventHandler() {
+		super.clearEventHandler();
+		mHandler.clear();
+	}
+
+	private ScummVMEventsModernHandler mHandler = new ScummVMEventsModernHandler(this);
+	private float repeatingX = 0.0f;
+	private float repeatingY = 0.0f;
+
+	private static float getCenteredAxis(MotionEvent event, InputDevice device, int axis, int historyPos) {
+		final InputDevice.MotionRange range = device.getMotionRange(axis, event.getSource());
+		final int actionPointerIndex = event.getActionIndex();
+
+		// A joystick at rest does not always report an absolute position of
+		// (0,0). Use the getFlat() method to determine the range of values
+		// bounding the joystick axis center.
+		if (range != null) {
+			final float flat = range.getFlat();
+
+//			if (axis == MotionEvent.AXIS_X
+//				|| axis == MotionEvent.AXIS_HAT_X
+//				|| axis == MotionEvent.AXIS_Z) {
+//				Log.d(ScummVM.LOG_TAG, "Flat X= " + flat);
+//			} else {
+//				Log.d(ScummVM.LOG_TAG, "Flat Y= " + flat);
+//			}
+
+			float axisVal = (historyPos < 0) ? event.getAxisValue( range.getAxis(), actionPointerIndex) : event.getHistoricalAxisValue( range.getAxis(), actionPointerIndex, historyPos);
+			// Normalize
+			final float value =  (axisVal - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
+
+			// Ignore axis values that are within the 'flat' region of the
+			// joystick axis center.
+			if (Math.abs(value) > flat) {
+				return value;
+			}
 		}
+		return 0;
+	}
 
-		return false;
+	private void removeMessages() {
+		if (mHandler != null) {
+			mHandler.removeMessages(MSG_REPEAT);
+		}
+	}
+
+	private boolean repeatMove() {
+		_scummvm.pushEvent(JE_JOYSTICK, MotionEvent.ACTION_MOVE,
+			(int) (repeatingX * 100),
+			(int) (repeatingY * 100),
+			0, 0, 0);
+		return true;
+	}
+
+	private void processJoystickInput(MotionEvent event, int historyPos) {
+
+		InputDevice inputDevice = event.getDevice();
+
+		// Calculate the horizontal distance to move by
+		// using the input value from one of these physical controls:
+		// the left control stick, hat axis, or the right control stick.
+		float x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos);
+		//Log.d(ScummVM.LOG_TAG, "JOYSTICK - LEFT: x= " +x);
+		if (x == 0) {
+			x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos);
+			//Log.d(ScummVM.LOG_TAG, "JOYSTICK - HAT: x= " +x);
+		}
+		if (x == 0) {
+			x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos);
+			//Log.d(ScummVM.LOG_TAG, "JOYSTICK - RIGHT: x= " +x);
+		}
+
+		// Calculate the vertical distance to move by
+		// using the input value from one of these physical controls:
+		// the left control stick, hat switch, or the right control stick.
+		float y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos);
+		//Log.d(ScummVM.LOG_TAG, "JOYSTICK - LEFT: y= " +y);
+		if (y == 0) {
+			y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos);
+			//Log.d(ScummVM.LOG_TAG, "JOYSTICK - HAT: y= " +y);
+		}
+		if (y == 0) {
+			y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos);
+			//Log.d(ScummVM.LOG_TAG, "JOYSTICK - RIGHT: y= " +y);
+		}
+
+		// extra filter to stop repetition in order to avoid cases when android does not send onGenericMotionEvent()
+		// for small x or y (while abs is still larger than range.getflat())
+		// In such case we would end up with a slow moving "mouse" cursor - so we need this extra filter
+		if (Math.abs(x * 100) < 20.0f && Math.abs(y * 100) < 20.0f) {
+			//Log.d(ScummVM.LOG_TAG, "JOYSTICK - pushEvent(): STOPPED: " + (int)(x * 100) + " y= " + (int)(y * 100));
+			removeMessages();
+			// do the move anyway, just don't repeat
+			repeatMove();
+			repeatingX = 0.0f;
+			repeatingY = 0.0f;
+		} else {
+			//Log.d(ScummVM.LOG_TAG, "JOYSTICK - pushEvent(): x= " + (int)(x * 100) + " y= " + (int)(y * 100));
+			if (repeatingX != 0.0f || repeatingY != 0.0f) {
+				// already repeating - just update the movement co-ords
+				repeatingX = x;
+				repeatingY = y;
+			} else {
+				// start repeating
+				//removeMessages();
+				repeatingX = x;
+				repeatingY = y;
+				Message msg = mHandler.obtainMessage(MSG_REPEAT);
+				mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY);
+				repeatMove();
+			}
+		}
+	}
+
+	@Override
+	public boolean onGenericMotionEvent(MotionEvent event) {
+		// Check that the event came from a joystick
+		if (((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
+			 || (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0)) {
+			int action = event.getActionMasked();
+			if (action == MotionEvent.ACTION_MOVE) {
+
+				// Process all historical movement samples in the batch
+				final int historySize = event.getHistorySize();
+
+				// Process the movements starting from the
+				// earliest historical position in the batch
+				for (int i = 0; i < historySize; i++) {
+					// Process the event at historical position i
+					//Log.d(ScummVM.LOG_TAG, "JOYSTICK - onGenericMotionEvent(m) hist: ");
+					processJoystickInput(event, i);
+				}
+
+				// Process the current movement sample in the batch (position -1)
+				//Log.d(ScummVM.LOG_TAG, "JOYSTICK - onGenericMotionEvent(m): "  );
+				processJoystickInput(event, -1);
+				return true;
+			}
+		}
+		// this basically returns false since the super just returns false
+		return super.onGenericMotionEvent(event);
 	}
 }




More information about the Scummvm-git-logs mailing list