mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-09 04:32:27 -04:00
Many under the hood improvements:
- CPU overhead reduced - Compatibility increased - Fix digital triggers auto-disabling - Fix KeyEvents from DPAD
This commit is contained in:
parent
51e7c2fce8
commit
b4a21feaea
@ -1,6 +1,8 @@
|
||||
package net.kdt.pojavlaunch.customcontrols.gamepad;
|
||||
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
@ -34,7 +36,7 @@ public class Gamepad {
|
||||
private final BaseMainActivity gameActivity;
|
||||
private final ImageView pointerView;
|
||||
|
||||
private final GamepadDpad gamepadDpad = new GamepadDpad(this);
|
||||
private final GamepadDpad gamepadDpad = new GamepadDpad();
|
||||
|
||||
private final GamepadJoystick leftJoystick;
|
||||
private int currentJoystickDirection = DIRECTION_NONE;
|
||||
@ -55,86 +57,37 @@ public class Gamepad {
|
||||
private GamepadMap currentMap = gameMap;
|
||||
|
||||
private boolean lastGrabbingState = true;
|
||||
private MotionEvent lastMotionEvent = null;
|
||||
private final boolean hasDigitalTriggers;
|
||||
|
||||
private final Thread mouseThread;
|
||||
private final Runnable mouseRunnable;
|
||||
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||
private final Runnable switchStateRunnable;
|
||||
private final Runnable motionEventRunnable;
|
||||
|
||||
public Gamepad(BaseMainActivity gameActivity, InputDevice inputDevice){
|
||||
Toast.makeText(gameActivity.getApplicationContext(),"GAMEPAD CREATED", Toast.LENGTH_LONG).show();
|
||||
|
||||
leftJoystick = new GamepadJoystick(MotionEvent.AXIS_X, MotionEvent.AXIS_Y, inputDevice);
|
||||
rightJoystick = new GamepadJoystick(MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ, inputDevice);
|
||||
hasDigitalTriggers = inputDevice.hasKeys(KeyEvent.KEYCODE_BUTTON_R2)[0];
|
||||
|
||||
this.gameActivity = gameActivity;
|
||||
pointerView = this.gameActivity.findViewById(R.id.console_pointer);
|
||||
pointerView.getDrawable().setFilterBitmap(false);
|
||||
notifyGUISizeChange(gameActivity.getMcScale());
|
||||
|
||||
|
||||
mouseThread = new Thread("Gamepad Thread"){
|
||||
long lastTime = System.nanoTime();
|
||||
final double ticks = 60D;
|
||||
final double ns = 1000000000 / ticks;
|
||||
double delta = 0;
|
||||
Runnable handlerRunnable = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
updateGrabbingState();
|
||||
tick();
|
||||
|
||||
while (!isInterrupted()) {
|
||||
long now = System.nanoTime();
|
||||
delta += (now - lastTime) / ns;
|
||||
lastTime = now;
|
||||
|
||||
if(delta >= 1) {
|
||||
updateGrabbingState();
|
||||
tick();
|
||||
|
||||
delta--;
|
||||
|
||||
try{ sleep(Math.max((long) ( (1 - delta) * (1000/ticks) ), 0)); } catch (InterruptedException e) {e.printStackTrace();}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void tick(){
|
||||
//Update motion events, and the mouse position
|
||||
if(lastMotionEvent != null)gameActivity.runOnUiThread(motionEventRunnable);
|
||||
|
||||
if(lastHorizontalValue != 0 || lastVerticalValue != 0){
|
||||
GamepadJoystick currentJoystick = lastGrabbingState ? leftJoystick : rightJoystick;
|
||||
|
||||
acceleration = (mouseMagnitude - currentJoystick.getDeadzone())/(1 - currentJoystick.getDeadzone());
|
||||
acceleration = Math.pow(acceleration, mouseMaxAcceleration);
|
||||
|
||||
if(acceleration > 1) acceleration = 1;
|
||||
|
||||
|
||||
CallbackBridge.mouseX += Math.cos(mouseAngle) * acceleration * mouseSensitivity;
|
||||
CallbackBridge.mouseY -= Math.sin(mouseAngle) * acceleration * mouseSensitivity;
|
||||
|
||||
gameActivity.runOnUiThread(mouseRunnable);
|
||||
|
||||
if(!lastGrabbingState){
|
||||
CallbackBridge.mouseX = MathUtils.clamp(CallbackBridge.mouseX, 0, CallbackBridge.windowWidth);
|
||||
CallbackBridge.mouseY = MathUtils.clamp(CallbackBridge.mouseY, 0, CallbackBridge.windowHeight);
|
||||
placePointerView((int) (CallbackBridge.mouseX /gameActivity.scaleFactor), (int) (CallbackBridge.mouseY/gameActivity.scaleFactor));
|
||||
}
|
||||
|
||||
gameActivity.mouse_x = CallbackBridge.mouseX;
|
||||
gameActivity.mouse_y = CallbackBridge.mouseY;
|
||||
}
|
||||
|
||||
handler.postDelayed(this, 16);
|
||||
}
|
||||
};
|
||||
mouseThread.setPriority(Thread.MAX_PRIORITY);
|
||||
mouseThread.start();
|
||||
|
||||
handler.postDelayed(handlerRunnable, 16);
|
||||
|
||||
//Initialize runnables to be used by the input system, avoiding generating one each time is better memory.
|
||||
mouseRunnable = () -> CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
switchStateRunnable = () -> {
|
||||
currentMap.resetPressedState();
|
||||
if(lastGrabbingState){
|
||||
@ -155,12 +108,34 @@ public class Gamepad {
|
||||
mouseSensitivity = 14; //sensitivity in game doesn't need to be resolution dependent
|
||||
};
|
||||
|
||||
motionEventRunnable = () -> {
|
||||
updateDirectionalJoystick(lastMotionEvent);
|
||||
updateMouseJoystick(lastMotionEvent);
|
||||
updateAnalogTriggers(lastMotionEvent);
|
||||
gamepadDpad.update(lastMotionEvent);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void tick(){
|
||||
//update mouse position
|
||||
if(lastHorizontalValue != 0 || lastVerticalValue != 0){
|
||||
GamepadJoystick currentJoystick = lastGrabbingState ? leftJoystick : rightJoystick;
|
||||
|
||||
acceleration = (mouseMagnitude - currentJoystick.getDeadzone())/(1 - currentJoystick.getDeadzone());
|
||||
acceleration = Math.pow(acceleration, mouseMaxAcceleration);
|
||||
if(acceleration > 1) acceleration = 1;
|
||||
|
||||
CallbackBridge.mouseX += Math.cos(mouseAngle) * acceleration * mouseSensitivity;
|
||||
CallbackBridge.mouseY -= Math.sin(mouseAngle) * acceleration * mouseSensitivity;
|
||||
|
||||
if(!lastGrabbingState){
|
||||
CallbackBridge.mouseX = MathUtils.clamp(CallbackBridge.mouseX, 0, CallbackBridge.windowWidth);
|
||||
CallbackBridge.mouseY = MathUtils.clamp(CallbackBridge.mouseY, 0, CallbackBridge.windowHeight);
|
||||
placePointerView((int) (CallbackBridge.mouseX /gameActivity.scaleFactor), (int) (CallbackBridge.mouseY/gameActivity.scaleFactor));
|
||||
}
|
||||
|
||||
gameActivity.mouse_x = CallbackBridge.mouseX;
|
||||
gameActivity.mouse_y = CallbackBridge.mouseY;
|
||||
|
||||
//Send the mouse to the game
|
||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -173,13 +148,14 @@ public class Gamepad {
|
||||
}
|
||||
|
||||
public void update(KeyEvent event){
|
||||
gamepadDpad.update(event);
|
||||
sendButton(event);
|
||||
}
|
||||
|
||||
public void update(MotionEvent event){
|
||||
//Motion events are taken into account every 1/60th second
|
||||
lastMotionEvent = event;
|
||||
updateDirectionalJoystick(event);
|
||||
updateMouseJoystick(event);
|
||||
updateAnalogTriggers(event);
|
||||
sendButton(gamepadDpad.convertEvent(event));
|
||||
}
|
||||
|
||||
private void updateMouseJoystick(MotionEvent event){
|
||||
@ -204,8 +180,10 @@ public class Gamepad {
|
||||
}
|
||||
|
||||
private void updateAnalogTriggers(MotionEvent event){
|
||||
getCurrentMap().TRIGGER_LEFT.update(event.getAxisValue(MotionEvent.AXIS_LTRIGGER) > 0.5);
|
||||
getCurrentMap().TRIGGER_RIGHT.update(event.getAxisValue(MotionEvent.AXIS_RTRIGGER) > 0.5);
|
||||
if(!hasDigitalTriggers){
|
||||
getCurrentMap().TRIGGER_LEFT.update((event.getAxisValue(MotionEvent.AXIS_LTRIGGER) > 0.5) || (event.getAxisValue(MotionEvent.AXIS_BRAKE) > 0.5));
|
||||
getCurrentMap().TRIGGER_RIGHT.update((event.getAxisValue(MotionEvent.AXIS_RTRIGGER) > 0.5) || (event.getAxisValue(MotionEvent.AXIS_GAS) > 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyGUISizeChange(int newSize){
|
||||
@ -298,19 +276,19 @@ public class Gamepad {
|
||||
break;
|
||||
|
||||
//DPAD
|
||||
case GamepadDpad.UP:
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
getCurrentMap().DPAD_UP.update(event);
|
||||
break;
|
||||
case GamepadDpad.DOWN:
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
getCurrentMap().DPAD_DOWN.update(event);
|
||||
break;
|
||||
case GamepadDpad.LEFT:
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
getCurrentMap().DPAD_LEFT.update(event);
|
||||
break;
|
||||
case GamepadDpad.RIGHT:
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
getCurrentMap().DPAD_RIGHT.update(event);
|
||||
break;
|
||||
case GamepadDpad.CENTER:
|
||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||
getCurrentMap().DPAD_RIGHT.update(false);
|
||||
getCurrentMap().DPAD_LEFT.update(false);
|
||||
getCurrentMap().DPAD_UP.update(false);
|
||||
|
@ -1,91 +1,77 @@
|
||||
package net.kdt.pojavlaunch.customcontrols.gamepad;
|
||||
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputEvent;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import net.kdt.pojavlaunch.LWJGLGLFWKeycode;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static android.view.InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC;
|
||||
import static android.view.InputDevice.SOURCE_DPAD;
|
||||
import static android.view.KeyEvent.KEYCODE_DPAD_CENTER;
|
||||
import static android.view.KeyEvent.KEYCODE_DPAD_DOWN;
|
||||
import static android.view.KeyEvent.KEYCODE_DPAD_LEFT;
|
||||
import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT;
|
||||
import static android.view.KeyEvent.KEYCODE_DPAD_UP;
|
||||
|
||||
/*
|
||||
Code from the android documentation
|
||||
Reflection is used to avoid memory churning, and only has an negative impact at start
|
||||
*/
|
||||
|
||||
public class GamepadDpad {
|
||||
final static int UP = 999;
|
||||
final static int LEFT = 9999;
|
||||
final static int RIGHT = 99999;
|
||||
final static int DOWN = 999999;
|
||||
final static int CENTER = 9999999;
|
||||
|
||||
int pressedDirection = -1;
|
||||
Gamepad parentPad;
|
||||
KeyEvent dummyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, CENTER);
|
||||
Field eventCodeField;
|
||||
|
||||
private int lastKeycode = KEYCODE_DPAD_CENTER;
|
||||
private KeyEvent dummyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, lastKeycode);
|
||||
private Field eventCodeField;
|
||||
private Field eventActionField;
|
||||
|
||||
{
|
||||
try {
|
||||
eventCodeField = dummyEvent.getClass().getDeclaredField("mKeyCode");
|
||||
eventCodeField.setAccessible(true);
|
||||
|
||||
eventActionField = dummyEvent.getClass().getDeclaredField("mAction");
|
||||
eventActionField.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public GamepadDpad(Gamepad parentPad){
|
||||
this.parentPad = parentPad;
|
||||
}
|
||||
|
||||
public void update(KeyEvent event){
|
||||
|
||||
//TODO check if the event is valid
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
|
||||
pressedDirection = LEFT;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
|
||||
pressedDirection = RIGHT;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
|
||||
pressedDirection = UP;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
|
||||
pressedDirection = DOWN;
|
||||
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) {
|
||||
pressedDirection = CENTER;
|
||||
}
|
||||
|
||||
setDummyEventKeyCode(pressedDirection);
|
||||
parentPad.sendButton(dummyEvent);
|
||||
}
|
||||
|
||||
public void update(MotionEvent event){
|
||||
//TODO check if the event is valid
|
||||
|
||||
public KeyEvent convertEvent(MotionEvent event){
|
||||
// Use the hat axis value to find the D-pad direction
|
||||
float xaxis = event.getAxisValue(MotionEvent.AXIS_HAT_X);
|
||||
float yaxis = event.getAxisValue(MotionEvent.AXIS_HAT_Y);
|
||||
int action = KeyEvent.ACTION_DOWN;
|
||||
|
||||
// Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
|
||||
// LEFT and RIGHT direction accordingly.
|
||||
if (Float.compare(xaxis, -1.0f) == 0) {
|
||||
pressedDirection = LEFT;
|
||||
lastKeycode = KEYCODE_DPAD_LEFT;
|
||||
} else if (Float.compare(xaxis, 1.0f) == 0) {
|
||||
pressedDirection = RIGHT;
|
||||
lastKeycode = KEYCODE_DPAD_RIGHT;
|
||||
}
|
||||
// Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
|
||||
// UP and DOWN direction accordingly.
|
||||
else if (Float.compare(yaxis, -1.0f) == 0) {
|
||||
pressedDirection = UP;
|
||||
lastKeycode = KEYCODE_DPAD_UP;
|
||||
} else if (Float.compare(yaxis, 1.0f) == 0) {
|
||||
pressedDirection = DOWN;
|
||||
lastKeycode = KEYCODE_DPAD_DOWN;
|
||||
}else {
|
||||
pressedDirection = CENTER;
|
||||
//No keycode change
|
||||
action = KeyEvent.ACTION_UP;
|
||||
}
|
||||
|
||||
setDummyEventKeyCode(pressedDirection);
|
||||
parentPad.sendButton(dummyEvent);
|
||||
setDummyEventKeycode(lastKeycode);
|
||||
setDummyEventAction(action);
|
||||
dummyEvent.setSource(SOURCE_DPAD);
|
||||
return dummyEvent;
|
||||
|
||||
}
|
||||
|
||||
private void setDummyEventKeyCode(int fakeKeycode){
|
||||
private void setDummyEventKeycode(int fakeKeycode){
|
||||
try {
|
||||
eventCodeField.setInt(dummyEvent, fakeKeycode);
|
||||
} catch (IllegalAccessException e) {
|
||||
@ -93,6 +79,14 @@ public class GamepadDpad {
|
||||
}
|
||||
}
|
||||
|
||||
private void setDummyEventAction(int action){
|
||||
try {
|
||||
eventActionField.setInt(dummyEvent, action);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDpadEvent(MotionEvent event) {
|
||||
// Check that input comes from a device with directional pads.
|
||||
// And... also the joystick since it declares sometimes as a joystick.
|
||||
|
Loading…
x
Reference in New Issue
Block a user