mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-05 01:38:36 +00:00
ANDROID: A tentative handling of handling joystick control
Basically as a virtual mouse
This commit is contained in:
parent
9045bceac9
commit
64eb1c0afe
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
@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;
|
||||
// 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);
|
||||
}
|
||||
|
||||
return false;
|
||||
@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 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user