From 9321fcb627fb020fb9b354429f27ab8663a8e629 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 9 Dec 2019 22:18:18 +1000 Subject: [PATCH] Android: Basic game controller input forwarding --- .../duckstation/EmulationActivity.java | 5 +- .../duckstation/EmulationSurfaceView.java | 92 +++++++++++++++++++ .../main/res/layout/activity_emulation.xml | 2 +- 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java index c5249bc9c..142b828c4 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java @@ -50,7 +50,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde */ private static final int UI_ANIMATION_DELAY = 300; private final Handler mHideHandler = new Handler(); - private SurfaceView mContentView; + private EmulationSurfaceView mContentView; private final Runnable mHidePart2Runnable = new Runnable() { @SuppressLint("InlinedApi") @Override @@ -148,6 +148,9 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde mTouchscreenController = new TouchscreenControllerView(this); activityLayout.addView(mTouchscreenController); mTouchscreenController.init(0, "DigitalController", mHostInterface); + + // Hook up controller input. + mContentView.initControllerKeyMapping(mHostInterface, "DigitalController"); } @Override diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java new file mode 100644 index 000000000..9669d1a77 --- /dev/null +++ b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java @@ -0,0 +1,92 @@ +package com.github.stenzek.duckstation; + +import android.content.Context; +import android.util.ArrayMap; +import android.util.AttributeSet; +import android.util.Log; +import android.view.InputDevice; +import android.view.KeyEvent; +import android.view.SurfaceView; + +public class EmulationSurfaceView extends SurfaceView { + public EmulationSurfaceView(Context context) { + super(context); + } + + public EmulationSurfaceView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public EmulationSurfaceView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + private boolean isDPadOrButtonEvent(KeyEvent event) { + final int source = event.getSource(); + return (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD || + (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || + (source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (isDPadOrButtonEvent(event) && event.getRepeatCount() == 0 && + handleControllerKey(keyCode, true)) { + return true; + } + + return super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (isDPadOrButtonEvent(event) && event.getRepeatCount() == 0 && + handleControllerKey(keyCode, false)) { + return true; + } + + return super.onKeyDown(keyCode, event); + } + + private AndroidHostInterface mHostInterface; + private ArrayMap mControllerKeyMapping; + + private void addControllerKeyMapping(int keyCode, String controllerType, String buttonName) { + int mapping = AndroidHostInterface.getControllerButtonCode(controllerType, buttonName); + Log.i("EmulationSurfaceView", String.format("Map %d to %d (%s)", keyCode, mapping, + buttonName)); + if (mapping >= 0) + mControllerKeyMapping.put(keyCode, mapping); + } + + public void initControllerKeyMapping(AndroidHostInterface hostInterface, + String controllerType) { + mHostInterface = hostInterface; + mControllerKeyMapping = new ArrayMap<>(); + + // TODO: Don't hardcode... + addControllerKeyMapping(KeyEvent.KEYCODE_DPAD_UP, controllerType, "Up"); + addControllerKeyMapping(KeyEvent.KEYCODE_DPAD_RIGHT, controllerType, "Right"); + addControllerKeyMapping(KeyEvent.KEYCODE_DPAD_DOWN, controllerType, "Down"); + addControllerKeyMapping(KeyEvent.KEYCODE_DPAD_LEFT, controllerType, "Left"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_L1, controllerType, "L1"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_L2, controllerType, "L2"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_SELECT, controllerType, "Select"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_START, controllerType, "Start"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_Y, controllerType, "Triangle"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_B, controllerType, "Circle"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_A, controllerType, "Cross"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_X, controllerType, "Square"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_R1, controllerType, "R1"); + addControllerKeyMapping(KeyEvent.KEYCODE_BUTTON_R2, controllerType, "R2"); + } + + private boolean handleControllerKey(int keyCode, boolean pressed) { + if (!mControllerKeyMapping.containsKey(keyCode)) + return false; + + final int mapping = mControllerKeyMapping.get(keyCode); + mHostInterface.setControllerButtonState(0, mapping, pressed); + return true; + } +} diff --git a/android/app/src/main/res/layout/activity_emulation.xml b/android/app/src/main/res/layout/activity_emulation.xml index ca8d77394..12493cbca 100644 --- a/android/app/src/main/res/layout/activity_emulation.xml +++ b/android/app/src/main/res/layout/activity_emulation.xml @@ -10,7 +10,7 @@ -