Skip to content

Commit

Permalink
add support for gamepad
Browse files Browse the repository at this point in the history
  • Loading branch information
ShirosakiMio committed Mar 12, 2024
1 parent 9b4da19 commit 7dea895
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 5 deletions.
10 changes: 10 additions & 0 deletions FCL/src/main/java/com/tungsten/fcl/activity/JVMActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.TextureView;
import android.view.ViewGroup;
Expand Down Expand Up @@ -155,6 +156,15 @@ public boolean dispatchKeyEvent(KeyEvent event) {
return handleEvent;
}

@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
boolean handleEvent = true;
if (menu != null && menuType == MenuType.GAME) {
handleEvent = menu.getInput().handleGenericMotionEvent(event);
}
return handleEvent;
}

@Override
protected void onPostResume() {
super.onPostResume();
Expand Down
141 changes: 136 additions & 5 deletions FCL/src/main/java/com/tungsten/fcl/control/FCLInput.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.tungsten.fcl.control;

import android.view.Choreographer;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
Expand All @@ -10,6 +11,7 @@
import com.tungsten.fclauncher.keycodes.AndroidKeycodeMap;
import com.tungsten.fclauncher.keycodes.FCLKeycodes;
import com.tungsten.fclauncher.bridge.FCLBridge;
import com.tungsten.fclauncher.keycodes.GamepadKeycodeMap;

import java.util.HashMap;

Expand All @@ -26,6 +28,15 @@ public class FCLInput implements View.OnCapturedPointerListener, View.OnGenericM
private final int screenWidth;
private final int screenHeight;

//for gamepad
private int dpadLastKey = -1;
private int currentDirection = -1;
private long lastFrameTime;
private Choreographer choreographer;
private float lastXAxis;
private float lastYAxis;


public static final HashMap<Integer, Integer> MOUSE_MAP = new HashMap<Integer, Integer>() {
{
put(MOUSE_LEFT, FCLBridge.Button1);
Expand Down Expand Up @@ -132,9 +143,20 @@ private boolean handleExternalMouseEvent(MotionEvent event) {

@Override
public boolean onCapturedPointer(View view, MotionEvent event) {
return handleMouse(event, 0);
}

private boolean handleMouse(MotionEvent event, float deltaTimeScale) {
if (menu instanceof GameMenu) {
int deltaX = (int) (event.getX() * ((GameMenu) menu).getMenuSetting().getMouseSensitivity());
int deltaY = (int) (event.getY() * ((GameMenu) menu).getMenuSetting().getMouseSensitivity());
int deltaX;
int deltaY;
if (event != null) {
deltaX = (int) (event.getX() * ((GameMenu) menu).getMenuSetting().getMouseSensitivity());
deltaY = (int) (event.getY() * ((GameMenu) menu).getMenuSetting().getMouseSensitivity());
} else {
deltaX = (int) (lastXAxis * deltaTimeScale * 10 * ((GameMenu) menu).getMenuSetting().getMouseSensitivity());
deltaY = (int) (lastYAxis * deltaTimeScale * 10 * ((GameMenu) menu).getMenuSetting().getMouseSensitivity());
}
if (menu.getCursorMode() == FCLBridge.CursorEnabled) {
int targetX = Math.max(0, Math.min(screenWidth, ((GameMenu) menu).getCursorX() + deltaX));
int targetY = Math.max(0, Math.min(screenHeight, ((GameMenu) menu).getCursorY() + deltaY));
Expand All @@ -153,10 +175,11 @@ public boolean onCapturedPointer(View view, MotionEvent event) {
setPointerId(null);
}
}
return handleExternalMouseEvent(event);
} else {
return false;
if (event != null){
return handleExternalMouseEvent(event);
}
}
return false;
}

@Override
Expand Down Expand Up @@ -187,6 +210,13 @@ public boolean handleKeyEvent(KeyEvent event) {
return true;
}
}
if (event.getDevice() != null && ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)) {
if (event.getRepeatCount() == 0) {
int converted = GamepadKeycodeMap.convert(event.getKeyCode());
sendKeyEvent(converted, event.getAction() == KeyEvent.ACTION_DOWN);
}
return true;
}
if ((event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) == KeyEvent.FLAG_SOFT_KEYBOARD) {
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)
return true;
Expand All @@ -209,4 +239,105 @@ public boolean handleKeyEvent(KeyEvent event) {
}
return true;
}

public boolean handleGenericMotionEvent(MotionEvent event) {
if (event.getDevice() != null && event.getSource() == InputDevice.SOURCE_JOYSTICK) {
if (choreographer == null) {
choreographer = Choreographer.getInstance();
Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doTick();
choreographer.postFrameCallback(this);
}
};
choreographer.postFrameCallback(frameCallback);
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
handleDPad(event);
handleLeftJoyStick(event);
handleRightJoyStick(event);
}
return true;
}
return false;
}

private void handleDPad(MotionEvent event) {
float xAxis = event.getAxisValue(MotionEvent.AXIS_HAT_X);
float yAxis = event.getAxisValue(MotionEvent.AXIS_HAT_Y);
if (Float.compare(xAxis, -1.0f) == 0) {
dpadLastKey = KeyEvent.KEYCODE_DPAD_LEFT;
} else if (Float.compare(xAxis, 1.0f) == 0) {
dpadLastKey = KeyEvent.KEYCODE_DPAD_RIGHT;
} else if (Float.compare(yAxis, -1.0f) == 0) {
dpadLastKey = KeyEvent.KEYCODE_DPAD_UP;
} else if (Float.compare(yAxis, 1.0f) == 0) {
dpadLastKey = KeyEvent.KEYCODE_DPAD_DOWN;
}
sendKeyEvent(GamepadKeycodeMap.convert(dpadLastKey), (xAxis != 0 || yAxis != 0));
}

private void handleLeftJoyStick(MotionEvent event) {
float xAxis = event.getAxisValue(MotionEvent.AXIS_X);
float yAxis = event.getAxisValue(MotionEvent.AXIS_Y);
double dist = Math.hypot(Math.abs(xAxis), Math.abs(yAxis));
//todo: custom deadzone
if (dist >= 0.2) {
double degrees = Math.toDegrees(-Math.atan2(yAxis, xAxis));
if (degrees < 0) {
degrees += 360;
}
int lastDirection = currentDirection;
currentDirection = ((int) ((degrees + 22.5) / 45)) % 8;
sendDirection(lastDirection, false);
sendDirection(currentDirection, true);
} else {
sendDirection(0, false);
sendDirection(2, false);
sendDirection(4, false);
sendDirection(6, false);
}
}

private void sendDirection(int direction, boolean press) {
if ((direction & 1) == 0) {
sendKeyEvent(GamepadKeycodeMap.convert(GamepadKeycodeMap.LEFT_JOYSTICK_RIGHT + direction), press);
} else {
sendKeyEvent(GamepadKeycodeMap.convert(GamepadKeycodeMap.LEFT_JOYSTICK_RIGHT + direction - 1), press);
int keyCode = GamepadKeycodeMap.LEFT_JOYSTICK_RIGHT + direction + 1;
if (keyCode == 2008) {
keyCode = 0;
}
sendKeyEvent(GamepadKeycodeMap.convert(keyCode), press);
}
}

private void doTick() {
long newFrameTime = System.nanoTime();
if (lastXAxis != 0 || lastYAxis != 0) {
newFrameTime = System.nanoTime();
float deltaTimeScale = ((newFrameTime - lastFrameTime) / 16666666f);
handleMouse(null, deltaTimeScale);
}
lastFrameTime = newFrameTime;
}

private void handleRightJoyStick(MotionEvent event) {
float xAxis = event.getAxisValue(MotionEvent.AXIS_Z);
float yAxis = event.getAxisValue(MotionEvent.AXIS_RZ);
double dist = Math.hypot(Math.abs(xAxis), Math.abs(yAxis));
//todo: custom deadzone
if (dist < 0.2) {
lastXAxis = 0;
lastYAxis = 0;
return;
}
if (lastXAxis != xAxis || lastYAxis != yAxis) {
lastXAxis = xAxis;
lastYAxis = yAxis;
doTick();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.tungsten.fclauncher.keycodes;

import android.view.KeyEvent;

import java.util.HashMap;

public class GamepadKeycodeMap {
private static final HashMap<Integer, Integer> KEY_MAP = new HashMap<>();
private static final int MOUSE_LEFT = 1000;
private static final int MOUSE_MIDDLE = 1001;
private static final int MOUSE_RIGHT = 1002;
private static final int MOUSE_SCROLL_UP = 1003;
private static final int MOUSE_SCROLL_DOWN = 1004;
public static final int LEFT_JOYSTICK_RIGHT = 2000;
public static final int LEFT_JOYSTICK_UP = 2002;
public static final int LEFT_JOYSTICK_LEFT = 2004;
public static final int LEFT_JOYSTICK_DOWN = 2006;

private static void add(int key, int value) {
KEY_MAP.put(key, value);
}

//todo: custom keycode
public static void modify(int key, int value) {
KEY_MAP.replace(key, value);
}

public static int convert(int key) {
return KEY_MAP.getOrDefault(key, -1);
}

static {
add(KeyEvent.KEYCODE_BUTTON_A, FCLKeycodes.KEY_SPACE);
add(KeyEvent.KEYCODE_BUTTON_B, FCLKeycodes.KEY_Q);
add(KeyEvent.KEYCODE_BUTTON_X, FCLKeycodes.KEY_E);
add(KeyEvent.KEYCODE_BUTTON_Y, FCLKeycodes.KEY_F);
add(KeyEvent.KEYCODE_BUTTON_L1, MOUSE_SCROLL_UP);
add(KeyEvent.KEYCODE_BUTTON_R1, MOUSE_SCROLL_DOWN);
add(KeyEvent.KEYCODE_BUTTON_L2, MOUSE_LEFT);
add(KeyEvent.KEYCODE_BUTTON_R2, MOUSE_RIGHT);
add(KeyEvent.KEYCODE_BUTTON_THUMBL, FCLKeycodes.KEY_LEFTCTRL);
add(KeyEvent.KEYCODE_BUTTON_THUMBR, FCLKeycodes.KEY_LEFTSHIFT);
add(KeyEvent.KEYCODE_BUTTON_START, FCLKeycodes.KEY_ESC);
add(KeyEvent.KEYCODE_BUTTON_SELECT, FCLKeycodes.KEY_TAB);
add(KeyEvent.KEYCODE_DPAD_UP, FCLKeycodes.KEY_LEFTSHIFT);
add(KeyEvent.KEYCODE_DPAD_DOWN, FCLKeycodes.KEY_O);
add(KeyEvent.KEYCODE_DPAD_LEFT, FCLKeycodes.KEY_J);
add(KeyEvent.KEYCODE_DPAD_RIGHT, FCLKeycodes.KEY_K);
add(LEFT_JOYSTICK_UP, FCLKeycodes.KEY_W);
add(LEFT_JOYSTICK_DOWN, FCLKeycodes.KEY_S);
add(LEFT_JOYSTICK_LEFT, FCLKeycodes.KEY_A);
add(LEFT_JOYSTICK_RIGHT, FCLKeycodes.KEY_D);
}
}

0 comments on commit 7dea895

Please sign in to comment.