diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerDPadView.java b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerDPadView.java new file mode 100644 index 000000000..e81c3c416 --- /dev/null +++ b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerDPadView.java @@ -0,0 +1,166 @@ +package com.github.stenzek.duckstation; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; + +public final class TouchscreenControllerDPadView extends View { + private static final int NUM_DIRECTIONS = 4; + private static final int NUM_POSITIONS = 8; + private static final int DIRECTION_UP = 0; + private static final int DIRECTION_RIGHT = 1; + private static final int DIRECTION_DOWN = 2; + private static final int DIRECTION_LEFT = 3; + + private final Drawable[] mUnpressedDrawables = new Drawable[NUM_DIRECTIONS]; + private final Drawable[] mPressedDrawables = new Drawable[NUM_DIRECTIONS]; + private final int[] mDirectionCodes = new int[] { -1, -1, -1, -1 }; + private final boolean[] mDirectionStates = new boolean[NUM_DIRECTIONS]; + + private boolean mPressed = false; + private int mPointerId = 0; + private int mPointerX = 0; + private int mPointerY = 0; + + private String mConfigName; + private boolean mDefaultVisibility = true; + + private int mControllerIndex = -1; + + private static final int[][] DRAWABLES = { + {R.drawable.ic_controller_up_button,R.drawable.ic_controller_up_button_pressed}, + {R.drawable.ic_controller_right_button,R.drawable.ic_controller_right_button_pressed}, + {R.drawable.ic_controller_down_button,R.drawable.ic_controller_down_button_pressed}, + {R.drawable.ic_controller_left_button,R.drawable.ic_controller_left_button_pressed}, + }; + + + public TouchscreenControllerDPadView(Context context) { + super(context); + init(); + } + + public TouchscreenControllerDPadView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public TouchscreenControllerDPadView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + for (int i = 0; i < NUM_DIRECTIONS; i++) { + mUnpressedDrawables[i] = getContext().getDrawable(DRAWABLES[i][0]); + mPressedDrawables[i] = getContext().getDrawable(DRAWABLES[i][1]); + } + } + + public String getConfigName() { + return mConfigName; + } + public void setConfigName(String configName) { + mConfigName = configName; + } + + public boolean getDefaultVisibility() { return mDefaultVisibility; } + public void setDefaultVisibility(boolean visibility) { mDefaultVisibility = visibility; } + + public void setControllerButtons(int controllerIndex, int leftCode, int rightCode, int upCode, int downCode) { + mControllerIndex = controllerIndex; + mDirectionCodes[DIRECTION_LEFT] = leftCode; + mDirectionCodes[DIRECTION_RIGHT] = rightCode; + mDirectionCodes[DIRECTION_UP] = upCode; + mDirectionCodes[DIRECTION_DOWN] = downCode; + } + + public void setUnpressed() { + if (!mPressed && mPointerX == 0 && mPointerY == 0) + return; + + mPressed = false; + mPointerX = 0; + mPointerY = 0; + updateControllerState(); + invalidate(); + } + + public void setPressed(int pointerId, float pointerX, float pointerY) { + final int posX = (int)(pointerX - getX()); + final int posY = (int)(pointerY - getY()); + + boolean doUpdate = (pointerId != mPointerId || !mPressed || (posX != mPointerX || posY != mPointerY)); + mPointerId = pointerId; + mPointerX = posX; + mPointerY = posY; + mPressed = true; + + if (doUpdate) { + updateControllerState(); + invalidate(); + } + } + + private void updateControllerState() { + final int subX = mPointerX / (getWidth() / 3); + final int subY = mPointerY / (getWidth() / 3); + + mDirectionStates[DIRECTION_UP] = (mPressed && subY == 0); + mDirectionStates[DIRECTION_RIGHT] = (mPressed && subX == 2); + mDirectionStates[DIRECTION_DOWN] = (mPressed && subY == 2); + mDirectionStates[DIRECTION_LEFT] = (mPressed && subX == 0); + + AndroidHostInterface hostInterface = AndroidHostInterface.getInstance(); + for (int i = 0; i < NUM_DIRECTIONS; i++) { + if (mDirectionCodes[i] >= 0) + hostInterface.setControllerButtonState(mControllerIndex, mDirectionCodes[i], mDirectionStates[i]); + } + } + + private void drawDirection(int direction, int subX, int subY, Canvas canvas, int buttonWidth, int buttonHeight) { + final int leftBounds = subX * buttonWidth; + final int rightBounds = leftBounds + buttonWidth; + final int topBounds = subY * buttonHeight; + final int bottomBounds = topBounds + buttonHeight; + + final Drawable drawable = mDirectionStates[direction] ? mPressedDrawables[direction] : mUnpressedDrawables[direction]; + drawable.setBounds(leftBounds, topBounds, rightBounds, bottomBounds); + drawable.draw(canvas); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + final int width = getWidth(); + final int height = getHeight(); + + // Divide it into thirds - draw between. + final int buttonWidth = width / 3; + final int buttonHeight = height / 3; + + drawDirection(DIRECTION_UP, 1, 0, canvas, buttonWidth, buttonHeight); + drawDirection(DIRECTION_RIGHT, 2, 1, canvas, buttonWidth, buttonHeight); + drawDirection(DIRECTION_DOWN, 1, 2, canvas, buttonWidth, buttonHeight); + drawDirection(DIRECTION_LEFT, 0, 1, canvas, buttonWidth, buttonHeight); + } + + public boolean isPressed() { + return mPressed; + } + + public boolean hasPointerId() { + return mPointerId >= 0; + } + + public int getPointerId() { + return mPointerId; + } + + public void setPointerId(int mPointerId) { + this.mPointerId = mPointerId; + } +} diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java index cd55d6d65..0cdeeda82 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java @@ -35,6 +35,7 @@ public class TouchscreenControllerView extends FrameLayout { private View mMainView; private ArrayList mButtonViews = new ArrayList<>(); private ArrayList mAxisViews = new ArrayList<>(); + private TouchscreenControllerDPadView mDPadView = null; private boolean mHapticFeedback; private String mLayoutOrientation; private boolean mEditingLayout = false; @@ -105,6 +106,13 @@ public class TouchscreenControllerView extends FrameLayout { axisView.setTranslationY(0.0f); } + if (mDPadView != null) { + editor.remove(getConfigKeyForXTranslation(mDPadView.getConfigName())); + editor.remove(getConfigKeyForYTranslation(mDPadView.getConfigName())); + mDPadView.setTranslationX(0.0f); + mDPadView.setTranslationY(0.0f); + } + editor.commit(); requestLayout(); } @@ -137,6 +145,18 @@ public class TouchscreenControllerView extends FrameLayout { } } + + if (mDPadView != null) { + try { + mDPadView.setTranslationX(prefs.getFloat(getConfigKeyForXTranslation(mDPadView.getConfigName()), 0.0f)); + mDPadView.setTranslationY(prefs.getFloat(getConfigKeyForYTranslation(mDPadView.getConfigName()), 0.0f)); + + final boolean visible = prefs.getBoolean(getConfigKeyForVisibility(mDPadView.getConfigName()), mDPadView.getDefaultVisibility()); + mDPadView.setVisibility(visible ? VISIBLE : INVISIBLE); + } catch (ClassCastException ex) { + + } + } } private void setOpacity(int opacity) { @@ -160,6 +180,8 @@ public class TouchscreenControllerView extends FrameLayout { for (TouchscreenControllerAxisView axisView : mAxisViews) { axisView.setAlpha(alpha); } + if (mDPadView != null) + mDPadView.setAlpha(alpha); } private String getOrientationString() { @@ -232,10 +254,7 @@ public class TouchscreenControllerView extends FrameLayout { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); - linkButton(mMainView, R.id.controller_button_up, "UpButton", "Up", true, false); - linkButton(mMainView, R.id.controller_button_right, "RightButton", "Right", true, false); - linkButton(mMainView, R.id.controller_button_down, "DownButton", "Down", true, false); - linkButton(mMainView, R.id.controller_button_left, "LeftButton", "Left", true, false); + linkDPadToButtons(mMainView, R.id.controller_dpad, "DPad", "", true); linkButton(mMainView, R.id.controller_button_l1, "L1Button", "L1", true, gliding); linkButton(mMainView, R.id.controller_button_l2, "L2Button", "L2", true, gliding); linkButton(mMainView, R.id.controller_button_select, "SelectButton", "Select", true, gliding); @@ -320,6 +339,27 @@ public class TouchscreenControllerView extends FrameLayout { return true; } + private boolean linkDPadToButtons(View view, int id, String configName, String buttonPrefix, boolean defaultVisibility) { + TouchscreenControllerDPadView dpadView = (TouchscreenControllerDPadView) view.findViewById(id); + if (dpadView == null) + return false; + + dpadView.setConfigName(configName); + dpadView.setDefaultVisibility(defaultVisibility); + mDPadView = dpadView; + + int leftCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Left"); + int rightCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Right"); + int upCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Up"); + int downCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Down"); + Log.i("TouchscreenController", String.format("%s(DPad) -> %d,%d,%d,%d", buttonPrefix, leftCode, rightCode, upCode, downCode)); + if (leftCode < 0 && rightCode < 0 && upCode < 0 && downCode < 0) + return false; + + dpadView.setControllerButtons(mControllerIndex, leftCode, rightCode, upCode, downCode); + return true; + } + private void linkHotkeyButton(View view, int id, String configName, TouchscreenControllerButtonView.Hotkey hotkey, boolean defaultVisibility) { TouchscreenControllerButtonView buttonView = (TouchscreenControllerButtonView) view.findViewById(id); if (buttonView == null) @@ -410,6 +450,17 @@ public class TouchscreenControllerView extends FrameLayout { } } + if (mDPadView != null) { + mDPadView.getHitRect(rect); + if (rect.contains((int) x, (int) y)) { + mMovingView = mDPadView; + mMovingName = mDPadView.getConfigName(); + mMovingLastX = x; + mMovingLastY = y; + return true; + } + } + // nothing.. return true; } @@ -502,6 +553,23 @@ public class TouchscreenControllerView extends FrameLayout { axisView.setUnpressed(); } + if (mDPadView != null && mDPadView.getVisibility() == VISIBLE) { + mDPadView.getHitRect(rect); + + boolean pressed = false; + for (int i = 0; i < pointerCount; i++) { + final int x = (int) event.getX(i); + final int y = (int) event.getY(i); + if (rect.contains(x, y)) { + mDPadView.setPressed(event.getPointerId(i), x, y); + pressed = true; + } + } + + if (!pressed) + mDPadView.setUnpressed(); + } + return true; } @@ -521,6 +589,9 @@ public class TouchscreenControllerView extends FrameLayout { axisView.setUnpressed(); } + if (mDPadView != null) + mDPadView.setUnpressed(); + return true; } diff --git a/android/app/src/main/res/layout/layout_touchscreen_controller_analog_sticks.xml b/android/app/src/main/res/layout/layout_touchscreen_controller_analog_sticks.xml index 70a468ffc..35c275e96 100644 --- a/android/app/src/main/res/layout/layout_touchscreen_controller_analog_sticks.xml +++ b/android/app/src/main/res/layout/layout_touchscreen_controller_analog_sticks.xml @@ -147,57 +147,14 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> - - - - - - - + app:layout_constraintStart_toStartOf="parent" /> - - - + app:layout_constraintStart_toStartOf="parent" /> - - - -