From 4b8ae472ab763a63ce53fd3123b587d7873ed28c Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 6 Oct 2020 23:06:41 +1000 Subject: [PATCH] Android: Fix touchscreen controller being limited to touch down/up --- .../TouchscreenControllerButtonView.java | 44 +------------ .../TouchscreenControllerView.java | 64 ++++++++++++++++--- 2 files changed, 59 insertions(+), 49 deletions(-) diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerButtonView.java b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerButtonView.java index b5986e3e0..438b7b8db 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerButtonView.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerButtonView.java @@ -5,6 +5,7 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; import android.view.View; @@ -17,12 +18,6 @@ public class TouchscreenControllerButtonView extends View { private boolean mPressed = false; private int mButtonCode = -1; private String mButtonName = ""; - private ButtonStateChangedListener mListener; - - public interface ButtonStateChangedListener { - void onButtonStateChanged(TouchscreenControllerButtonView view, boolean pressed); - } - public TouchscreenControllerButtonView(Context context) { super(context); @@ -78,41 +73,12 @@ public class TouchscreenControllerButtonView extends View { } } - @Override - public boolean onTouchEvent(MotionEvent event) { - final boolean oldState = mPressed; - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: { - mPressed = true; - invalidate(); - - if (mListener != null && !oldState) - mListener.onButtonStateChanged(this, true); - - return true; - } - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: { - mPressed = false; - invalidate(); - - if (mListener != null && oldState) - mListener.onButtonStateChanged(this, false); - - return true; - } - } - - return super.onTouchEvent(event); - } - public boolean isPressed() { return mPressed; } + public void setPressed(boolean pressed) { mPressed = pressed; invalidate(); } + public String getButtonName() { return mButtonName; } @@ -144,8 +110,4 @@ public class TouchscreenControllerButtonView extends View { public void setUnpressedDrawable(Drawable unpressedDrawable) { mUnpressedDrawable = unpressedDrawable; } - - public void setButtonStateChangedListener(ButtonStateChangedListener listener) { - mListener = listener; - } } 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 1b7f475c4..bee9d8d41 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 @@ -1,18 +1,25 @@ package com.github.stenzek.duckstation; import android.content.Context; +import android.graphics.Rect; +import android.text.method.Touch; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; +import java.util.ArrayList; +import java.util.HashMap; + /** * TODO: document your custom view class. */ -public class TouchscreenControllerView extends FrameLayout implements TouchscreenControllerButtonView.ButtonStateChangedListener { +public class TouchscreenControllerView extends FrameLayout { private int mControllerIndex; private String mControllerType; + private ArrayList mButtonViews = new ArrayList<>(); public TouchscreenControllerView(Context context) { super(context); @@ -32,8 +39,12 @@ public class TouchscreenControllerView extends FrameLayout implements Touchscree LayoutInflater inflater = LayoutInflater.from(getContext()); View view = inflater.inflate(R.layout.layout_touchscreen_controller, this, true); + view.setOnTouchListener((view1, event) -> { + return handleTouchEvent(event); + }); // TODO: Make dynamic, editable. + mButtonViews.clear(); linkButton(view, R.id.controller_button_up, "Up"); linkButton(view, R.id.controller_button_right, "Right"); linkButton(view, R.id.controller_button_down, "Down"); @@ -53,24 +64,61 @@ public class TouchscreenControllerView extends FrameLayout implements Touchscree private void linkButton(View view, int id, String buttonName) { TouchscreenControllerButtonView buttonView = (TouchscreenControllerButtonView) view.findViewById(id); buttonView.setButtonName(buttonName); - buttonView.setButtonStateChangedListener(this); int code = AndroidHostInterface.getInstance().getControllerButtonCode(mControllerType, buttonName); buttonView.setButtonCode(code); Log.i("TouchscreenController", String.format("%s -> %d", buttonName, code)); - if (code < 0) { + if (code >= 0) { + mButtonViews.add(buttonView); + } else { Log.e("TouchscreenController", String.format("Unknown button name '%s' " + "for '%s'", buttonName, mControllerType)); } } + private boolean handleTouchEvent(MotionEvent event) { + switch (event.getActionMasked()) + { + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + { + clearAllButtonPressedStates(); + return true; + } - @Override - public void onButtonStateChanged(TouchscreenControllerButtonView view, boolean pressed) { - if (view.getButtonCode() < 0) - return; + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_MOVE: + { + final int x = (int)event.getX(); + final int y = (int)event.getY(); + Rect rect = new Rect(); + for (TouchscreenControllerButtonView buttonView : mButtonViews) + { + buttonView.getHitRect(rect); + final boolean pressed = rect.contains(x, y); + if (buttonView.isPressed() == pressed) + continue; - AndroidHostInterface.getInstance().setControllerButtonState(mControllerIndex, view.getButtonCode(), pressed); + buttonView.setPressed(pressed); + AndroidHostInterface.getInstance().setControllerButtonState(mControllerIndex, buttonView.getButtonCode(), pressed); + } + + return true; + } + } + + return false; + } + + private void clearAllButtonPressedStates() { + for (TouchscreenControllerButtonView buttonView : mButtonViews) { + if (!buttonView.isPressed()) + continue; + + AndroidHostInterface.getInstance().setControllerButtonState(mControllerIndex, buttonView.getButtonCode(), false); + buttonView.setPressed(false); + } } }