From 90bcf49db089a644f2f34e56ddad986333aeba74 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Sat, 8 Apr 2023 23:28:42 -0600 Subject: [PATCH] android: Clean up overlay controls and avoid triggering touch screen when a button is pressed (#6391) --- .../citra/citra_emu/overlay/InputOverlay.java | 258 +++++------------- .../overlay/InputOverlayDrawableButton.java | 57 +++- .../overlay/InputOverlayDrawableDpad.java | 248 ++++++++++++----- .../overlay/InputOverlayDrawableJoystick.java | 175 ++++++------ 4 files changed, 386 insertions(+), 352 deletions(-) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.java b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.java index cdb2f7666..f3e18afb2 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.java +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.java @@ -342,182 +342,93 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener { if (isInEditMode()) { return onTouchWhileEditing(event); } - - int pointerIndex = event.getActionIndex(); - - if (mPreferences.getBoolean("isTouchEnabled", true)) { - switch (event.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - if (NativeLibrary.onTouchEvent(event.getX(pointerIndex), event.getY(pointerIndex), true)) { - mTouchscreenPointerId = event.getPointerId(pointerIndex); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - if (mTouchscreenPointerId == event.getPointerId(pointerIndex)) { - // We don't really care where the touch has been released. We only care whether it has been - // released or not. - NativeLibrary.onTouchEvent(0, 0, false); - mTouchscreenPointerId = -1; - } - break; - } - - for (int i = 0; i < event.getPointerCount(); i++) { - if (mTouchscreenPointerId == event.getPointerId(i)) { - NativeLibrary.onTouchMoved(event.getX(i), event.getY(i)); - } - } - } - + boolean shouldUpdateView = false; for (InputOverlayDrawableButton button : overlayButtons) { - // Determine the button state to apply based on the MotionEvent action flag. - switch (event.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - // If a pointer enters the bounds of a button, press that button. - if (button.getBounds() - .contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) { - button.setPressedState(true); - button.setTrackId(event.getPointerId(pointerIndex)); - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), - ButtonState.PRESSED); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - // If a pointer ends, release the button it was pressing. - if (button.getTrackId() == event.getPointerId(pointerIndex)) { - button.setPressedState(false); - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), - ButtonState.RELEASED); - } - break; + if (!button.updateStatus(event)) { + continue; } + NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), button.getStatus()); + shouldUpdateView = true; } for (InputOverlayDrawableDpad dpad : overlayDpads) { - // Determine the button state to apply based on the MotionEvent action flag. - switch (event.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - // If a pointer enters the bounds of a button, press that button. - if (dpad.getBounds() - .contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) { - dpad.setTrackId(event.getPointerId(pointerIndex)); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - // If a pointer ends, release the buttons. - if (dpad.getTrackId() == event.getPointerId(pointerIndex)) { - for (int i = 0; i < 4; i++) { - dpad.setState(InputOverlayDrawableDpad.STATE_DEFAULT); - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i), - NativeLibrary.ButtonState.RELEASED); - } - dpad.setTrackId(-1); - } - break; - } - - if (dpad.getTrackId() != -1) { - for (int i = 0; i < event.getPointerCount(); i++) { - if (dpad.getTrackId() == event.getPointerId(i)) { - float touchX = event.getX(i); - float touchY = event.getY(i); - float maxY = dpad.getBounds().bottom; - float maxX = dpad.getBounds().right; - touchX -= dpad.getBounds().centerX(); - maxX -= dpad.getBounds().centerX(); - touchY -= dpad.getBounds().centerY(); - maxY -= dpad.getBounds().centerY(); - final float AxisX = touchX / maxX; - final float AxisY = touchY / maxY; - - boolean up = false; - boolean down = false; - boolean left = false; - boolean right = false; - if (EmulationMenuSettings.getDpadSlideEnable() || - (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN || - (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { - if (AxisY < -InputOverlayDrawableDpad.VIRT_AXIS_DEADZONE) { - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(0), - NativeLibrary.ButtonState.PRESSED); - up = true; - } else { - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(0), - NativeLibrary.ButtonState.RELEASED); - } - if (AxisY > InputOverlayDrawableDpad.VIRT_AXIS_DEADZONE) { - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(1), - NativeLibrary.ButtonState.PRESSED); - down = true; - } else { - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(1), - NativeLibrary.ButtonState.RELEASED); - } - if (AxisX < -InputOverlayDrawableDpad.VIRT_AXIS_DEADZONE) { - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(2), - NativeLibrary.ButtonState.PRESSED); - left = true; - } else { - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(2), - NativeLibrary.ButtonState.RELEASED); - } - if (AxisX > InputOverlayDrawableDpad.VIRT_AXIS_DEADZONE) { - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(3), - NativeLibrary.ButtonState.PRESSED); - right = true; - } else { - NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(3), - NativeLibrary.ButtonState.RELEASED); - } - - // Set state - if (up) { - if (left) - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP_LEFT); - else if (right) - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP_RIGHT); - else - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP); - } else if (down) { - if (left) - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN_LEFT); - else if (right) - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN_RIGHT); - else - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN); - } else if (left) { - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_LEFT); - } else if (right) { - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_RIGHT); - } else { - dpad.setState(InputOverlayDrawableDpad.STATE_DEFAULT); - } - } - } - } + if (!dpad.updateStatus(event, EmulationMenuSettings.getDpadSlideEnable())) { + continue; } + NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getUpId(), dpad.getUpStatus()); + NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getDownId(), dpad.getDownStatus()); + NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getLeftId(), dpad.getLeftStatus()); + NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getRightId(), dpad.getRightStatus()); + shouldUpdateView = true; } for (InputOverlayDrawableJoystick joystick : overlayJoysticks) { - joystick.TrackEvent(event); - int axisID = joystick.getId(); - float[] axises = joystick.getAxisValues(); - + if (!joystick.updateStatus(event)) { + continue; + } + int axisID = joystick.getJoystickId(); NativeLibrary - .onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, axisID, axises[0], axises[1]); + .onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, axisID, joystick.getXAxis(), joystick.getYAxis()); + shouldUpdateView = true; } - invalidate(); + if (shouldUpdateView) { + invalidate(); + } + + if (!mPreferences.getBoolean("isTouchEnabled", true)) { + return true; + } + + int pointerIndex = event.getActionIndex(); + int xPosition = (int) event.getX(pointerIndex); + int yPosition = (int) event.getY(pointerIndex); + int pointerId = event.getPointerId(pointerIndex); + int motionEvent = event.getAction() & MotionEvent.ACTION_MASK; + boolean isActionDown = motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN; + boolean isActionMove = motionEvent == MotionEvent.ACTION_MOVE; + boolean isActionUp = motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP; + + if (isActionDown && !isTouchInputConsumed(pointerId)) { + NativeLibrary.onTouchEvent(xPosition, yPosition, true); + } + + if (isActionMove) { + for (int i = 0; i < event.getPointerCount(); i++) { + int fingerId = event.getPointerId(i); + if (isTouchInputConsumed(fingerId)) { + continue; + } + NativeLibrary.onTouchMoved(xPosition, yPosition); + } + } + + if (isActionUp && !isTouchInputConsumed(pointerId)) { + NativeLibrary.onTouchEvent(0, 0, false); + } return true; } + private boolean isTouchInputConsumed(int trackId) { + for (InputOverlayDrawableButton button : overlayButtons) { + if (button.getTrackId() == trackId) { + return true; + } + } + for (InputOverlayDrawableDpad dpad : overlayDpads) { + if (dpad.getTrackId() == trackId) { + return true; + } + } + for (InputOverlayDrawableJoystick joystick : overlayJoysticks) { + if (joystick.getTrackId() == trackId) { + return true; + } + } + return false; + } + public boolean onTouchWhileEditing(MotionEvent event) { int pointerIndex = event.getActionIndex(); int fingerPositionX = (int) event.getX(pointerIndex); @@ -587,7 +498,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener { case MotionEvent.ACTION_POINTER_UP: if (mDpadBeingConfigured == dpad) { // Persist button position by saving new place. - saveControlPosition(mDpadBeingConfigured.getId(0), + saveControlPosition(mDpadBeingConfigured.getUpId(), mDpadBeingConfigured.getBounds().left, mDpadBeingConfigured.getBounds().top, orientation); mDpadBeingConfigured = null; @@ -615,7 +526,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: if (mJoystickBeingConfigured != null) { - saveControlPosition(mJoystickBeingConfigured.getId(), + saveControlPosition(mJoystickBeingConfigured.getJoystickId(), mJoystickBeingConfigured.getBounds().left, mJoystickBeingConfigured.getBounds().top, orientation); mJoystickBeingConfigured = null; @@ -627,29 +538,6 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener { return true; } - private void setDpadState(InputOverlayDrawableDpad dpad, boolean up, boolean down, boolean left, - boolean right) { - if (up) { - if (left) - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP_LEFT); - else if (right) - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP_RIGHT); - else - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_UP); - } else if (down) { - if (left) - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN_LEFT); - else if (right) - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN_RIGHT); - else - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_DOWN); - } else if (left) { - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_LEFT); - } else if (right) { - dpad.setState(InputOverlayDrawableDpad.STATE_PRESSED_RIGHT); - } - } - private void addOverlayControls(String orientation) { if (mPreferences.getBoolean("buttonToggle0", true)) { overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_a, diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableButton.java b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableButton.java index 81352296c..ec49808af 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableButton.java +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableButton.java @@ -13,6 +13,8 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.view.MotionEvent; +import org.citra.citra_emu.NativeLibrary; + /** * Custom {@link BitmapDrawable} that is capable * of storing it's own ID. @@ -42,26 +44,45 @@ public final class InputOverlayDrawableButton { mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap); mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap); mButtonType = buttonType; + mTrackId = -1; mWidth = mDefaultStateBitmap.getIntrinsicWidth(); mHeight = mDefaultStateBitmap.getIntrinsicHeight(); } /** - * Gets this InputOverlayDrawableButton's button ID. + * Updates button status based on the motion event. * - * @return this InputOverlayDrawableButton's button ID. + * @return true if value was changed */ - public int getId() { - return mButtonType; - } + public boolean updateStatus(MotionEvent event) { + int pointerIndex = event.getActionIndex(); + int xPosition = (int) event.getX(pointerIndex); + int yPosition = (int) event.getY(pointerIndex); + int pointerId = event.getPointerId(pointerIndex); + int motionEvent = event.getAction() & MotionEvent.ACTION_MASK; + boolean isActionDown = motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN; + boolean isActionUp = motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP; - public int getTrackId() { - return mTrackId; - } + if (isActionDown) { + if (!getBounds().contains(xPosition, yPosition)) { + return false; + } + mPressedState = true; + mTrackId = pointerId; + return true; + } - public void setTrackId(int trackId) { - mTrackId = trackId; + if (isActionUp) { + if (mTrackId != pointerId) { + return false; + } + mPressedState = false; + mTrackId = -1; + return true; + } + + return false; } public boolean onConfigureTouch(MotionEvent event) { @@ -104,6 +125,22 @@ public final class InputOverlayDrawableButton { mPressedStateBitmap.setBounds(left, top, right, bottom); } + public int getId() { + return mButtonType; + } + + public int getTrackId() { + return mTrackId; + } + + public void setTrackId(int trackId) { + mTrackId = trackId; + } + + public int getStatus() { + return mPressedState ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED; + } + public Rect getBounds() { return mDefaultStateBitmap.getBounds(); } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableDpad.java b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableDpad.java index 87f3b7cd9..2555b2c52 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableDpad.java +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableDpad.java @@ -13,23 +13,19 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.view.MotionEvent; +import org.citra.citra_emu.NativeLibrary; + /** * Custom {@link BitmapDrawable} that is capable * of storing it's own ID. */ public final class InputOverlayDrawableDpad { - public static final int STATE_DEFAULT = 0; - public static final int STATE_PRESSED_UP = 1; - public static final int STATE_PRESSED_DOWN = 2; - public static final int STATE_PRESSED_LEFT = 3; - public static final int STATE_PRESSED_RIGHT = 4; - public static final int STATE_PRESSED_UP_LEFT = 5; - public static final int STATE_PRESSED_UP_RIGHT = 6; - public static final int STATE_PRESSED_DOWN_LEFT = 7; - public static final int STATE_PRESSED_DOWN_RIGHT = 8; public static final float VIRT_AXIS_DEADZONE = 0.5f; // The ID identifying what type of button this Drawable represents. - private int[] mButtonType = new int[4]; + private int mUpButtonId; + private int mDownButtonId; + private int mLeftButtonId; + private int mRightButtonId; private int mTrackId; private int mPreviousTouchX, mPreviousTouchY; private int mControlPositionX, mControlPositionY; @@ -38,7 +34,10 @@ public final class InputOverlayDrawableDpad { private BitmapDrawable mDefaultStateBitmap; private BitmapDrawable mPressedOneDirectionStateBitmap; private BitmapDrawable mPressedTwoDirectionsStateBitmap; - private int mPressState = STATE_DEFAULT; + private boolean mUpButtonState; + private boolean mDownButtonState; + private boolean mLeftButtonState; + private boolean mRightButtonState; /** * Constructor @@ -65,73 +64,167 @@ public final class InputOverlayDrawableDpad { mWidth = mDefaultStateBitmap.getIntrinsicWidth(); mHeight = mDefaultStateBitmap.getIntrinsicHeight(); - mButtonType[0] = buttonUp; - mButtonType[1] = buttonDown; - mButtonType[2] = buttonLeft; - mButtonType[3] = buttonRight; + mUpButtonId = buttonUp; + mDownButtonId = buttonDown; + mLeftButtonId = buttonLeft; + mRightButtonId = buttonRight; mTrackId = -1; } + public boolean updateStatus(MotionEvent event, boolean dpadSlide) { + int pointerIndex = event.getActionIndex(); + int xPosition = (int) event.getX(pointerIndex); + int yPosition = (int) event.getY(pointerIndex); + int pointerId = event.getPointerId(pointerIndex); + int motionEvent = event.getAction() & MotionEvent.ACTION_MASK; + boolean isActionDown = motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN; + boolean isActionUp = motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP; + + if (isActionDown) { + if (!getBounds().contains(xPosition, yPosition)) { + return false; + } + mTrackId = pointerId; + } + + if (isActionUp) { + if (mTrackId != pointerId) { + return false; + } + mTrackId = -1; + mUpButtonState = false; + mDownButtonState = false; + mLeftButtonState = false; + mRightButtonState = false; + return true; + } + + if (mTrackId == -1) { + return false; + } + + if (!dpadSlide && !isActionDown) { + return false; + } + + for (int i = 0; i < event.getPointerCount(); i++) { + if (mTrackId != event.getPointerId(i)) { + continue; + } + float touchX = event.getX(i); + float touchY = event.getY(i); + float maxY = getBounds().bottom; + float maxX = getBounds().right; + touchX -= getBounds().centerX(); + maxX -= getBounds().centerX(); + touchY -= getBounds().centerY(); + maxY -= getBounds().centerY(); + final float AxisX = touchX / maxX; + final float AxisY = touchY / maxY; + final boolean upState = mUpButtonState; + final boolean downState = mDownButtonState; + final boolean leftState = mLeftButtonState; + final boolean rightState = mRightButtonState; + + mUpButtonState = AxisY < -InputOverlayDrawableDpad.VIRT_AXIS_DEADZONE; + mDownButtonState = AxisY > InputOverlayDrawableDpad.VIRT_AXIS_DEADZONE; + mLeftButtonState = AxisX < -InputOverlayDrawableDpad.VIRT_AXIS_DEADZONE; + mRightButtonState = AxisX > InputOverlayDrawableDpad.VIRT_AXIS_DEADZONE; + return upState != mUpButtonState || downState != mDownButtonState || leftState != mLeftButtonState || rightState != mRightButtonState; + } + + return false; + } + public void draw(Canvas canvas) { int px = mControlPositionX + (getWidth() / 2); int py = mControlPositionY + (getHeight() / 2); - switch (mPressState) { - case STATE_DEFAULT: - mDefaultStateBitmap.draw(canvas); - break; - case STATE_PRESSED_UP: - mPressedOneDirectionStateBitmap.draw(canvas); - break; - case STATE_PRESSED_RIGHT: - canvas.save(); - canvas.rotate(90, px, py); - mPressedOneDirectionStateBitmap.draw(canvas); - canvas.restore(); - break; - case STATE_PRESSED_DOWN: - canvas.save(); - canvas.rotate(180, px, py); - mPressedOneDirectionStateBitmap.draw(canvas); - canvas.restore(); - break; - case STATE_PRESSED_LEFT: - canvas.save(); - canvas.rotate(270, px, py); - mPressedOneDirectionStateBitmap.draw(canvas); - canvas.restore(); - break; - case STATE_PRESSED_UP_LEFT: - mPressedTwoDirectionsStateBitmap.draw(canvas); - break; - case STATE_PRESSED_UP_RIGHT: - canvas.save(); - canvas.rotate(90, px, py); - mPressedTwoDirectionsStateBitmap.draw(canvas); - canvas.restore(); - break; - case STATE_PRESSED_DOWN_RIGHT: - canvas.save(); - canvas.rotate(180, px, py); - mPressedTwoDirectionsStateBitmap.draw(canvas); - canvas.restore(); - break; - case STATE_PRESSED_DOWN_LEFT: - canvas.save(); - canvas.rotate(270, px, py); - mPressedTwoDirectionsStateBitmap.draw(canvas); - canvas.restore(); - break; + + // Pressed up + if (mUpButtonState && !mLeftButtonState && !mRightButtonState) { + mPressedOneDirectionStateBitmap.draw(canvas); + return; } + + // Pressed down + if (mDownButtonState && !mLeftButtonState && !mRightButtonState) { + canvas.save(); + canvas.rotate(180, px, py); + mPressedOneDirectionStateBitmap.draw(canvas); + canvas.restore(); + return; + } + + // Pressed left + if (mLeftButtonState && !mUpButtonState && !mDownButtonState) { + canvas.save(); + canvas.rotate(270, px, py); + mPressedOneDirectionStateBitmap.draw(canvas); + canvas.restore(); + return; + } + + // Pressed right + if (mRightButtonState && !mUpButtonState && !mDownButtonState) { + canvas.save(); + canvas.rotate(90, px, py); + mPressedOneDirectionStateBitmap.draw(canvas); + canvas.restore(); + return; + } + + // Pressed up left + if (mUpButtonState && mLeftButtonState && !mRightButtonState) { + mPressedTwoDirectionsStateBitmap.draw(canvas); + return; + } + + // Pressed up right + if (mUpButtonState && !mLeftButtonState && mRightButtonState) { + canvas.save(); + canvas.rotate(90, px, py); + mPressedTwoDirectionsStateBitmap.draw(canvas); + canvas.restore(); + return; + } + + // Pressed down left + if (mDownButtonState && mLeftButtonState && !mRightButtonState) { + canvas.save(); + canvas.rotate(270, px, py); + mPressedTwoDirectionsStateBitmap.draw(canvas); + canvas.restore(); + return; + } + + // Pressed down right + if (mDownButtonState && !mLeftButtonState && mRightButtonState) { + canvas.save(); + canvas.rotate(180, px, py); + mPressedTwoDirectionsStateBitmap.draw(canvas); + canvas.restore(); + return; + } + + // Not pressed + mDefaultStateBitmap.draw(canvas); } - /** - * Gets one of the InputOverlayDrawableDpad's button IDs. - * - * @return the requested InputOverlayDrawableDpad's button ID. - */ - public int getId(int direction) { - return mButtonType[direction]; + public int getUpId() { + return mUpButtonId; + } + + public int getDownId() { + return mDownButtonId; + } + + public int getLeftId() { + return mLeftButtonId; + } + + public int getRightId() { + return mRightButtonId; } public int getTrackId() { @@ -142,6 +235,22 @@ public final class InputOverlayDrawableDpad { mTrackId = trackId; } + public int getUpStatus() { + return mUpButtonState ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED; + } + + public int getDownStatus() { + return mDownButtonState ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED; + } + + public int getLeftStatus() { + return mLeftButtonState ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED; + } + + public int getRightStatus() { + return mRightButtonState ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED; + } + public boolean onConfigureTouch(MotionEvent event) { int pointerIndex = event.getActionIndex(); int fingerPositionX = (int) event.getX(pointerIndex); @@ -187,7 +296,4 @@ public final class InputOverlayDrawableDpad { return mHeight; } - public void setState(int pressState) { - mPressState = pressState; - } } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableJoystick.java b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableJoystick.java index 956a8b1e9..0f44d5add 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableJoystick.java +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlayDrawableJoystick.java @@ -21,10 +21,12 @@ import org.citra.citra_emu.utils.EmulationMenuSettings; * of storing it's own ID. */ public final class InputOverlayDrawableJoystick { - private final int[] axisIDs = {0, 0, 0, 0}; - private final float[] axises = {0f, 0f}; - private int trackId = -1; - private int mJoystickType; + // The ID value what type of joystick this Drawable represents. + private int mJoystickId; + // The ID value what motion event is tracking + private int mTrackId = -1; + private float mXAxis; + private float mYAxis; private int mControlPositionX, mControlPositionY; private int mPreviousTouchX, mPreviousTouchY; private int mWidth; @@ -51,11 +53,7 @@ public final class InputOverlayDrawableJoystick { public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter, Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed, Rect rectOuter, Rect rectInner, int joystick) { - axisIDs[0] = joystick + 1; // Up - axisIDs[1] = joystick + 2; // Down - axisIDs[2] = joystick + 3; // Left - axisIDs[3] = joystick + 4; // Right - mJoystickType = joystick; + mJoystickId = joystick; mOuterBitmap = new BitmapDrawable(res, bitmapOuter); mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault); @@ -74,84 +72,87 @@ public final class InputOverlayDrawableJoystick { SetInnerBounds(); } - /** - * Gets this InputOverlayDrawableJoystick's button ID. - * - * @return this InputOverlayDrawableJoystick's button ID. - */ - public int getId() { - return mJoystickType; - } - public void draw(Canvas canvas) { mOuterBitmap.draw(canvas); getCurrentStateBitmapDrawable().draw(canvas); mBoundsBoxBitmap.draw(canvas); } - public void TrackEvent(MotionEvent event) { + public boolean updateStatus(MotionEvent event) { int pointerIndex = event.getActionIndex(); + int xPosition = (int) event.getX(pointerIndex); + int yPosition = (int) event.getY(pointerIndex); + int pointerId = event.getPointerId(pointerIndex); + int motionEvent = event.getAction() & MotionEvent.ACTION_MASK; + boolean isActionDown = motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN; + boolean isActionUp = motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP; - switch (event.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) { - mPressedState = true; - mOuterBitmap.setAlpha(0); - mBoundsBoxBitmap.setAlpha(255); - if (EmulationMenuSettings.getJoystickRelCenter()) { - getVirtBounds().offset((int) event.getX(pointerIndex) - getVirtBounds().centerX(), - (int) event.getY(pointerIndex) - getVirtBounds().centerY()); - } - mBoundsBoxBitmap.setBounds(getVirtBounds()); - trackId = event.getPointerId(pointerIndex); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - if (trackId == event.getPointerId(pointerIndex)) { - mPressedState = false; - axises[0] = axises[1] = 0.0f; - mOuterBitmap.setAlpha(255); - mBoundsBoxBitmap.setAlpha(0); - setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right, - mOrigBounds.bottom)); - setBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right, - mOrigBounds.bottom)); - SetInnerBounds(); - trackId = -1; - } - break; + if (isActionDown) { + if (!getBounds().contains(xPosition, yPosition)) { + return false; + } + mPressedState = true; + mOuterBitmap.setAlpha(0); + mBoundsBoxBitmap.setAlpha(255); + if (EmulationMenuSettings.getJoystickRelCenter()) { + getVirtBounds().offset(xPosition - getVirtBounds().centerX(), + yPosition - getVirtBounds().centerY()); + } + mBoundsBoxBitmap.setBounds(getVirtBounds()); + mTrackId = pointerId; } - if (trackId == -1) - return; + if (isActionUp) { + if (mTrackId != pointerId) { + return false; + } + mPressedState = false; + mXAxis = 0.0f; + mYAxis = 0.0f; + mOuterBitmap.setAlpha(255); + mBoundsBoxBitmap.setAlpha(0); + setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right, + mOrigBounds.bottom)); + setBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right, + mOrigBounds.bottom)); + SetInnerBounds(); + mTrackId = -1; + return true; + } + + if (mTrackId == -1) + return false; for (int i = 0; i < event.getPointerCount(); i++) { - if (trackId == event.getPointerId(i)) { - float touchX = event.getX(i); - float touchY = event.getY(i); - float maxY = getVirtBounds().bottom; - float maxX = getVirtBounds().right; - touchX -= getVirtBounds().centerX(); - maxX -= getVirtBounds().centerX(); - touchY -= getVirtBounds().centerY(); - maxY -= getVirtBounds().centerY(); - final float AxisX = touchX / maxX; - final float AxisY = touchY / maxY; - - // Clamp the circle pad input to a circle - final float angle = (float) Math.atan2(AxisY, AxisX); - float radius = (float) Math.sqrt(AxisX * AxisX + AxisY * AxisY); - if(radius > 1.0f) - { - radius = 1.0f; - } - axises[0] = ((float)Math.cos(angle) * radius); - axises[1] = ((float)Math.sin(angle) * radius); - SetInnerBounds(); + if (mTrackId != event.getPointerId(i)) { + continue; } + float touchX = event.getX(i); + float touchY = event.getY(i); + float maxY = getVirtBounds().bottom; + float maxX = getVirtBounds().right; + touchX -= getVirtBounds().centerX(); + maxX -= getVirtBounds().centerX(); + touchY -= getVirtBounds().centerY(); + maxY -= getVirtBounds().centerY(); + final float AxisX = touchX / maxX; + final float AxisY = touchY / maxY; + final float oldXAxis = mXAxis; + final float oldYAxis = mYAxis; + + // Clamp the circle pad input to a circle + final float angle = (float) Math.atan2(AxisY, AxisX); + float radius = (float) Math.sqrt(AxisX * AxisX + AxisY * AxisY); + if (radius > 1.0f) { + radius = 1.0f; + } + mXAxis = ((float) Math.cos(angle) * radius); + mYAxis = ((float) Math.sin(angle) * radius); + SetInnerBounds(); + return oldXAxis != mXAxis && oldYAxis != mYAxis; } + + return false; } public boolean onConfigureTouch(MotionEvent event) { @@ -160,7 +161,7 @@ public final class InputOverlayDrawableJoystick { int fingerPositionY = (int) event.getY(pointerIndex); int scale = 1; - if (mJoystickType == ButtonType.STICK_C) { + if (mJoystickId == ButtonType.STICK_C) { // C-stick is scaled down to be half the size of the circle pad scale = 2; } @@ -192,23 +193,25 @@ public final class InputOverlayDrawableJoystick { return true; } - - public float[] getAxisValues() { - return axises; + public int getJoystickId() { + return mJoystickId; } - public int[] getAxisIDs() { - return axisIDs; + public float getXAxis() { + return mXAxis; + } + + public float getYAxis() { + return mYAxis; + } + + public int getTrackId() { + return mTrackId; } private void SetInnerBounds() { - int X = getVirtBounds().centerX() + (int) ((axises[0]) * (getVirtBounds().width() / 2)); - int Y = getVirtBounds().centerY() + (int) ((axises[1]) * (getVirtBounds().height() / 2)); - - if (mJoystickType == ButtonType.STICK_LEFT) { - X += 1; - Y += 1; - } + int X = getVirtBounds().centerX() + (int) ((mXAxis) * (getVirtBounds().width() / 2)); + int Y = getVirtBounds().centerY() + (int) ((mYAxis) * (getVirtBounds().height() / 2)); if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2)) X = getVirtBounds().centerX() + (getVirtBounds().width() / 2);