Android: Fix touchscreen controller being limited to touch down/up

This commit is contained in:
Connor McLaughlin 2020-10-06 23:06:41 +10:00
parent e6ef5f1a1c
commit 4b8ae472ab
2 changed files with 59 additions and 49 deletions

View File

@ -5,6 +5,7 @@ import android.content.res.TypedArray;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
@ -17,12 +18,6 @@ public class TouchscreenControllerButtonView extends View {
private boolean mPressed = false; private boolean mPressed = false;
private int mButtonCode = -1; private int mButtonCode = -1;
private String mButtonName = ""; private String mButtonName = "";
private ButtonStateChangedListener mListener;
public interface ButtonStateChangedListener {
void onButtonStateChanged(TouchscreenControllerButtonView view, boolean pressed);
}
public TouchscreenControllerButtonView(Context context) { public TouchscreenControllerButtonView(Context context) {
super(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() { public boolean isPressed() {
return mPressed; return mPressed;
} }
public void setPressed(boolean pressed) { mPressed = pressed; invalidate(); }
public String getButtonName() { public String getButtonName() {
return mButtonName; return mButtonName;
} }
@ -144,8 +110,4 @@ public class TouchscreenControllerButtonView extends View {
public void setUnpressedDrawable(Drawable unpressedDrawable) { public void setUnpressedDrawable(Drawable unpressedDrawable) {
mUnpressedDrawable = unpressedDrawable; mUnpressedDrawable = unpressedDrawable;
} }
public void setButtonStateChangedListener(ButtonStateChangedListener listener) {
mListener = listener;
}
} }

View File

@ -1,18 +1,25 @@
package com.github.stenzek.duckstation; package com.github.stenzek.duckstation;
import android.content.Context; import android.content.Context;
import android.graphics.Rect;
import android.text.method.Touch;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import java.util.ArrayList;
import java.util.HashMap;
/** /**
* TODO: document your custom view class. * TODO: document your custom view class.
*/ */
public class TouchscreenControllerView extends FrameLayout implements TouchscreenControllerButtonView.ButtonStateChangedListener { public class TouchscreenControllerView extends FrameLayout {
private int mControllerIndex; private int mControllerIndex;
private String mControllerType; private String mControllerType;
private ArrayList<TouchscreenControllerButtonView> mButtonViews = new ArrayList<>();
public TouchscreenControllerView(Context context) { public TouchscreenControllerView(Context context) {
super(context); super(context);
@ -32,8 +39,12 @@ public class TouchscreenControllerView extends FrameLayout implements Touchscree
LayoutInflater inflater = LayoutInflater.from(getContext()); LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.layout_touchscreen_controller, this, true); View view = inflater.inflate(R.layout.layout_touchscreen_controller, this, true);
view.setOnTouchListener((view1, event) -> {
return handleTouchEvent(event);
});
// TODO: Make dynamic, editable. // TODO: Make dynamic, editable.
mButtonViews.clear();
linkButton(view, R.id.controller_button_up, "Up"); linkButton(view, R.id.controller_button_up, "Up");
linkButton(view, R.id.controller_button_right, "Right"); linkButton(view, R.id.controller_button_right, "Right");
linkButton(view, R.id.controller_button_down, "Down"); 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) { private void linkButton(View view, int id, String buttonName) {
TouchscreenControllerButtonView buttonView = (TouchscreenControllerButtonView) view.findViewById(id); TouchscreenControllerButtonView buttonView = (TouchscreenControllerButtonView) view.findViewById(id);
buttonView.setButtonName(buttonName); buttonView.setButtonName(buttonName);
buttonView.setButtonStateChangedListener(this);
int code = AndroidHostInterface.getInstance().getControllerButtonCode(mControllerType, buttonName); int code = AndroidHostInterface.getInstance().getControllerButtonCode(mControllerType, buttonName);
buttonView.setButtonCode(code); buttonView.setButtonCode(code);
Log.i("TouchscreenController", String.format("%s -> %d", buttonName, 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' " + Log.e("TouchscreenController", String.format("Unknown button name '%s' " +
"for '%s'", buttonName, mControllerType)); "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 case MotionEvent.ACTION_DOWN:
public void onButtonStateChanged(TouchscreenControllerButtonView view, boolean pressed) { case MotionEvent.ACTION_POINTER_DOWN:
if (view.getButtonCode() < 0) case MotionEvent.ACTION_MOVE:
return; {
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);
}
} }
} }