diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java index b5451bbfd..26531682d 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java @@ -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); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDpad.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDpad.java index e07692b1e..8cd12c46f 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDpad.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadDpad.java @@ -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.