android: Clean up overlay controls and avoid triggering touch screen when a button is pressed (#6391)

This commit is contained in:
Narr the Reg 2023-04-08 23:28:42 -06:00 committed by GitHub
parent bc5b065abe
commit 90bcf49db0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 386 additions and 352 deletions

View file

@ -342,182 +342,93 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener {
if (isInEditMode()) { if (isInEditMode()) {
return onTouchWhileEditing(event); return onTouchWhileEditing(event);
} }
boolean shouldUpdateView = false;
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));
}
}
}
for (InputOverlayDrawableButton button : overlayButtons) { for (InputOverlayDrawableButton button : overlayButtons) {
// Determine the button state to apply based on the MotionEvent action flag. if (!button.updateStatus(event)) {
switch (event.getAction() & MotionEvent.ACTION_MASK) { continue;
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;
} }
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), button.getStatus());
shouldUpdateView = true;
} }
for (InputOverlayDrawableDpad dpad : overlayDpads) { for (InputOverlayDrawableDpad dpad : overlayDpads) {
// Determine the button state to apply based on the MotionEvent action flag. if (!dpad.updateStatus(event, EmulationMenuSettings.getDpadSlideEnable())) {
switch (event.getAction() & MotionEvent.ACTION_MASK) { continue;
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);
}
}
}
}
} }
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) { for (InputOverlayDrawableJoystick joystick : overlayJoysticks) {
joystick.TrackEvent(event); if (!joystick.updateStatus(event)) {
int axisID = joystick.getId(); continue;
float[] axises = joystick.getAxisValues(); }
int axisID = joystick.getJoystickId();
NativeLibrary 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; 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) { public boolean onTouchWhileEditing(MotionEvent event) {
int pointerIndex = event.getActionIndex(); int pointerIndex = event.getActionIndex();
int fingerPositionX = (int) event.getX(pointerIndex); int fingerPositionX = (int) event.getX(pointerIndex);
@ -587,7 +498,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener {
case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_UP:
if (mDpadBeingConfigured == dpad) { if (mDpadBeingConfigured == dpad) {
// Persist button position by saving new place. // Persist button position by saving new place.
saveControlPosition(mDpadBeingConfigured.getId(0), saveControlPosition(mDpadBeingConfigured.getUpId(),
mDpadBeingConfigured.getBounds().left, mDpadBeingConfigured.getBounds().top, mDpadBeingConfigured.getBounds().left, mDpadBeingConfigured.getBounds().top,
orientation); orientation);
mDpadBeingConfigured = null; mDpadBeingConfigured = null;
@ -615,7 +526,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener {
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_UP:
if (mJoystickBeingConfigured != null) { if (mJoystickBeingConfigured != null) {
saveControlPosition(mJoystickBeingConfigured.getId(), saveControlPosition(mJoystickBeingConfigured.getJoystickId(),
mJoystickBeingConfigured.getBounds().left, mJoystickBeingConfigured.getBounds().left,
mJoystickBeingConfigured.getBounds().top, orientation); mJoystickBeingConfigured.getBounds().top, orientation);
mJoystickBeingConfigured = null; mJoystickBeingConfigured = null;
@ -627,29 +538,6 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener {
return true; 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) { private void addOverlayControls(String orientation) {
if (mPreferences.getBoolean("buttonToggle0", true)) { if (mPreferences.getBoolean("buttonToggle0", true)) {
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_a, overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_a,

View file

@ -13,6 +13,8 @@ import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.view.MotionEvent; import android.view.MotionEvent;
import org.citra.citra_emu.NativeLibrary;
/** /**
* Custom {@link BitmapDrawable} that is capable * Custom {@link BitmapDrawable} that is capable
* of storing it's own ID. * of storing it's own ID.
@ -42,26 +44,45 @@ public final class InputOverlayDrawableButton {
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap); mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap); mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap);
mButtonType = buttonType; mButtonType = buttonType;
mTrackId = -1;
mWidth = mDefaultStateBitmap.getIntrinsicWidth(); mWidth = mDefaultStateBitmap.getIntrinsicWidth();
mHeight = mDefaultStateBitmap.getIntrinsicHeight(); 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() { public boolean updateStatus(MotionEvent event) {
return mButtonType; 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() { if (isActionDown) {
return mTrackId; if (!getBounds().contains(xPosition, yPosition)) {
} return false;
}
mPressedState = true;
mTrackId = pointerId;
return true;
}
public void setTrackId(int trackId) { if (isActionUp) {
mTrackId = trackId; if (mTrackId != pointerId) {
return false;
}
mPressedState = false;
mTrackId = -1;
return true;
}
return false;
} }
public boolean onConfigureTouch(MotionEvent event) { public boolean onConfigureTouch(MotionEvent event) {
@ -104,6 +125,22 @@ public final class InputOverlayDrawableButton {
mPressedStateBitmap.setBounds(left, top, right, bottom); 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() { public Rect getBounds() {
return mDefaultStateBitmap.getBounds(); return mDefaultStateBitmap.getBounds();
} }

View file

@ -13,23 +13,19 @@ import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.view.MotionEvent; import android.view.MotionEvent;
import org.citra.citra_emu.NativeLibrary;
/** /**
* Custom {@link BitmapDrawable} that is capable * Custom {@link BitmapDrawable} that is capable
* of storing it's own ID. * of storing it's own ID.
*/ */
public final class InputOverlayDrawableDpad { 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; public static final float VIRT_AXIS_DEADZONE = 0.5f;
// The ID identifying what type of button this Drawable represents. // 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 mTrackId;
private int mPreviousTouchX, mPreviousTouchY; private int mPreviousTouchX, mPreviousTouchY;
private int mControlPositionX, mControlPositionY; private int mControlPositionX, mControlPositionY;
@ -38,7 +34,10 @@ public final class InputOverlayDrawableDpad {
private BitmapDrawable mDefaultStateBitmap; private BitmapDrawable mDefaultStateBitmap;
private BitmapDrawable mPressedOneDirectionStateBitmap; private BitmapDrawable mPressedOneDirectionStateBitmap;
private BitmapDrawable mPressedTwoDirectionsStateBitmap; private BitmapDrawable mPressedTwoDirectionsStateBitmap;
private int mPressState = STATE_DEFAULT; private boolean mUpButtonState;
private boolean mDownButtonState;
private boolean mLeftButtonState;
private boolean mRightButtonState;
/** /**
* Constructor * Constructor
@ -65,73 +64,167 @@ public final class InputOverlayDrawableDpad {
mWidth = mDefaultStateBitmap.getIntrinsicWidth(); mWidth = mDefaultStateBitmap.getIntrinsicWidth();
mHeight = mDefaultStateBitmap.getIntrinsicHeight(); mHeight = mDefaultStateBitmap.getIntrinsicHeight();
mButtonType[0] = buttonUp; mUpButtonId = buttonUp;
mButtonType[1] = buttonDown; mDownButtonId = buttonDown;
mButtonType[2] = buttonLeft; mLeftButtonId = buttonLeft;
mButtonType[3] = buttonRight; mRightButtonId = buttonRight;
mTrackId = -1; 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) { public void draw(Canvas canvas) {
int px = mControlPositionX + (getWidth() / 2); int px = mControlPositionX + (getWidth() / 2);
int py = mControlPositionY + (getHeight() / 2); int py = mControlPositionY + (getHeight() / 2);
switch (mPressState) {
case STATE_DEFAULT: // Pressed up
mDefaultStateBitmap.draw(canvas); if (mUpButtonState && !mLeftButtonState && !mRightButtonState) {
break; mPressedOneDirectionStateBitmap.draw(canvas);
case STATE_PRESSED_UP: return;
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 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);
} }
/** public int getUpId() {
* Gets one of the InputOverlayDrawableDpad's button IDs. return mUpButtonId;
* }
* @return the requested InputOverlayDrawableDpad's button ID.
*/ public int getDownId() {
public int getId(int direction) { return mDownButtonId;
return mButtonType[direction]; }
public int getLeftId() {
return mLeftButtonId;
}
public int getRightId() {
return mRightButtonId;
} }
public int getTrackId() { public int getTrackId() {
@ -142,6 +235,22 @@ public final class InputOverlayDrawableDpad {
mTrackId = trackId; 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) { public boolean onConfigureTouch(MotionEvent event) {
int pointerIndex = event.getActionIndex(); int pointerIndex = event.getActionIndex();
int fingerPositionX = (int) event.getX(pointerIndex); int fingerPositionX = (int) event.getX(pointerIndex);
@ -187,7 +296,4 @@ public final class InputOverlayDrawableDpad {
return mHeight; return mHeight;
} }
public void setState(int pressState) {
mPressState = pressState;
}
} }

View file

@ -21,10 +21,12 @@ import org.citra.citra_emu.utils.EmulationMenuSettings;
* of storing it's own ID. * of storing it's own ID.
*/ */
public final class InputOverlayDrawableJoystick { public final class InputOverlayDrawableJoystick {
private final int[] axisIDs = {0, 0, 0, 0}; // The ID value what type of joystick this Drawable represents.
private final float[] axises = {0f, 0f}; private int mJoystickId;
private int trackId = -1; // The ID value what motion event is tracking
private int mJoystickType; private int mTrackId = -1;
private float mXAxis;
private float mYAxis;
private int mControlPositionX, mControlPositionY; private int mControlPositionX, mControlPositionY;
private int mPreviousTouchX, mPreviousTouchY; private int mPreviousTouchX, mPreviousTouchY;
private int mWidth; private int mWidth;
@ -51,11 +53,7 @@ public final class InputOverlayDrawableJoystick {
public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter, public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter,
Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed, Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed,
Rect rectOuter, Rect rectInner, int joystick) { Rect rectOuter, Rect rectInner, int joystick) {
axisIDs[0] = joystick + 1; // Up mJoystickId = joystick;
axisIDs[1] = joystick + 2; // Down
axisIDs[2] = joystick + 3; // Left
axisIDs[3] = joystick + 4; // Right
mJoystickType = joystick;
mOuterBitmap = new BitmapDrawable(res, bitmapOuter); mOuterBitmap = new BitmapDrawable(res, bitmapOuter);
mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault); mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault);
@ -74,84 +72,87 @@ public final class InputOverlayDrawableJoystick {
SetInnerBounds(); SetInnerBounds();
} }
/**
* Gets this InputOverlayDrawableJoystick's button ID.
*
* @return this InputOverlayDrawableJoystick's button ID.
*/
public int getId() {
return mJoystickType;
}
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
mOuterBitmap.draw(canvas); mOuterBitmap.draw(canvas);
getCurrentStateBitmapDrawable().draw(canvas); getCurrentStateBitmapDrawable().draw(canvas);
mBoundsBoxBitmap.draw(canvas); mBoundsBoxBitmap.draw(canvas);
} }
public void TrackEvent(MotionEvent event) { public boolean updateStatus(MotionEvent event) {
int pointerIndex = event.getActionIndex(); 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) { if (isActionDown) {
case MotionEvent.ACTION_DOWN: if (!getBounds().contains(xPosition, yPosition)) {
case MotionEvent.ACTION_POINTER_DOWN: return false;
if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) { }
mPressedState = true; mPressedState = true;
mOuterBitmap.setAlpha(0); mOuterBitmap.setAlpha(0);
mBoundsBoxBitmap.setAlpha(255); mBoundsBoxBitmap.setAlpha(255);
if (EmulationMenuSettings.getJoystickRelCenter()) { if (EmulationMenuSettings.getJoystickRelCenter()) {
getVirtBounds().offset((int) event.getX(pointerIndex) - getVirtBounds().centerX(), getVirtBounds().offset(xPosition - getVirtBounds().centerX(),
(int) event.getY(pointerIndex) - getVirtBounds().centerY()); yPosition - getVirtBounds().centerY());
} }
mBoundsBoxBitmap.setBounds(getVirtBounds()); mBoundsBoxBitmap.setBounds(getVirtBounds());
trackId = event.getPointerId(pointerIndex); mTrackId = pointerId;
}
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 (trackId == -1) if (isActionUp) {
return; 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++) { for (int i = 0; i < event.getPointerCount(); i++) {
if (trackId == event.getPointerId(i)) { if (mTrackId != event.getPointerId(i)) {
float touchX = event.getX(i); continue;
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();
} }
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) { public boolean onConfigureTouch(MotionEvent event) {
@ -160,7 +161,7 @@ public final class InputOverlayDrawableJoystick {
int fingerPositionY = (int) event.getY(pointerIndex); int fingerPositionY = (int) event.getY(pointerIndex);
int scale = 1; 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 // C-stick is scaled down to be half the size of the circle pad
scale = 2; scale = 2;
} }
@ -192,23 +193,25 @@ public final class InputOverlayDrawableJoystick {
return true; return true;
} }
public int getJoystickId() {
public float[] getAxisValues() { return mJoystickId;
return axises;
} }
public int[] getAxisIDs() { public float getXAxis() {
return axisIDs; return mXAxis;
}
public float getYAxis() {
return mYAxis;
}
public int getTrackId() {
return mTrackId;
} }
private void SetInnerBounds() { private void SetInnerBounds() {
int X = getVirtBounds().centerX() + (int) ((axises[0]) * (getVirtBounds().width() / 2)); int X = getVirtBounds().centerX() + (int) ((mXAxis) * (getVirtBounds().width() / 2));
int Y = getVirtBounds().centerY() + (int) ((axises[1]) * (getVirtBounds().height() / 2)); int Y = getVirtBounds().centerY() + (int) ((mYAxis) * (getVirtBounds().height() / 2));
if (mJoystickType == ButtonType.STICK_LEFT) {
X += 1;
Y += 1;
}
if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2)) if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2))
X = getVirtBounds().centerX() + (getVirtBounds().width() / 2); X = getVirtBounds().centerX() + (getVirtBounds().width() / 2);