Android: Add on-screen dpad support

This commit is contained in:
Sean Maas 2016-09-21 22:50:22 -04:00
parent c24a22e30f
commit bd99b318e5
2 changed files with 223 additions and 0 deletions

View file

@ -37,10 +37,12 @@ import java.util.Set;
public final class InputOverlay extends SurfaceView implements OnTouchListener
{
private final Set<InputOverlayDrawableButton> overlayButtons = new HashSet<>();
private final Set<InputOverlayDrawableDpad> overlayDpads = new HashSet<>();
private final Set<InputOverlayDrawableJoystick> overlayJoysticks = new HashSet<>();
private boolean mIsInEditMode = false;
private InputOverlayDrawableButton mButtonBeingConfigured;
private InputOverlayDrawableDpad mDpadBeingConfigured;
private InputOverlayDrawableJoystick mJoystickBeingConfigured;
/**
@ -84,6 +86,9 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_start, ButtonType.BUTTON_START));
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_l, ButtonType.TRIGGER_L));
overlayButtons.add(initializeOverlayButton(context, R.drawable.gcpad_r, ButtonType.TRIGGER_R));
overlayDpads.add(initializeOverlayDpad(context, R.drawable.gcpad_dpad,
ButtonType.BUTTON_UP, ButtonType.BUTTON_DOWN,
ButtonType.BUTTON_LEFT, ButtonType.BUTTON_RIGHT));
overlayJoysticks.add(initializeOverlayJoystick(context,
R.drawable.gcpad_joystick_range, R.drawable.gcpad_joystick,
ButtonType.STICK_MAIN));
@ -108,6 +113,11 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
button.draw(canvas);
}
for (InputOverlayDrawableDpad dpad : overlayDpads)
{
dpad.draw(canvas);
}
for (InputOverlayDrawableJoystick joystick: overlayJoysticks)
{
joystick.draw(canvas);
@ -149,6 +159,48 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
}
}
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:
case MotionEvent.ACTION_MOVE:
// If a pointer enters the bounds of a button, press that button.
if (dpad.getBounds().contains((int)event.getX(pointerIndex), (int)event.getY(pointerIndex)))
{
if (dpad.getBounds().top + (dpad.getIntrinsicHeight() / 3) > (int)event.getY(pointerIndex))
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(0), ButtonState.PRESSED);
}
if (dpad.getBounds().bottom - (dpad.getIntrinsicHeight() / 3) < (int)event.getY(pointerIndex))
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(1), ButtonState.PRESSED);
}
if (dpad.getBounds().left + (dpad.getIntrinsicWidth() / 3) > (int)event.getX(pointerIndex))
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(2), ButtonState.PRESSED);
}
if (dpad.getBounds().right - (dpad.getIntrinsicWidth() / 3) < (int)event.getX(pointerIndex))
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(3), ButtonState.PRESSED);
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
// If a pointer ends, release the buttons.
if (dpad.getBounds().contains((int)event.getX(pointerIndex), (int)event.getY(pointerIndex)))
{
for(int i = 0; i < 4; i++)
{
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i), ButtonState.RELEASED);
}
}
break;
}
}
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
{
@ -209,6 +261,40 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
}
}
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 no button is being moved now, remember the currently touched button to move.
if (mButtonBeingConfigured == null && dpad.getBounds().contains(fingerPositionX, fingerPositionY))
{
mDpadBeingConfigured = dpad;
mDpadBeingConfigured.onConfigureTouch(v, event);
}
break;
case MotionEvent.ACTION_MOVE:
if (mDpadBeingConfigured != null)
{
mDpadBeingConfigured.onConfigureTouch(v, event);
invalidate();
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
if (mDpadBeingConfigured == dpad)
{
//Persist button position by saving new place.
saveControlPosition(mDpadBeingConfigured.getId(0), mDpadBeingConfigured.getBounds().left, mDpadBeingConfigured.getBounds().top);
mDpadBeingConfigured = null;
}
break;
}
}
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
{
@ -341,6 +427,57 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
return overlayDrawable;
}
/**
* Initializes an {@link InputOverlayDrawableDpad}
*
* @param context The current {@link Context}.
* @param resId The resource ID of the {@link Drawable} to get the {@link Bitmap} of.
* @param buttonUp Identifier for the up button.
* @param buttonDown Identifier for the down button.
* @param buttonLeft Identifier for the left button.
* @param buttonRight Identifier for the right button.
*
* @return the initialized {@link InputOverlayDrawableDpad}
*/
private static InputOverlayDrawableDpad initializeOverlayDpad(Context context, int resId,
int buttonUp, int buttonDown,
int buttonLeft, int buttonRight)
{
// Resources handle for fetching the initial Drawable resource.
final Resources res = context.getResources();
// SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableDpad.
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(context);
// Initialize the InputOverlayDrawableDpad.
float overlaySize = sPrefs.getInt("controls_size", 20);
overlaySize += 30;
overlaySize /= 50;
final Bitmap bitmap = resizeBitmap(context, BitmapFactory.decodeResource(res, resId), 0.30f * overlaySize);
final InputOverlayDrawableDpad overlayDrawable = new InputOverlayDrawableDpad(res, bitmap,
buttonUp, buttonDown, buttonLeft, buttonRight);
// The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay.
// These were set in the input overlay configuration menu.
int drawableX = (int) sPrefs.getFloat(buttonUp+"-X", 0f);
int drawableY = (int) sPrefs.getFloat(buttonUp+"-Y", 0f);
// Intrinsic width and height of the InputOverlayDrawableDpad.
// For any who may not know, intrinsic width/height
// are the original unmodified width and height of the image.
int intrinWidth = overlayDrawable.getIntrinsicWidth();
int intrinHeight = overlayDrawable.getIntrinsicHeight();
// Now set the bounds for the InputOverlayDrawableDpad.
// This will dictate where on the screen (and the what the size) the InputOverlayDrawableDpad will be.
overlayDrawable.setBounds(drawableX, drawableY, drawableX+intrinWidth, drawableY+intrinHeight);
// Need to set the image's position
overlayDrawable.setPosition(drawableX, drawableY);
return overlayDrawable;
}
/**
* Initializes an {@link InputOverlayDrawableJoystick}
*

View file

@ -0,0 +1,86 @@
/**
* Copyright 2016 Dolphin Emulator Project
* Licensed under GPLv2+
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.overlay;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.view.MotionEvent;
import android.view.View;
/**
* Custom {@link BitmapDrawable} that is capable
* of storing it's own ID.
*/
public final class InputOverlayDrawableDpad extends BitmapDrawable
{
// The ID identifying what type of button this Drawable represents.
private int[] mButtonType = new int[4];
private int mPreviousTouchX, mPreviousTouchY;
private int mControlPositionX, mControlPositionY;
/**
* Constructor
*
* @param res {@link Resources} instance.
* @param bitmap {@link Bitmap} to use with this Drawable.
* @param buttonUp Identifier for the up button.
* @param buttonDown Identifier for the down button.
* @param buttonLeft Identifier for the left button.
* @param buttonRight Identifier for the right button.
*/
public InputOverlayDrawableDpad(Resources res, Bitmap bitmap,
int buttonUp, int buttonDown,
int buttonLeft, int buttonRight)
{
super(res, bitmap);
mButtonType[0] = buttonUp;
mButtonType[1] = buttonDown;
mButtonType[2] = buttonLeft;
mButtonType[3] = buttonRight;
}
/**
* Gets one of the InputOverlayDrawableDpad's button IDs.
*
* @return the requested InputOverlayDrawableDpad's button ID.
*/
public int getId(int direction)
{
return mButtonType[direction];
}
public boolean onConfigureTouch(View v, MotionEvent event)
{
int pointerIndex = event.getActionIndex();
int fingerPositionX = (int)event.getX(pointerIndex);
int fingerPositionY = (int)event.getY(pointerIndex);
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
mPreviousTouchX = fingerPositionX;
mPreviousTouchY = fingerPositionY;
break;
case MotionEvent.ACTION_MOVE:
mControlPositionX += fingerPositionX - mPreviousTouchX;
mControlPositionY += fingerPositionY - mPreviousTouchY;
setBounds(new Rect(mControlPositionX, mControlPositionY, getBitmap().getWidth() + mControlPositionX, getBitmap().getHeight() + mControlPositionY));
mPreviousTouchX = fingerPositionX;
mPreviousTouchY = fingerPositionY;
break;
}
return true;
}
public void setPosition(int x, int y)
{
mControlPositionX = x;
mControlPositionY = y;
}
}