diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index 5a0d02be42..3a7c9c1067 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -238,7 +238,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C if (mInputOverlay != null) { mBinding.doneControlConfig.setVisibility(View.VISIBLE); - mInputOverlay.setIsInEditMode(true); + mInputOverlay.setEditMode(true); } } @@ -247,7 +247,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C if (mInputOverlay != null) { mBinding.doneControlConfig.setVisibility(View.GONE); - mInputOverlay.setIsInEditMode(false); + mInputOverlay.setEditMode(false); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java deleted file mode 100644 index d44acc2786..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.java +++ /dev/null @@ -1,1868 +0,0 @@ -/* - * Copyright 2013 Dolphin Emulator Project - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -package org.dolphinemu.dolphinemu.overlay; - -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.view.Display; -import android.view.MotionEvent; -import android.view.SurfaceView; -import android.view.View; -import android.view.View.OnTouchListener; -import android.widget.Toast; - -import androidx.preference.PreferenceManager; - -import org.dolphinemu.dolphinemu.NativeLibrary; -import org.dolphinemu.dolphinemu.NativeLibrary.ButtonType; -import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.features.input.model.InputMappingBooleanSetting; -import org.dolphinemu.dolphinemu.features.input.model.InputOverrider; -import org.dolphinemu.dolphinemu.features.input.model.InputOverrider.ControlId; -import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController; -import org.dolphinemu.dolphinemu.features.input.model.controlleremu.NumericSetting; -import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; -import org.dolphinemu.dolphinemu.features.settings.model.IntSetting; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -/** - * Draws the interactive input overlay on top of the - * {@link SurfaceView} that is rendering emulation. - */ -public final class InputOverlay extends SurfaceView implements OnTouchListener -{ - public static final int OVERLAY_GAMECUBE = 0; - public static final int OVERLAY_WIIMOTE = 1; - public static final int OVERLAY_WIIMOTE_SIDEWAYS = 2; - public static final int OVERLAY_WIIMOTE_NUNCHUK = 3; - public static final int OVERLAY_WIIMOTE_CLASSIC = 4; - public static final int OVERLAY_NONE = 5; - - private static final int DISABLED_GAMECUBE_CONTROLLER = 0; - private static final int EMULATED_GAMECUBE_CONTROLLER = 6; - private static final int GAMECUBE_ADAPTER = 12; - - private final Set overlayButtons = new HashSet<>(); - private final Set overlayDpads = new HashSet<>(); - private final Set overlayJoysticks = new HashSet<>(); - private InputOverlayPointer overlayPointer = null; - - private Rect mSurfacePosition = null; - - private boolean mIsFirstRun = true; - private boolean[] mGcPadRegistered = new boolean[4]; - private boolean[] mWiimoteRegistered = new boolean[4]; - private boolean mIsInEditMode = false; - private int mControllerType = -1; - private int mControllerIndex = 0; - private InputOverlayDrawableButton mButtonBeingConfigured; - private InputOverlayDrawableDpad mDpadBeingConfigured; - private InputOverlayDrawableJoystick mJoystickBeingConfigured; - - private final SharedPreferences mPreferences; - - // Buttons that have special positions in Wiimote only - private static final ArrayList WIIMOTE_H_BUTTONS = new ArrayList<>(); - - static - { - WIIMOTE_H_BUTTONS.add(ButtonType.WIIMOTE_BUTTON_A); - WIIMOTE_H_BUTTONS.add(ButtonType.WIIMOTE_BUTTON_B); - WIIMOTE_H_BUTTONS.add(ButtonType.WIIMOTE_BUTTON_1); - WIIMOTE_H_BUTTONS.add(ButtonType.WIIMOTE_BUTTON_2); - } - - private static final ArrayList WIIMOTE_O_BUTTONS = new ArrayList<>(); - - static - { - WIIMOTE_O_BUTTONS.add(ButtonType.WIIMOTE_UP); - } - - /** - * Resizes a {@link Bitmap} by a given scale factor - * - * @param context The current {@link Context} - * @param bitmap The {@link Bitmap} to scale. - * @param scale The scale factor for the bitmap. - * @return The scaled {@link Bitmap} - */ - public static Bitmap resizeBitmap(Context context, Bitmap bitmap, float scale) - { - // Determine the button size based on the smaller screen dimension. - // This makes sure the buttons are the same size in both portrait and landscape. - DisplayMetrics dm = context.getResources().getDisplayMetrics(); - int minScreenDimension = Math.min(dm.widthPixels, dm.heightPixels); - - int maxBitmapDimension = Math.max(bitmap.getWidth(), bitmap.getHeight()); - float bitmapScale = scale * minScreenDimension / maxBitmapDimension; - - return Bitmap.createScaledBitmap(bitmap, - (int) (bitmap.getWidth() * bitmapScale), - (int) (bitmap.getHeight() * bitmapScale), - true); - } - - /** - * Constructor - * - * @param context The current {@link Context}. - * @param attrs {@link AttributeSet} for parsing XML attributes. - */ - public InputOverlay(Context context, AttributeSet attrs) - { - super(context, attrs); - - mPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); - if (!mPreferences.getBoolean("OverlayInitV3", false)) - defaultOverlay(); - - // Set the on touch listener. - setOnTouchListener(this); - - // Force draw - setWillNotDraw(false); - - // Request focus for the overlay so it has priority on presses. - requestFocus(); - } - - public void setSurfacePosition(Rect rect) - { - mSurfacePosition = rect; - initTouchPointer(); - } - - public void initTouchPointer() - { - // Check if we have all the data we need yet - boolean aspectRatioAvailable = NativeLibrary.IsRunningAndStarted(); - if (!aspectRatioAvailable || mSurfacePosition == null) - return; - - // Check if there's any point in running the pointer code - if (!NativeLibrary.IsEmulatingWii()) - return; - - int doubleTapButton = IntSetting.MAIN_DOUBLE_TAP_BUTTON.getInt(); - - if (getConfiguredControllerType() != InputOverlay.OVERLAY_WIIMOTE_CLASSIC && - doubleTapButton == ButtonType.CLASSIC_BUTTON_A) - { - doubleTapButton = ButtonType.WIIMOTE_BUTTON_A; - } - - int doubleTapControl = ControlId.WIIMOTE_A_BUTTON; - switch (doubleTapButton) - { - case ButtonType.WIIMOTE_BUTTON_A: - doubleTapControl = ControlId.WIIMOTE_A_BUTTON; - break; - case ButtonType.WIIMOTE_BUTTON_B: - doubleTapControl = ControlId.WIIMOTE_B_BUTTON; - break; - case ButtonType.WIIMOTE_BUTTON_2: - doubleTapControl = ControlId.WIIMOTE_TWO_BUTTON; - break; - } - - overlayPointer = new InputOverlayPointer(mSurfacePosition, doubleTapControl, - IntSetting.MAIN_IR_MODE.getInt(), BooleanSetting.MAIN_IR_ALWAYS_RECENTER.getBoolean(), - mControllerIndex); - } - - @Override - public void draw(Canvas canvas) - { - super.draw(canvas); - - for (InputOverlayDrawableButton button : overlayButtons) - { - button.draw(canvas); - } - - for (InputOverlayDrawableDpad dpad : overlayDpads) - { - dpad.draw(canvas); - } - - for (InputOverlayDrawableJoystick joystick : overlayJoysticks) - { - joystick.draw(canvas); - } - } - - @Override - public boolean onTouch(View v, MotionEvent event) - { - if (isInEditMode()) - { - return onTouchWhileEditing(event); - } - - int action = event.getActionMasked(); - boolean firstPointer = action != MotionEvent.ACTION_POINTER_DOWN && - action != MotionEvent.ACTION_POINTER_UP; - int pointerIndex = firstPointer ? 0 : event.getActionIndex(); - // Tracks if any button/joystick is pressed down - boolean pressed = false; - - for (InputOverlayDrawableButton button : overlayButtons) - { - // Determine the button state to apply based on the MotionEvent action flag. - switch (action) - { - 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)); - pressed = true; - InputOverrider.setControlState(mControllerIndex, button.getControl(), 1.0); - - int analogControl = getAnalogControlForTrigger(button.getControl()); - if (analogControl >= 0) - InputOverrider.setControlState(mControllerIndex, analogControl, 1.0); - } - 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); - InputOverrider.setControlState(mControllerIndex, button.getControl(), 0.0); - - int analogControl = getAnalogControlForTrigger(button.getControl()); - if (analogControl >= 0) - InputOverrider.setControlState(mControllerIndex, analogControl, 0.0); - - button.setTrackId(-1); - } - break; - } - } - - 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 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)); - pressed = true; - } - case MotionEvent.ACTION_MOVE: - if (dpad.getTrackId() == event.getPointerId(pointerIndex)) - { - // Up, Down, Left, Right - boolean[] dpadPressed = {false, false, false, false}; - - if (dpad.getBounds().top + (dpad.getHeight() / 3) > (int) event.getY(pointerIndex)) - dpadPressed[0] = true; - if (dpad.getBounds().bottom - (dpad.getHeight() / 3) < (int) event.getY(pointerIndex)) - dpadPressed[1] = true; - if (dpad.getBounds().left + (dpad.getWidth() / 3) > (int) event.getX(pointerIndex)) - dpadPressed[2] = true; - if (dpad.getBounds().right - (dpad.getWidth() / 3) < (int) event.getX(pointerIndex)) - dpadPressed[3] = true; - - // Release the buttons first, then press - for (int i = 0; i < dpadPressed.length; i++) - { - if (!dpadPressed[i]) - { - InputOverrider.setControlState(mControllerIndex, dpad.getControl(i), 0.0); - } - } - // Press buttons - for (int i = 0; i < dpadPressed.length; i++) - { - if (dpadPressed[i]) - { - InputOverrider.setControlState(mControllerIndex, dpad.getControl(i), 1.0); - } - } - setDpadState(dpad, dpadPressed[0], dpadPressed[1], dpadPressed[2], dpadPressed[3]); - } - 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); - InputOverrider.setControlState(mControllerIndex, dpad.getControl(i), 0.0); - } - dpad.setTrackId(-1); - } - break; - } - } - - for (InputOverlayDrawableJoystick joystick : overlayJoysticks) - { - if (joystick.TrackEvent(event)) - { - if (joystick.getTrackId() != -1) - pressed = true; - } - - InputOverrider.setControlState(mControllerIndex, joystick.getXControl(), joystick.getX()); - InputOverrider.setControlState(mControllerIndex, joystick.getYControl(), -joystick.getY()); - } - - // No button/joystick pressed, safe to move pointer - if (!pressed && overlayPointer != null) - { - overlayPointer.onTouch(event); - InputOverrider.setControlState(mControllerIndex, ControlId.WIIMOTE_IR_X, - overlayPointer.getX()); - InputOverrider.setControlState(mControllerIndex, ControlId.WIIMOTE_IR_Y, - -overlayPointer.getY()); - } - - invalidate(); - - return true; - } - - public boolean onTouchWhileEditing(MotionEvent event) - { - int pointerIndex = event.getActionIndex(); - int fingerPositionX = (int) event.getX(pointerIndex); - int fingerPositionY = (int) event.getY(pointerIndex); - - String orientation = - getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ? - "-Portrait" : ""; - - // Maybe combine Button and Joystick as subclasses of the same parent? - // Or maybe create an interface like IMoveableHUDControl? - - for (InputOverlayDrawableButton button : overlayButtons) - { - // 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 && - button.getBounds().contains(fingerPositionX, fingerPositionY)) - { - mButtonBeingConfigured = button; - mButtonBeingConfigured.onConfigureTouch(event); - } - break; - case MotionEvent.ACTION_MOVE: - if (mButtonBeingConfigured != null) - { - mButtonBeingConfigured.onConfigureTouch(event); - invalidate(); - return true; - } - break; - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - if (mButtonBeingConfigured == button) - { - // Persist button position by saving new place. - saveControlPosition(mButtonBeingConfigured.getLegacyId(), - mButtonBeingConfigured.getBounds().left, - mButtonBeingConfigured.getBounds().top, orientation); - mButtonBeingConfigured = null; - } - break; - } - } - - 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(event); - } - break; - case MotionEvent.ACTION_MOVE: - if (mDpadBeingConfigured != null) - { - mDpadBeingConfigured.onConfigureTouch(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.getLegacyId(), - mDpadBeingConfigured.getBounds().left, mDpadBeingConfigured.getBounds().top, - orientation); - mDpadBeingConfigured = null; - } - break; - } - } - - for (InputOverlayDrawableJoystick joystick : overlayJoysticks) - { - switch (event.getAction()) - { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - if (mJoystickBeingConfigured == null && - joystick.getBounds().contains(fingerPositionX, fingerPositionY)) - { - mJoystickBeingConfigured = joystick; - mJoystickBeingConfigured.onConfigureTouch(event); - } - break; - case MotionEvent.ACTION_MOVE: - if (mJoystickBeingConfigured != null) - { - mJoystickBeingConfigured.onConfigureTouch(event); - invalidate(); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - if (mJoystickBeingConfigured != null) - { - saveControlPosition(mJoystickBeingConfigured.getLegacyId(), - mJoystickBeingConfigured.getBounds().left, - mJoystickBeingConfigured.getBounds().top, orientation); - mJoystickBeingConfigured = null; - } - break; - } - } - - return true; - } - - public void onDestroy() - { - unregisterControllers(); - } - - private void unregisterControllers() - { - for (int i = 0; i < mGcPadRegistered.length; i++) - { - if (mGcPadRegistered[i]) - InputOverrider.unregisterGameCube(i); - } - - for (int i = 0; i < mWiimoteRegistered.length; i++) - { - if (mWiimoteRegistered[i]) - InputOverrider.unregisterWii(i); - } - - Arrays.fill(mGcPadRegistered, false); - Arrays.fill(mWiimoteRegistered, false); - } - - private int getAnalogControlForTrigger(int control) - { - switch (control) - { - case ControlId.GCPAD_L_DIGITAL: - return ControlId.GCPAD_L_ANALOG; - case ControlId.GCPAD_R_DIGITAL: - return ControlId.GCPAD_R_ANALOG; - case ControlId.CLASSIC_L_DIGITAL: - return ControlId.CLASSIC_L_ANALOG; - case ControlId.CLASSIC_R_DIGITAL: - return ControlId.CLASSIC_R_ANALOG; - default: - return -1; - } - } - - 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 addGameCubeOverlayControls(String orientation) - { - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_0.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_a, - R.drawable.gcpad_a_pressed, ButtonType.BUTTON_A, ControlId.GCPAD_A_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_1.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_b, - R.drawable.gcpad_b_pressed, ButtonType.BUTTON_B, ControlId.GCPAD_B_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_2.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_x, - R.drawable.gcpad_x_pressed, ButtonType.BUTTON_X, ControlId.GCPAD_X_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_3.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_y, - R.drawable.gcpad_y_pressed, ButtonType.BUTTON_Y, ControlId.GCPAD_Y_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_4.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_z, - R.drawable.gcpad_z_pressed, ButtonType.BUTTON_Z, ControlId.GCPAD_Z_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_5.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_start, - R.drawable.gcpad_start_pressed, ButtonType.BUTTON_START, ControlId.GCPAD_START_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_6.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_l, - R.drawable.gcpad_l_pressed, ButtonType.TRIGGER_L, ControlId.GCPAD_L_DIGITAL, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_7.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.gcpad_r, - R.drawable.gcpad_r_pressed, ButtonType.TRIGGER_R, ControlId.GCPAD_R_DIGITAL, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_8.getBoolean()) - { - overlayDpads.add(initializeOverlayDpad(getContext(), R.drawable.gcwii_dpad, - R.drawable.gcwii_dpad_pressed_one_direction, - R.drawable.gcwii_dpad_pressed_two_directions, - ButtonType.BUTTON_UP, ControlId.GCPAD_DPAD_UP, ControlId.GCPAD_DPAD_DOWN, - ControlId.GCPAD_DPAD_LEFT, ControlId.GCPAD_DPAD_RIGHT, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_9.getBoolean()) - { - overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range, - R.drawable.gcwii_joystick, R.drawable.gcwii_joystick_pressed, ButtonType.STICK_MAIN, - ControlId.GCPAD_MAIN_STICK_X, ControlId.GCPAD_MAIN_STICK_Y, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_10.getBoolean()) - { - overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range, - R.drawable.gcpad_c, R.drawable.gcpad_c_pressed, ButtonType.STICK_C, - ControlId.GCPAD_C_STICK_X, ControlId.GCPAD_C_STICK_Y, orientation)); - } - } - - private void addWiimoteOverlayControls(String orientation) - { - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_0.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_a, - R.drawable.wiimote_a_pressed, ButtonType.WIIMOTE_BUTTON_A, ControlId.WIIMOTE_A_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_1.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_b, - R.drawable.wiimote_b_pressed, ButtonType.WIIMOTE_BUTTON_B, ControlId.WIIMOTE_B_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_2.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_one, - R.drawable.wiimote_one_pressed, ButtonType.WIIMOTE_BUTTON_1, - ControlId.WIIMOTE_ONE_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_3.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_two, - R.drawable.wiimote_two_pressed, ButtonType.WIIMOTE_BUTTON_2, - ControlId.WIIMOTE_TWO_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_4.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_plus, - R.drawable.wiimote_plus_pressed, ButtonType.WIIMOTE_BUTTON_PLUS, - ControlId.WIIMOTE_PLUS_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_5.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_minus, - R.drawable.wiimote_minus_pressed, ButtonType.WIIMOTE_BUTTON_MINUS, - ControlId.WIIMOTE_MINUS_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_6.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_home, - R.drawable.wiimote_home_pressed, ButtonType.WIIMOTE_BUTTON_HOME, - ControlId.WIIMOTE_HOME_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_7.getBoolean()) - { - overlayDpads.add(initializeOverlayDpad(getContext(), R.drawable.gcwii_dpad, - R.drawable.gcwii_dpad_pressed_one_direction, - R.drawable.gcwii_dpad_pressed_two_directions, - ButtonType.WIIMOTE_UP, ControlId.WIIMOTE_DPAD_UP, ControlId.WIIMOTE_DPAD_DOWN, - ControlId.WIIMOTE_DPAD_LEFT, ControlId.WIIMOTE_DPAD_RIGHT, orientation)); - } - } - - private void addNunchukOverlayControls(String orientation) - { - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_8.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.nunchuk_c, - R.drawable.nunchuk_c_pressed, ButtonType.NUNCHUK_BUTTON_C, ControlId.NUNCHUK_C_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_9.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.nunchuk_z, - R.drawable.nunchuk_z_pressed, ButtonType.NUNCHUK_BUTTON_Z, ControlId.NUNCHUK_Z_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_10.getBoolean()) - { - overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range, - R.drawable.gcwii_joystick, R.drawable.gcwii_joystick_pressed, - ButtonType.NUNCHUK_STICK, ControlId.NUNCHUK_STICK_X, ControlId.NUNCHUK_STICK_Y, - orientation)); - } - } - - private void addClassicOverlayControls(String orientation) - { - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_0.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_a, - R.drawable.classic_a_pressed, ButtonType.CLASSIC_BUTTON_A, ControlId.CLASSIC_A_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_1.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_b, - R.drawable.classic_b_pressed, ButtonType.CLASSIC_BUTTON_B, ControlId.CLASSIC_B_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_2.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_x, - R.drawable.classic_x_pressed, ButtonType.CLASSIC_BUTTON_X, ControlId.CLASSIC_X_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_3.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_y, - R.drawable.classic_y_pressed, ButtonType.CLASSIC_BUTTON_Y, ControlId.CLASSIC_Y_BUTTON, - orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_4.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_plus, - R.drawable.wiimote_plus_pressed, ButtonType.CLASSIC_BUTTON_PLUS, - ControlId.CLASSIC_PLUS_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_5.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_minus, - R.drawable.wiimote_minus_pressed, ButtonType.CLASSIC_BUTTON_MINUS, - ControlId.CLASSIC_MINUS_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_6.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.wiimote_home, - R.drawable.wiimote_home_pressed, ButtonType.CLASSIC_BUTTON_HOME, - ControlId.CLASSIC_HOME_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_7.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_l, - R.drawable.classic_l_pressed, ButtonType.CLASSIC_TRIGGER_L, - ControlId.CLASSIC_L_DIGITAL, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_8.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_r, - R.drawable.classic_r_pressed, ButtonType.CLASSIC_TRIGGER_R, - ControlId.CLASSIC_R_DIGITAL, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_9.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_zl, - R.drawable.classic_zl_pressed, ButtonType.CLASSIC_BUTTON_ZL, - ControlId.CLASSIC_ZL_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_10.getBoolean()) - { - overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.classic_zr, - R.drawable.classic_zr_pressed, ButtonType.CLASSIC_BUTTON_ZR, - ControlId.CLASSIC_ZR_BUTTON, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_11.getBoolean()) - { - overlayDpads.add(initializeOverlayDpad(getContext(), R.drawable.gcwii_dpad, - R.drawable.gcwii_dpad_pressed_one_direction, - R.drawable.gcwii_dpad_pressed_two_directions, - ButtonType.CLASSIC_DPAD_UP, ControlId.CLASSIC_DPAD_UP, ControlId.CLASSIC_DPAD_DOWN, - ControlId.CLASSIC_DPAD_LEFT, ControlId.CLASSIC_DPAD_RIGHT, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_12.getBoolean()) - { - overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range, - R.drawable.gcwii_joystick, R.drawable.gcwii_joystick_pressed, - ButtonType.CLASSIC_STICK_LEFT, ControlId.CLASSIC_LEFT_STICK_X, - ControlId.CLASSIC_LEFT_STICK_Y, orientation)); - } - if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_13.getBoolean()) - { - overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.gcwii_joystick_range, - R.drawable.gcwii_joystick, R.drawable.gcwii_joystick_pressed, - ButtonType.CLASSIC_STICK_RIGHT, ControlId.CLASSIC_RIGHT_STICK_X, - ControlId.CLASSIC_RIGHT_STICK_Y, orientation)); - } - } - - public void refreshControls() - { - unregisterControllers(); - - // Remove all the overlay buttons from the HashSet. - overlayButtons.removeAll(overlayButtons); - overlayDpads.removeAll(overlayDpads); - overlayJoysticks.removeAll(overlayJoysticks); - - String orientation = - getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ? - "-Portrait" : ""; - - mControllerType = getConfiguredControllerType(); - - IntSetting controllerSetting = NativeLibrary.IsEmulatingWii() ? - IntSetting.MAIN_OVERLAY_WII_CONTROLLER : IntSetting.MAIN_OVERLAY_GC_CONTROLLER; - int controllerIndex = controllerSetting.getInt(); - - if (BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.getBoolean()) - { - // Add all the enabled overlay items back to the HashSet. - switch (mControllerType) - { - case OVERLAY_GAMECUBE: - if (IntSetting.getSettingForSIDevice(controllerIndex).getInt() == - DISABLED_GAMECUBE_CONTROLLER && mIsFirstRun) - { - Toast.makeText(getContext(), R.string.disabled_gc_overlay_notice, Toast.LENGTH_SHORT) - .show(); - } - - mControllerIndex = controllerIndex; - InputOverrider.registerGameCube(mControllerIndex); - mGcPadRegistered[mControllerIndex] = true; - - addGameCubeOverlayControls(orientation); - break; - - case OVERLAY_WIIMOTE: - case OVERLAY_WIIMOTE_SIDEWAYS: - mControllerIndex = controllerIndex - 4; - InputOverrider.registerWii(mControllerIndex); - mWiimoteRegistered[mControllerIndex] = true; - - addWiimoteOverlayControls(orientation); - break; - - case OVERLAY_WIIMOTE_NUNCHUK: - mControllerIndex = controllerIndex - 4; - InputOverrider.registerWii(mControllerIndex); - mWiimoteRegistered[mControllerIndex] = true; - - addWiimoteOverlayControls(orientation); - addNunchukOverlayControls(orientation); - break; - - case OVERLAY_WIIMOTE_CLASSIC: - mControllerIndex = controllerIndex - 4; - InputOverrider.registerWii(mControllerIndex); - mWiimoteRegistered[mControllerIndex] = true; - - addClassicOverlayControls(orientation); - break; - - case OVERLAY_NONE: - break; - } - } - - mIsFirstRun = false; - invalidate(); - } - - public void refreshOverlayPointer() - { - if (overlayPointer != null) - { - overlayPointer.setMode(IntSetting.MAIN_IR_MODE.getInt()); - overlayPointer.setRecenter(BooleanSetting.MAIN_IR_ALWAYS_RECENTER.getBoolean()); - } - } - - public void resetButtonPlacement() - { - boolean isLandscape = - getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; - - final int controller = getConfiguredControllerType(); - if (controller == OVERLAY_GAMECUBE) - { - if (isLandscape) - gcDefaultOverlay(); - else - gcPortraitDefaultOverlay(); - } - else if (controller == OVERLAY_WIIMOTE_CLASSIC) - { - if (isLandscape) - wiiClassicDefaultOverlay(); - else - wiiClassicPortraitDefaultOverlay(); - } - else - { - if (isLandscape) - { - wiiDefaultOverlay(); - wiiOnlyDefaultOverlay(); - } - else - { - wiiPortraitDefaultOverlay(); - wiiOnlyPortraitDefaultOverlay(); - } - } - refreshControls(); - } - - public static int getConfiguredControllerType() - { - IntSetting controllerSetting = NativeLibrary.IsEmulatingWii() ? - IntSetting.MAIN_OVERLAY_WII_CONTROLLER : IntSetting.MAIN_OVERLAY_GC_CONTROLLER; - int controllerIndex = controllerSetting.getInt(); - - if (controllerIndex >= 0 && controllerIndex < 4) - { - // GameCube controller - if (IntSetting.getSettingForSIDevice(controllerIndex).getInt() == 6) - return OVERLAY_GAMECUBE; - } - else if (controllerIndex >= 4 && controllerIndex < 8) - { - // Wii Remote - int wiimoteIndex = controllerIndex - 4; - if (IntSetting.getSettingForWiimoteSource(wiimoteIndex).getInt() == 1) - { - int attachmentIndex = EmulatedController.getSelectedWiimoteAttachment(wiimoteIndex); - switch (attachmentIndex) - { - case 1: - return OVERLAY_WIIMOTE_NUNCHUK; - case 2: - return OVERLAY_WIIMOTE_CLASSIC; - } - - NumericSetting sidewaysSetting = EmulatedController.getSidewaysWiimoteSetting(wiimoteIndex); - boolean sideways = new InputMappingBooleanSetting(sidewaysSetting).getBoolean(); - - return sideways ? OVERLAY_WIIMOTE_SIDEWAYS : OVERLAY_WIIMOTE; - } - } - - return OVERLAY_NONE; - } - - private void saveControlPosition(int sharedPrefsId, int x, int y, String orientation) - { - final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); - SharedPreferences.Editor sPrefsEditor = sPrefs.edit(); - sPrefsEditor.putFloat(getXKey(sharedPrefsId, mControllerType, orientation), x); - sPrefsEditor.putFloat(getYKey(sharedPrefsId, mControllerType, orientation), y); - sPrefsEditor.apply(); - } - - private static String getKey(int sharedPrefsId, int controller, String orientation, String suffix) - { - if (controller == OVERLAY_WIIMOTE_SIDEWAYS && WIIMOTE_H_BUTTONS.contains(sharedPrefsId)) - { - return sharedPrefsId + "_H" + orientation + suffix; - } - else if (controller == OVERLAY_WIIMOTE && WIIMOTE_O_BUTTONS.contains(sharedPrefsId)) - { - return sharedPrefsId + "_O" + orientation + suffix; - } - else - { - return sharedPrefsId + orientation + suffix; - } - } - - private static String getXKey(int sharedPrefsId, int controller, String orientation) - { - return getKey(sharedPrefsId, controller, orientation, "-X"); - } - - private static String getYKey(int sharedPrefsId, int controller, String orientation) - { - return getKey(sharedPrefsId, controller, orientation, "-Y"); - } - - /** - * Initializes an InputOverlayDrawableButton, given by resId, with all of the - * parameters set for it to be properly shown on the InputOverlay. - *

- * This works due to the way the X and Y coordinates are stored within - * the {@link SharedPreferences}. - *

- * In the input overlay configuration menu, - * once a touch event begins and then ends (ie. Organizing the buttons to one's own liking for the overlay). - * the X and Y coordinates of the button at the END of its touch event - * (when you remove your finger/stylus from the touchscreen) are then stored - * within a SharedPreferences instance so that those values can be retrieved here. - *

- * This has a few benefits over the conventional way of storing the values - * (ie. within the Dolphin ini file). - *

    - *
  • No native calls
  • - *
  • Keeps Android-only values inside the Android environment
  • - *
- *

- * Technically no modifications should need to be performed on the returned - * InputOverlayDrawableButton. Simply add it to the HashSet of overlay items and wait - * for Android to call the onDraw method. - * - * @param context The current {@link Context}. - * @param defaultResId The resource ID of the {@link Drawable} to get the {@link Bitmap} of (Default State). - * @param pressedResId The resource ID of the {@link Drawable} to get the {@link Bitmap} of (Pressed State). - * @param legacyId Legacy identifier for the button the InputOverlayDrawableButton represents. - * @param control Control identifier for the button the InputOverlayDrawableButton represents. - * @return An {@link InputOverlayDrawableButton} with the correct drawing bounds set. - */ - private InputOverlayDrawableButton initializeOverlayButton(Context context, - int defaultResId, int pressedResId, int legacyId, int control, String orientation) - { - // Resources handle for fetching the initial Drawable resource. - final Resources res = context.getResources(); - - // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableButton. - final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(context); - - // Decide scale based on button ID and user preference - float scale; - - switch (legacyId) - { - case ButtonType.BUTTON_A: - case ButtonType.WIIMOTE_BUTTON_B: - case ButtonType.NUNCHUK_BUTTON_Z: - scale = 0.2f; - break; - case ButtonType.BUTTON_X: - case ButtonType.BUTTON_Y: - scale = 0.175f; - break; - case ButtonType.BUTTON_Z: - case ButtonType.TRIGGER_L: - case ButtonType.TRIGGER_R: - scale = 0.225f; - break; - case ButtonType.BUTTON_START: - scale = 0.075f; - break; - case ButtonType.WIIMOTE_BUTTON_1: - case ButtonType.WIIMOTE_BUTTON_2: - if (mControllerType == OVERLAY_WIIMOTE_SIDEWAYS) - scale = 0.14f; - else - scale = 0.0875f; - break; - case ButtonType.WIIMOTE_BUTTON_PLUS: - case ButtonType.WIIMOTE_BUTTON_MINUS: - case ButtonType.WIIMOTE_BUTTON_HOME: - case ButtonType.CLASSIC_BUTTON_PLUS: - case ButtonType.CLASSIC_BUTTON_MINUS: - case ButtonType.CLASSIC_BUTTON_HOME: - scale = 0.0625f; - break; - case ButtonType.CLASSIC_TRIGGER_L: - case ButtonType.CLASSIC_TRIGGER_R: - case ButtonType.CLASSIC_BUTTON_ZL: - case ButtonType.CLASSIC_BUTTON_ZR: - scale = 0.25f; - break; - default: - scale = 0.125f; - break; - } - - scale *= (IntSetting.MAIN_CONTROL_SCALE.getInt() + 50); - scale /= 100; - - // Initialize the InputOverlayDrawableButton. - final Bitmap defaultStateBitmap = - resizeBitmap(context, BitmapFactory.decodeResource(res, defaultResId), scale); - final Bitmap pressedStateBitmap = - resizeBitmap(context, BitmapFactory.decodeResource(res, pressedResId), scale); - final InputOverlayDrawableButton overlayDrawable = - new InputOverlayDrawableButton(res, defaultStateBitmap, pressedStateBitmap, legacyId, - control); - - // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. - // These were set in the input overlay configuration menu. - int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, mControllerType, orientation), 0f); - int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, mControllerType, orientation), 0f); - - int width = overlayDrawable.getWidth(); - int height = overlayDrawable.getHeight(); - - // Now set the bounds for the InputOverlayDrawableButton. - // This will dictate where on the screen (and the what the size) the InputOverlayDrawableButton will be. - overlayDrawable.setBounds(drawableX, drawableY, drawableX + width, drawableY + height); - - // Need to set the image's position - overlayDrawable.setPosition(drawableX, drawableY); - overlayDrawable.setOpacity(IntSetting.MAIN_CONTROL_OPACITY.getInt() * 255 / 100); - - return overlayDrawable; - } - - /** - * Initializes an {@link InputOverlayDrawableDpad} - * - * @param context The current {@link Context}. - * @param defaultResId The {@link Bitmap} resource ID of the default sate. - * @param pressedOneDirectionResId The {@link Bitmap} resource ID of the pressed sate in one direction. - * @param pressedTwoDirectionsResId The {@link Bitmap} resource ID of the pressed sate in two directions. - * @param legacyId Legacy identifier for the up button. - * @param upControl Control identifier for the up button. - * @param downControl Control identifier for the down button. - * @param leftControl Control identifier for the left button. - * @param rightControl Control identifier for the right button. - * @return the initialized {@link InputOverlayDrawableDpad} - */ - private InputOverlayDrawableDpad initializeOverlayDpad(Context context, - int defaultResId, - int pressedOneDirectionResId, - int pressedTwoDirectionsResId, - int legacyId, - int upControl, - int downControl, - int leftControl, - int rightControl, - String orientation) - { - // 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); - - // Decide scale based on button ID and user preference - float scale; - - switch (legacyId) - { - case ButtonType.BUTTON_UP: - scale = 0.2375f; - break; - case ButtonType.CLASSIC_DPAD_UP: - scale = 0.275f; - break; - default: - if (mControllerType == OVERLAY_WIIMOTE_SIDEWAYS || mControllerType == OVERLAY_WIIMOTE) - scale = 0.275f; - else - scale = 0.2125f; - break; - } - - scale *= (IntSetting.MAIN_CONTROL_SCALE.getInt() + 50); - scale /= 100; - - // Initialize the InputOverlayDrawableDpad. - final Bitmap defaultStateBitmap = - resizeBitmap(context, BitmapFactory.decodeResource(res, defaultResId), scale); - final Bitmap pressedOneDirectionStateBitmap = - resizeBitmap(context, BitmapFactory.decodeResource(res, pressedOneDirectionResId), - scale); - final Bitmap pressedTwoDirectionsStateBitmap = - resizeBitmap(context, BitmapFactory.decodeResource(res, pressedTwoDirectionsResId), - scale); - final InputOverlayDrawableDpad overlayDrawable = - new InputOverlayDrawableDpad(res, defaultStateBitmap, - pressedOneDirectionStateBitmap, pressedTwoDirectionsStateBitmap, - legacyId, upControl, downControl, leftControl, rightControl); - - // 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(getXKey(legacyId, mControllerType, orientation), 0f); - int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, mControllerType, orientation), 0f); - - int width = overlayDrawable.getWidth(); - int height = overlayDrawable.getHeight(); - - // 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 + width, drawableY + height); - - // Need to set the image's position - overlayDrawable.setPosition(drawableX, drawableY); - overlayDrawable.setOpacity(IntSetting.MAIN_CONTROL_OPACITY.getInt() * 255 / 100); - - return overlayDrawable; - } - - /** - * Initializes an {@link InputOverlayDrawableJoystick} - * - * @param context The current {@link Context} - * @param resOuter Resource ID for the outer image of the joystick (the static image that shows the circular bounds). - * @param defaultResInner Resource ID for the default inner image of the joystick (the one you actually move around). - * @param pressedResInner Resource ID for the pressed inner image of the joystick. - * @param legacyId Legacy identifier (ButtonType) for which joystick this is. - * @param xControl Control identifier for the X axis. - * @param yControl Control identifier for the Y axis. - * @return the initialized {@link InputOverlayDrawableJoystick}. - */ - private InputOverlayDrawableJoystick initializeOverlayJoystick(Context context, int resOuter, - int defaultResInner, int pressedResInner, int legacyId, int xControl, int yControl, - String orientation) - { - // Resources handle for fetching the initial Drawable resource. - final Resources res = context.getResources(); - - // SharedPreference to retrieve the X and Y coordinates for the InputOverlayDrawableJoystick. - final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(context); - - // Decide scale based on user preference - float scale = 0.275f; - scale *= (IntSetting.MAIN_CONTROL_SCALE.getInt() + 50); - scale /= 100; - - // Initialize the InputOverlayDrawableJoystick. - final Bitmap bitmapOuter = - resizeBitmap(context, BitmapFactory.decodeResource(res, resOuter), scale); - final Bitmap bitmapInnerDefault = BitmapFactory.decodeResource(res, defaultResInner); - final Bitmap bitmapInnerPressed = BitmapFactory.decodeResource(res, pressedResInner); - - // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. - // These were set in the input overlay configuration menu. - int drawableX = (int) sPrefs.getFloat(getXKey(legacyId, mControllerType, orientation), 0f); - int drawableY = (int) sPrefs.getFloat(getYKey(legacyId, mControllerType, orientation), 0f); - - // Decide inner scale based on joystick ID - float innerScale; - - if (legacyId == ButtonType.STICK_C) - { - innerScale = 1.833f; - } - else - { - innerScale = 1.375f; - } - - // Now set the bounds for the InputOverlayDrawableJoystick. - // This will dictate where on the screen (and the what the size) the InputOverlayDrawableJoystick will be. - int outerSize = bitmapOuter.getWidth(); - Rect outerRect = new Rect(drawableX, drawableY, drawableX + outerSize, drawableY + outerSize); - Rect innerRect = new Rect(0, 0, (int) (outerSize / innerScale), (int) (outerSize / innerScale)); - - // Send the drawableId to the joystick so it can be referenced when saving control position. - final InputOverlayDrawableJoystick overlayDrawable = - new InputOverlayDrawableJoystick(res, bitmapOuter, bitmapInnerDefault, - bitmapInnerPressed, outerRect, innerRect, legacyId, xControl, yControl, - mControllerIndex); - - // Need to set the image's position - overlayDrawable.setPosition(drawableX, drawableY); - overlayDrawable.setOpacity(IntSetting.MAIN_CONTROL_OPACITY.getInt() * 255 / 100); - - return overlayDrawable; - } - - public void setIsInEditMode(boolean isInEditMode) - { - mIsInEditMode = isInEditMode; - } - - public boolean isInEditMode() - { - return mIsInEditMode; - } - - private void defaultOverlay() - { - if (!mPreferences.getBoolean("OverlayInitV2", false)) - { - // It's possible that a user has created their overlay before this was added - // Only change the overlay if the 'A' button is not in the upper corner. - // GameCube - if (mPreferences.getFloat(ButtonType.BUTTON_A + "-X", 0f) == 0f) - { - gcDefaultOverlay(); - } - if (mPreferences.getFloat(ButtonType.BUTTON_A + "-Portrait" + "-X", 0f) == 0f) - { - gcPortraitDefaultOverlay(); - } - - // Wii - if (mPreferences.getFloat(ButtonType.WIIMOTE_BUTTON_A + "-X", 0f) == 0f) - { - wiiDefaultOverlay(); - } - if (mPreferences.getFloat(ButtonType.WIIMOTE_BUTTON_A + "-Portrait" + "-X", 0f) == 0f) - { - wiiPortraitDefaultOverlay(); - } - - // Wii Classic - if (mPreferences.getFloat(ButtonType.CLASSIC_BUTTON_A + "-X", 0f) == 0f) - { - wiiClassicDefaultOverlay(); - } - if (mPreferences.getFloat(ButtonType.CLASSIC_BUTTON_A + "-Portrait" + "-X", 0f) == 0f) - { - wiiClassicPortraitDefaultOverlay(); - } - } - - if (!mPreferences.getBoolean("OverlayInitV3", false)) - { - wiiOnlyDefaultOverlay(); - wiiOnlyPortraitDefaultOverlay(); - } - - SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); - sPrefsEditor.putBoolean("OverlayInitV2", true); - sPrefsEditor.putBoolean("OverlayInitV3", true); - sPrefsEditor.apply(); - } - - private void gcDefaultOverlay() - { - SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); - - // Get screen size - Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); - DisplayMetrics outMetrics = new DisplayMetrics(); - display.getMetrics(outMetrics); - float maxX = outMetrics.heightPixels; - float maxY = outMetrics.widthPixels; - // Height and width changes depending on orientation. Use the larger value for height. - if (maxY > maxX) - { - float tmp = maxX; - maxX = maxY; - maxY = tmp; - } - Resources res = getResources(); - - // Each value is a percent from max X/Y stored as an int. Have to bring that value down - // to a decimal before multiplying by MAX X/Y. - sPrefsEditor.putFloat(ButtonType.BUTTON_A + "-X", - (((float) res.getInteger(R.integer.BUTTON_A_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_A + "-Y", - (((float) res.getInteger(R.integer.BUTTON_A_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_B + "-X", - (((float) res.getInteger(R.integer.BUTTON_B_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_B + "-Y", - (((float) res.getInteger(R.integer.BUTTON_B_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_X + "-X", - (((float) res.getInteger(R.integer.BUTTON_X_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_X + "-Y", - (((float) res.getInteger(R.integer.BUTTON_X_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_Y + "-X", - (((float) res.getInteger(R.integer.BUTTON_Y_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_Y + "-Y", - (((float) res.getInteger(R.integer.BUTTON_Y_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_Z + "-X", - (((float) res.getInteger(R.integer.BUTTON_Z_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_Z + "-Y", - (((float) res.getInteger(R.integer.BUTTON_Z_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_UP + "-X", - (((float) res.getInteger(R.integer.BUTTON_UP_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_UP + "-Y", - (((float) res.getInteger(R.integer.BUTTON_UP_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.TRIGGER_L + "-X", - (((float) res.getInteger(R.integer.TRIGGER_L_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.TRIGGER_L + "-Y", - (((float) res.getInteger(R.integer.TRIGGER_L_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.TRIGGER_R + "-X", - (((float) res.getInteger(R.integer.TRIGGER_R_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.TRIGGER_R + "-Y", - (((float) res.getInteger(R.integer.TRIGGER_R_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_START + "-X", - (((float) res.getInteger(R.integer.BUTTON_START_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_START + "-Y", - (((float) res.getInteger(R.integer.BUTTON_START_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.STICK_C + "-X", - (((float) res.getInteger(R.integer.STICK_C_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.STICK_C + "-Y", - (((float) res.getInteger(R.integer.STICK_C_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.STICK_MAIN + "-X", - (((float) res.getInteger(R.integer.STICK_MAIN_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.STICK_MAIN + "-Y", - (((float) res.getInteger(R.integer.STICK_MAIN_Y) / 1000) * maxY)); - - // We want to commit right away, otherwise the overlay could load before this is saved. - sPrefsEditor.commit(); - } - - private void gcPortraitDefaultOverlay() - { - SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); - - // Get screen size - Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); - DisplayMetrics outMetrics = new DisplayMetrics(); - display.getMetrics(outMetrics); - float maxX = outMetrics.heightPixels; - float maxY = outMetrics.widthPixels; - // Height and width changes depending on orientation. Use the larger value for height. - if (maxY < maxX) - { - float tmp = maxX; - maxX = maxY; - maxY = tmp; - } - Resources res = getResources(); - String portrait = "-Portrait"; - - // Each value is a percent from max X/Y stored as an int. Have to bring that value down - // to a decimal before multiplying by MAX X/Y. - sPrefsEditor.putFloat(ButtonType.BUTTON_A + portrait + "-X", - (((float) res.getInteger(R.integer.BUTTON_A_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_A + portrait + "-Y", - (((float) res.getInteger(R.integer.BUTTON_A_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_B + portrait + "-X", - (((float) res.getInteger(R.integer.BUTTON_B_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_B + portrait + "-Y", - (((float) res.getInteger(R.integer.BUTTON_B_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_X + portrait + "-X", - (((float) res.getInteger(R.integer.BUTTON_X_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_X + portrait + "-Y", - (((float) res.getInteger(R.integer.BUTTON_X_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_Y + portrait + "-X", - (((float) res.getInteger(R.integer.BUTTON_Y_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_Y + portrait + "-Y", - (((float) res.getInteger(R.integer.BUTTON_Y_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_Z + portrait + "-X", - (((float) res.getInteger(R.integer.BUTTON_Z_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_Z + portrait + "-Y", - (((float) res.getInteger(R.integer.BUTTON_Z_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_UP + portrait + "-X", - (((float) res.getInteger(R.integer.BUTTON_UP_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_UP + portrait + "-Y", - (((float) res.getInteger(R.integer.BUTTON_UP_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.TRIGGER_L + portrait + "-X", - (((float) res.getInteger(R.integer.TRIGGER_L_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.TRIGGER_L + portrait + "-Y", - (((float) res.getInteger(R.integer.TRIGGER_L_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.TRIGGER_R + portrait + "-X", - (((float) res.getInteger(R.integer.TRIGGER_R_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.TRIGGER_R + portrait + "-Y", - (((float) res.getInteger(R.integer.TRIGGER_R_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.BUTTON_START + portrait + "-X", - (((float) res.getInteger(R.integer.BUTTON_START_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.BUTTON_START + portrait + "-Y", - (((float) res.getInteger(R.integer.BUTTON_START_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.STICK_C + portrait + "-X", - (((float) res.getInteger(R.integer.STICK_C_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.STICK_C + portrait + "-Y", - (((float) res.getInteger(R.integer.STICK_C_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.STICK_MAIN + portrait + "-X", - (((float) res.getInteger(R.integer.STICK_MAIN_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.STICK_MAIN + portrait + "-Y", - (((float) res.getInteger(R.integer.STICK_MAIN_PORTRAIT_Y) / 1000) * maxY)); - - // We want to commit right away, otherwise the overlay could load before this is saved. - sPrefsEditor.commit(); - } - - private void wiiDefaultOverlay() - { - SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); - - // Get screen size - Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); - DisplayMetrics outMetrics = new DisplayMetrics(); - display.getMetrics(outMetrics); - float maxX = outMetrics.heightPixels; - float maxY = outMetrics.widthPixels; - // Height and width changes depending on orientation. Use the larger value for maxX. - if (maxY > maxX) - { - float tmp = maxX; - maxX = maxY; - maxY = tmp; - } - Resources res = getResources(); - - // Each value is a percent from max X/Y stored as an int. Have to bring that value down - // to a decimal before multiplying by MAX X/Y. - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_A + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_A_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_A + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_A_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_B + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_B_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_B + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_B_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_1 + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_1_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_1 + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_1_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_2 + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_2_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_2 + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_2_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_BUTTON_Z + "-X", - (((float) res.getInteger(R.integer.NUNCHUK_BUTTON_Z_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_BUTTON_Z + "-Y", - (((float) res.getInteger(R.integer.NUNCHUK_BUTTON_Z_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_BUTTON_C + "-X", - (((float) res.getInteger(R.integer.NUNCHUK_BUTTON_C_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_BUTTON_C + "-Y", - (((float) res.getInteger(R.integer.NUNCHUK_BUTTON_C_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_MINUS + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_MINUS_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_MINUS + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_MINUS_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_PLUS + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_PLUS_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_PLUS + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_PLUS_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_UP + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_UP_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_UP + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_UP_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_HOME + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_HOME_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_HOME + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_HOME_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_STICK + "-X", - (((float) res.getInteger(R.integer.NUNCHUK_STICK_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_STICK + "-Y", - (((float) res.getInteger(R.integer.NUNCHUK_STICK_Y) / 1000) * maxY)); - - // We want to commit right away, otherwise the overlay could load before this is saved. - sPrefsEditor.commit(); - } - - private void wiiOnlyDefaultOverlay() - { - SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); - - // Get screen size - Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); - DisplayMetrics outMetrics = new DisplayMetrics(); - display.getMetrics(outMetrics); - float maxX = outMetrics.heightPixels; - float maxY = outMetrics.widthPixels; - // Height and width changes depending on orientation. Use the larger value for maxX. - if (maxY > maxX) - { - float tmp = maxX; - maxX = maxY; - maxY = tmp; - } - Resources res = getResources(); - - // Each value is a percent from max X/Y stored as an int. Have to bring that value down - // to a decimal before multiplying by MAX X/Y. - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_A + "_H-X", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_A_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_A + "_H-Y", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_A_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_B + "_H-X", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_B_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_B + "_H-Y", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_B_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_1 + "_H-X", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_1_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_1 + "_H-Y", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_1_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_2 + "_H-X", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_2_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_2 + "_H-Y", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_2_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_UP + "_O-X", - (((float) res.getInteger(R.integer.WIIMOTE_O_UP_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_UP + "_O-Y", - (((float) res.getInteger(R.integer.WIIMOTE_O_UP_Y) / 1000) * maxY)); - - // Horizontal dpad - sPrefsEditor.putFloat(ButtonType.WIIMOTE_RIGHT + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_RIGHT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_RIGHT + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_RIGHT_Y) / 1000) * maxY)); - - // We want to commit right away, otherwise the overlay could load before this is saved. - sPrefsEditor.commit(); - } - - private void wiiPortraitDefaultOverlay() - { - SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); - - // Get screen size - Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); - DisplayMetrics outMetrics = new DisplayMetrics(); - display.getMetrics(outMetrics); - float maxX = outMetrics.heightPixels; - float maxY = outMetrics.widthPixels; - // Height and width changes depending on orientation. Use the larger value for maxX. - if (maxY < maxX) - { - float tmp = maxX; - maxX = maxY; - maxY = tmp; - } - Resources res = getResources(); - String portrait = "-Portrait"; - - // Each value is a percent from max X/Y stored as an int. Have to bring that value down - // to a decimal before multiplying by MAX X/Y. - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_A + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_A_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_A + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_A_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_B + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_B_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_B + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_B_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_1 + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_1_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_1 + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_1_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_2 + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_2_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_2 + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_2_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_BUTTON_Z + portrait + "-X", - (((float) res.getInteger(R.integer.NUNCHUK_BUTTON_Z_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_BUTTON_Z + portrait + "-Y", - (((float) res.getInteger(R.integer.NUNCHUK_BUTTON_Z_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_BUTTON_C + portrait + "-X", - (((float) res.getInteger(R.integer.NUNCHUK_BUTTON_C_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_BUTTON_C + portrait + "-Y", - (((float) res.getInteger(R.integer.NUNCHUK_BUTTON_C_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_MINUS + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_MINUS_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_MINUS + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_MINUS_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_PLUS + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_PLUS_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_PLUS + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_PLUS_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_UP + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_UP_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_UP + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_UP_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_HOME + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_HOME_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_HOME + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_BUTTON_HOME_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_STICK + portrait + "-X", - (((float) res.getInteger(R.integer.NUNCHUK_STICK_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.NUNCHUK_STICK + portrait + "-Y", - (((float) res.getInteger(R.integer.NUNCHUK_STICK_PORTRAIT_Y) / 1000) * maxY)); - // Horizontal dpad - sPrefsEditor.putFloat(ButtonType.WIIMOTE_RIGHT + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_RIGHT_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_RIGHT + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_RIGHT_PORTRAIT_Y) / 1000) * maxY)); - - // We want to commit right away, otherwise the overlay could load before this is saved. - sPrefsEditor.commit(); - } - - private void wiiOnlyPortraitDefaultOverlay() - { - SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); - - // Get screen size - Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); - DisplayMetrics outMetrics = new DisplayMetrics(); - display.getMetrics(outMetrics); - float maxX = outMetrics.heightPixels; - float maxY = outMetrics.widthPixels; - // Height and width changes depending on orientation. Use the larger value for maxX. - if (maxY < maxX) - { - float tmp = maxX; - maxX = maxY; - maxY = tmp; - } - Resources res = getResources(); - String portrait = "-Portrait"; - - // Each value is a percent from max X/Y stored as an int. Have to bring that value down - // to a decimal before multiplying by MAX X/Y. - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_A + "_H" + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_A_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_A + "_H" + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_A_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_B + "_H" + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_B_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_B + "_H" + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_B_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_1 + "_H" + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_1_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_1 + "_H" + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_1_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_2 + "_H" + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_2_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_BUTTON_2 + "_H" + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_H_BUTTON_2_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_UP + "_O" + portrait + "-X", - (((float) res.getInteger(R.integer.WIIMOTE_O_UP_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.WIIMOTE_UP + "_O" + portrait + "-Y", - (((float) res.getInteger(R.integer.WIIMOTE_O_UP_PORTRAIT_Y) / 1000) * maxY)); - - // We want to commit right away, otherwise the overlay could load before this is saved. - sPrefsEditor.commit(); - } - - private void wiiClassicDefaultOverlay() - { - SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); - - // Get screen size - Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); - DisplayMetrics outMetrics = new DisplayMetrics(); - display.getMetrics(outMetrics); - float maxX = outMetrics.heightPixels; - float maxY = outMetrics.widthPixels; - // Height and width changes depending on orientation. Use the larger value for maxX. - if (maxY > maxX) - { - float tmp = maxX; - maxX = maxY; - maxY = tmp; - } - Resources res = getResources(); - - // Each value is a percent from max X/Y stored as an int. Have to bring that value down - // to a decimal before multiplying by MAX X/Y. - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_A + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_A_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_A + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_A_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_B + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_B_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_B + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_B_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_X + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_X_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_X + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_X_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_Y + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_Y_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_Y + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_Y_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_MINUS + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_MINUS_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_MINUS + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_MINUS_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_PLUS + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_PLUS_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_PLUS + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_PLUS_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_HOME + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_HOME_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_HOME + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_HOME_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_ZL + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_ZL_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_ZL + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_ZL_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_ZR + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_ZR_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_ZR + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_ZR_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_DPAD_UP + "-X", - (((float) res.getInteger(R.integer.CLASSIC_DPAD_UP_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_DPAD_UP + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_DPAD_UP_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_STICK_LEFT + "-X", - (((float) res.getInteger(R.integer.CLASSIC_STICK_LEFT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_STICK_LEFT + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_STICK_LEFT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_STICK_RIGHT + "-X", - (((float) res.getInteger(R.integer.CLASSIC_STICK_RIGHT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_STICK_RIGHT + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_STICK_RIGHT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_TRIGGER_L + "-X", - (((float) res.getInteger(R.integer.CLASSIC_TRIGGER_L_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_TRIGGER_L + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_TRIGGER_L_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_TRIGGER_R + "-X", - (((float) res.getInteger(R.integer.CLASSIC_TRIGGER_R_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_TRIGGER_R + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_TRIGGER_R_Y) / 1000) * maxY)); - - // We want to commit right away, otherwise the overlay could load before this is saved. - sPrefsEditor.commit(); - } - - private void wiiClassicPortraitDefaultOverlay() - { - SharedPreferences.Editor sPrefsEditor = mPreferences.edit(); - - // Get screen size - Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay(); - DisplayMetrics outMetrics = new DisplayMetrics(); - display.getMetrics(outMetrics); - float maxX = outMetrics.heightPixels; - float maxY = outMetrics.widthPixels; - // Height and width changes depending on orientation. Use the larger value for maxX. - if (maxY < maxX) - { - float tmp = maxX; - maxX = maxY; - maxY = tmp; - } - Resources res = getResources(); - String portrait = "-Portrait"; - - // Each value is a percent from max X/Y stored as an int. Have to bring that value down - // to a decimal before multiplying by MAX X/Y. - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_A + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_A_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_A + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_A_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_B + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_B_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_B + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_B_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_X + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_X_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_X + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_X_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_Y + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_Y_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_Y + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_Y_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_MINUS + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_MINUS_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_MINUS + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_MINUS_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_PLUS + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_PLUS_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_PLUS + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_PLUS_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_HOME + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_HOME_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_HOME + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_HOME_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_ZL + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_ZL_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_ZL + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_ZL_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_ZR + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_ZR_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_BUTTON_ZR + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_BUTTON_ZR_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_DPAD_UP + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_DPAD_UP_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_DPAD_UP + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_DPAD_UP_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_STICK_LEFT + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_STICK_LEFT_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_STICK_LEFT + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_STICK_LEFT_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_STICK_RIGHT + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_STICK_RIGHT_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_STICK_RIGHT + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_STICK_RIGHT_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_TRIGGER_L + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_TRIGGER_L_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_TRIGGER_L + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_TRIGGER_L_PORTRAIT_Y) / 1000) * maxY)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_TRIGGER_R + portrait + "-X", - (((float) res.getInteger(R.integer.CLASSIC_TRIGGER_R_PORTRAIT_X) / 1000) * maxX)); - sPrefsEditor.putFloat(ButtonType.CLASSIC_TRIGGER_R + portrait + "-Y", - (((float) res.getInteger(R.integer.CLASSIC_TRIGGER_R_PORTRAIT_Y) / 1000) * maxY)); - - // We want to commit right away, otherwise the overlay could load before this is saved. - sPrefsEditor.commit(); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.kt new file mode 100644 index 0000000000..e42e96f0bb --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlay.kt @@ -0,0 +1,2342 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.overlay + +import android.app.Activity +import android.content.Context +import android.content.SharedPreferences +import android.content.res.Configuration +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.Rect +import android.util.AttributeSet +import android.util.DisplayMetrics +import android.view.MotionEvent +import android.view.SurfaceView +import android.view.View +import android.view.View.OnTouchListener +import android.widget.Toast +import androidx.preference.PreferenceManager +import org.dolphinemu.dolphinemu.DolphinApplication +import org.dolphinemu.dolphinemu.NativeLibrary +import org.dolphinemu.dolphinemu.NativeLibrary.ButtonType +import org.dolphinemu.dolphinemu.R +import org.dolphinemu.dolphinemu.features.input.model.InputMappingBooleanSetting +import org.dolphinemu.dolphinemu.features.input.model.InputOverrider +import org.dolphinemu.dolphinemu.features.input.model.InputOverrider.ControlId +import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController +import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting +import org.dolphinemu.dolphinemu.features.settings.model.IntSetting +import org.dolphinemu.dolphinemu.features.settings.model.IntSetting.Companion.getSettingForSIDevice +import org.dolphinemu.dolphinemu.features.settings.model.IntSetting.Companion.getSettingForWiimoteSource +import java.util.Arrays + +/** + * Draws the interactive input overlay on top of the + * [SurfaceView] that is rendering emulation. + * + * @param context The current [Context]. + * @param attrs [AttributeSet] for parsing XML attributes. + */ +class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(context, attrs), + OnTouchListener { + private val overlayButtons: MutableSet = HashSet() + private val overlayDpads: MutableSet = HashSet() + private val overlayJoysticks: MutableSet = HashSet() + private var overlayPointer: InputOverlayPointer? = null + + private var surfacePosition: Rect? = null + + private var isFirstRun = true + private val gcPadRegistered = BooleanArray(4) + private val wiimoteRegistered = BooleanArray(4) + var editMode = false + private var controllerType = -1 + private var controllerIndex = 0 + private var buttonBeingConfigured: InputOverlayDrawableButton? = null + private var dpadBeingConfigured: InputOverlayDrawableDpad? = null + private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null + + private val preferences: SharedPreferences + get() = + PreferenceManager.getDefaultSharedPreferences(DolphinApplication.getAppContext()) + + init { + if (!preferences.getBoolean("OverlayInitV3", false)) + defaultOverlay() + + // Set the on touch listener. + setOnTouchListener(this) + + // Force draw + setWillNotDraw(false) + + // Request focus for the overlay so it has priority on presses. + requestFocus() + } + + fun setSurfacePosition(rect: Rect?) { + surfacePosition = rect + initTouchPointer() + } + + fun initTouchPointer() { + // Check if we have all the data we need yet + val aspectRatioAvailable = NativeLibrary.IsRunningAndStarted() + if (!aspectRatioAvailable || surfacePosition == null) + return + + // Check if there's any point in running the pointer code + if (!NativeLibrary.IsEmulatingWii()) + return + + var doubleTapButton = IntSetting.MAIN_DOUBLE_TAP_BUTTON.int + + if (configuredControllerType != OVERLAY_WIIMOTE_CLASSIC && + doubleTapButton == ButtonType.CLASSIC_BUTTON_A + ) { + doubleTapButton = ButtonType.WIIMOTE_BUTTON_A + } + + var doubleTapControl = ControlId.WIIMOTE_A_BUTTON + when (doubleTapButton) { + ButtonType.WIIMOTE_BUTTON_A -> doubleTapControl = ControlId.WIIMOTE_A_BUTTON + ButtonType.WIIMOTE_BUTTON_B -> doubleTapControl = ControlId.WIIMOTE_B_BUTTON + ButtonType.WIIMOTE_BUTTON_2 -> doubleTapControl = ControlId.WIIMOTE_TWO_BUTTON + } + + overlayPointer = InputOverlayPointer( + surfacePosition!!, + doubleTapControl, + IntSetting.MAIN_IR_MODE.int, + BooleanSetting.MAIN_IR_ALWAYS_RECENTER.boolean, + controllerIndex + ) + } + + override fun draw(canvas: Canvas) { + super.draw(canvas) + + for (button in overlayButtons) { + button.draw(canvas) + } + + for (dpad in overlayDpads) { + dpad.draw(canvas) + } + + for (joystick in overlayJoysticks) { + joystick.draw(canvas) + } + } + + override fun onTouch(v: View, event: MotionEvent): Boolean { + if (editMode) { + return onTouchWhileEditing(event) + } + + val action = event.actionMasked + val firstPointer = action != MotionEvent.ACTION_POINTER_DOWN && + action != MotionEvent.ACTION_POINTER_UP + val pointerIndex = if (firstPointer) 0 else event.actionIndex + // Tracks if any button/joystick is pressed down + var pressed = false + + for (button in overlayButtons) { + // Determine the button state to apply based on the MotionEvent action flag. + when (action) { + MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_POINTER_DOWN -> { + // If a pointer enters the bounds of a button, press that button. + if (button.bounds.contains( + event.getX(pointerIndex).toInt(), + event.getY(pointerIndex).toInt() + ) + ) { + button.setPressedState(true) + button.trackId = event.getPointerId(pointerIndex) + pressed = true + InputOverrider.setControlState(controllerIndex, button.control, 1.0) + + val analogControl = getAnalogControlForTrigger(button.control) + if (analogControl >= 0) + InputOverrider.setControlState( + controllerIndex, + analogControl, + 1.0 + ) + } + } + + MotionEvent.ACTION_UP, + MotionEvent.ACTION_POINTER_UP -> { + // If a pointer ends, release the button it was pressing. + if (button.trackId == event.getPointerId(pointerIndex)) { + button.setPressedState(false) + InputOverrider.setControlState(controllerIndex, button.control, 0.0) + + val analogControl = getAnalogControlForTrigger(button.control) + if (analogControl >= 0) + InputOverrider.setControlState( + controllerIndex, + analogControl, + 0.0 + ) + + button.trackId = -1 + } + } + } + } + + for (dpad in overlayDpads) { + // Determine the button state to apply based on the MotionEvent action flag. + when (event.action and MotionEvent.ACTION_MASK) { + MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_POINTER_DOWN -> { + // If a pointer enters the bounds of a button, press that button. + if (dpad.bounds + .contains( + event.getX(pointerIndex).toInt(), + event.getY(pointerIndex).toInt() + ) + ) { + dpad.trackId = event.getPointerId(pointerIndex) + pressed = true + } + } + + MotionEvent.ACTION_MOVE -> { + if (dpad.trackId == event.getPointerId(pointerIndex)) { + val dpadPressed = booleanArrayOf(false, false, false, false) + + if (dpad.bounds.top + dpad.height / 3 > event.getY(pointerIndex).toInt()) + dpadPressed[0] = true + if (dpad.bounds.bottom - dpad.height / 3 < event.getY(pointerIndex).toInt()) + dpadPressed[1] = true + if (dpad.bounds.left + dpad.width / 3 > event.getX(pointerIndex).toInt()) + dpadPressed[2] = true + if (dpad.bounds.right - dpad.width / 3 < event.getX(pointerIndex).toInt()) + dpadPressed[3] = true + + // Release the buttons first, then press + for (i in 1 until dpadPressed.size) { + if (!dpadPressed[i]) { + InputOverrider.setControlState( + controllerIndex, + dpad.getControl(i), + 0.0 + ) + } else { + InputOverrider.setControlState( + controllerIndex, + dpad.getControl(i), + 1.0 + ) + } + } + setDpadState( + dpad, + dpadPressed[0], + dpadPressed[1], + dpadPressed[2], + dpadPressed[3] + ) + } + } + + MotionEvent.ACTION_UP, + MotionEvent.ACTION_POINTER_UP -> { + // If a pointer ends, release the buttons. + if (dpad.trackId == event.getPointerId(pointerIndex)) { + for (i in 0 until 4) { + dpad.setState(InputOverlayDrawableDpad.STATE_DEFAULT) + InputOverrider.setControlState( + controllerIndex, + dpad.getControl(i), + 0.0 + ) + } + dpad.trackId = -1 + } + } + } + } + + for (joystick in overlayJoysticks) { + if (joystick.trackEvent(event)) { + if (joystick.trackId != -1) + pressed = true + } + + InputOverrider.setControlState( + controllerIndex, + joystick.xControl, + joystick.x.toDouble() + ) + InputOverrider.setControlState( + controllerIndex, + joystick.yControl, + -joystick.y.toDouble() + ) + } + + // No button/joystick pressed, safe to move pointer + if (!pressed && overlayPointer != null) { + overlayPointer!!.onTouch(event) + InputOverrider.setControlState( + controllerIndex, + ControlId.WIIMOTE_IR_X, + overlayPointer!!.x.toDouble() + ) + InputOverrider.setControlState( + controllerIndex, + ControlId.WIIMOTE_IR_Y, + -overlayPointer!!.y.toDouble() + ) + } + + invalidate() + + return true + } + + fun onTouchWhileEditing(event: MotionEvent): Boolean { + val pointerIndex = event.actionIndex + val fingerPositionX = event.getX(pointerIndex).toInt() + val fingerPositionY = event.getY(pointerIndex).toInt() + + val orientation = + if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) "-Portrait" else "" + + // Maybe combine Button and Joystick as subclasses of the same parent? + // Or maybe create an interface like IMoveableHUDControl? + + for (button in overlayButtons) { + // Determine the button state to apply based on the MotionEvent action flag. + when (event.action and MotionEvent.ACTION_MASK) { + MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_POINTER_DOWN -> { + // If no button is being moved now, remember the currently touched button to move. + if (buttonBeingConfigured == null && + button.bounds.contains(fingerPositionX, fingerPositionY) + ) { + buttonBeingConfigured = button + buttonBeingConfigured?.onConfigureTouch(event) + } + } + + MotionEvent.ACTION_MOVE -> { + if (buttonBeingConfigured != null) { + buttonBeingConfigured?.onConfigureTouch(event) + invalidate() + return true + } + } + + MotionEvent.ACTION_UP, + MotionEvent.ACTION_POINTER_UP -> { + if (buttonBeingConfigured == button) { + // Persist button position by saving new place. + saveControlPosition( + buttonBeingConfigured!!.legacyId, + buttonBeingConfigured!!.bounds.left, + buttonBeingConfigured!!.bounds.top, orientation + ) + buttonBeingConfigured = null + } + } + } + } + + for (dpad in overlayDpads) { + // Determine the button state to apply based on the MotionEvent action flag. + when (event.action and MotionEvent.ACTION_MASK) { + MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_POINTER_DOWN -> { + // If no button is being moved now, remember the currently touched button to move. + if (buttonBeingConfigured == null && + dpad.bounds.contains(fingerPositionX, fingerPositionY) + ) { + dpadBeingConfigured = dpad + dpadBeingConfigured?.onConfigureTouch(event) + } + } + + MotionEvent.ACTION_MOVE -> { + if (dpadBeingConfigured != null) { + dpadBeingConfigured?.onConfigureTouch(event) + invalidate() + return true + } + } + + MotionEvent.ACTION_UP, + MotionEvent.ACTION_POINTER_UP -> { + if (dpadBeingConfigured == dpad) { + // Persist button position by saving new place. + saveControlPosition( + dpadBeingConfigured!!.legacyId, + dpadBeingConfigured!!.bounds.left, + dpadBeingConfigured!!.bounds.top, + orientation + ) + dpadBeingConfigured = null + } + } + } + } + + for (joystick in overlayJoysticks) { + when (event.action) { + MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_POINTER_DOWN -> { + if (joystickBeingConfigured == null && + joystick.bounds.contains(fingerPositionX, fingerPositionY) + ) { + joystickBeingConfigured = joystick + joystickBeingConfigured?.onConfigureTouch(event) + } + } + + MotionEvent.ACTION_MOVE -> { + if (joystickBeingConfigured != null) { + joystickBeingConfigured?.onConfigureTouch(event) + invalidate() + } + } + + MotionEvent.ACTION_UP, + MotionEvent.ACTION_POINTER_UP -> { + if (joystickBeingConfigured != null) { + saveControlPosition( + joystickBeingConfigured!!.legacyId, + joystickBeingConfigured!!.bounds.left, + joystickBeingConfigured!!.bounds.top, + orientation + ) + joystickBeingConfigured = null + } + } + } + } + return true + } + + fun onDestroy() { + unregisterControllers() + } + + private fun unregisterControllers() { + for (i in gcPadRegistered.indices) { + if (gcPadRegistered[i]) + InputOverrider.unregisterGameCube(i) + } + + for (i in wiimoteRegistered.indices) { + if (wiimoteRegistered[i]) + InputOverrider.unregisterWii(i) + } + + Arrays.fill(gcPadRegistered, false) + Arrays.fill(wiimoteRegistered, false) + } + + private fun getAnalogControlForTrigger(control: Int): Int = when (control) { + ControlId.GCPAD_L_DIGITAL -> ControlId.GCPAD_L_ANALOG + ControlId.GCPAD_R_DIGITAL -> ControlId.GCPAD_R_ANALOG + ControlId.CLASSIC_L_DIGITAL -> ControlId.CLASSIC_L_ANALOG + ControlId.CLASSIC_R_DIGITAL -> ControlId.CLASSIC_R_ANALOG + else -> -1 + } + + private fun setDpadState( + dpad: InputOverlayDrawableDpad, + up: Boolean, + down: Boolean, + left: Boolean, + right: Boolean + ) { + 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 fun addGameCubeOverlayControls(orientation: String) { + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_0.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.gcpad_a, + R.drawable.gcpad_a_pressed, + ButtonType.BUTTON_A, + ControlId.GCPAD_A_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_1.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.gcpad_b, + R.drawable.gcpad_b_pressed, + ButtonType.BUTTON_B, + ControlId.GCPAD_B_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_2.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.gcpad_x, + R.drawable.gcpad_x_pressed, + ButtonType.BUTTON_X, + ControlId.GCPAD_X_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_3.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.gcpad_y, + R.drawable.gcpad_y_pressed, + ButtonType.BUTTON_Y, + ControlId.GCPAD_Y_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_4.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.gcpad_z, + R.drawable.gcpad_z_pressed, + ButtonType.BUTTON_Z, + ControlId.GCPAD_Z_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_5.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.gcpad_start, + R.drawable.gcpad_start_pressed, + ButtonType.BUTTON_START, + ControlId.GCPAD_START_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_6.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.gcpad_l, + R.drawable.gcpad_l_pressed, + ButtonType.TRIGGER_L, + ControlId.GCPAD_L_DIGITAL, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_7.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.gcpad_r, + R.drawable.gcpad_r_pressed, + ButtonType.TRIGGER_R, + ControlId.GCPAD_R_DIGITAL, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_8.boolean) { + overlayDpads.add( + initializeOverlayDpad( + context, + R.drawable.gcwii_dpad, + R.drawable.gcwii_dpad_pressed_one_direction, + R.drawable.gcwii_dpad_pressed_two_directions, + ButtonType.BUTTON_UP, + ControlId.GCPAD_DPAD_UP, + ControlId.GCPAD_DPAD_DOWN, + ControlId.GCPAD_DPAD_LEFT, + ControlId.GCPAD_DPAD_RIGHT, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_9.boolean) { + overlayJoysticks.add( + initializeOverlayJoystick( + context, + R.drawable.gcwii_joystick_range, + R.drawable.gcwii_joystick, + R.drawable.gcwii_joystick_pressed, + ButtonType.STICK_MAIN, + ControlId.GCPAD_MAIN_STICK_X, + ControlId.GCPAD_MAIN_STICK_Y, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_GC_10.boolean) { + overlayJoysticks.add( + initializeOverlayJoystick( + context, + R.drawable.gcwii_joystick_range, + R.drawable.gcpad_c, + R.drawable.gcpad_c_pressed, + ButtonType.STICK_C, + ControlId.GCPAD_C_STICK_X, + ControlId.GCPAD_C_STICK_Y, + orientation + ) + ) + } + } + + private fun addWiimoteOverlayControls(orientation: String) { + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_0.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_a, + R.drawable.wiimote_a_pressed, + ButtonType.WIIMOTE_BUTTON_A, + ControlId.WIIMOTE_A_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_1.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_b, + R.drawable.wiimote_b_pressed, + ButtonType.WIIMOTE_BUTTON_B, + ControlId.WIIMOTE_B_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_2.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_one, + R.drawable.wiimote_one_pressed, + ButtonType.WIIMOTE_BUTTON_1, + ControlId.WIIMOTE_ONE_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_3.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_two, + R.drawable.wiimote_two_pressed, + ButtonType.WIIMOTE_BUTTON_2, + ControlId.WIIMOTE_TWO_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_4.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_plus, + R.drawable.wiimote_plus_pressed, + ButtonType.WIIMOTE_BUTTON_PLUS, + ControlId.WIIMOTE_PLUS_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_5.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_minus, + R.drawable.wiimote_minus_pressed, + ButtonType.WIIMOTE_BUTTON_MINUS, + ControlId.WIIMOTE_MINUS_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_6.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_home, + R.drawable.wiimote_home_pressed, + ButtonType.WIIMOTE_BUTTON_HOME, + ControlId.WIIMOTE_HOME_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_7.boolean) { + overlayDpads.add( + initializeOverlayDpad( + context, + R.drawable.gcwii_dpad, + R.drawable.gcwii_dpad_pressed_one_direction, + R.drawable.gcwii_dpad_pressed_two_directions, + ButtonType.WIIMOTE_UP, + ControlId.WIIMOTE_DPAD_UP, + ControlId.WIIMOTE_DPAD_DOWN, + ControlId.WIIMOTE_DPAD_LEFT, + ControlId.WIIMOTE_DPAD_RIGHT, + orientation + ) + ) + } + } + + private fun addNunchukOverlayControls(orientation: String) { + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_8.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.nunchuk_c, + R.drawable.nunchuk_c_pressed, + ButtonType.NUNCHUK_BUTTON_C, + ControlId.NUNCHUK_C_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_9.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.nunchuk_z, + R.drawable.nunchuk_z_pressed, + ButtonType.NUNCHUK_BUTTON_Z, + ControlId.NUNCHUK_Z_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_WII_10.boolean) { + overlayJoysticks.add( + initializeOverlayJoystick( + context, + R.drawable.gcwii_joystick_range, + R.drawable.gcwii_joystick, + R.drawable.gcwii_joystick_pressed, + ButtonType.NUNCHUK_STICK, + ControlId.NUNCHUK_STICK_X, + ControlId.NUNCHUK_STICK_Y, + orientation + ) + ) + } + } + + private fun addClassicOverlayControls(orientation: String) { + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_0.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.classic_a, + R.drawable.classic_a_pressed, + ButtonType.CLASSIC_BUTTON_A, + ControlId.CLASSIC_A_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_1.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.classic_b, + R.drawable.classic_b_pressed, + ButtonType.CLASSIC_BUTTON_B, + ControlId.CLASSIC_B_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_2.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.classic_x, + R.drawable.classic_x_pressed, + ButtonType.CLASSIC_BUTTON_X, + ControlId.CLASSIC_X_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_3.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.classic_y, + R.drawable.classic_y_pressed, + ButtonType.CLASSIC_BUTTON_Y, + ControlId.CLASSIC_Y_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_4.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_plus, + R.drawable.wiimote_plus_pressed, + ButtonType.CLASSIC_BUTTON_PLUS, + ControlId.CLASSIC_PLUS_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_5.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_minus, + R.drawable.wiimote_minus_pressed, + ButtonType.CLASSIC_BUTTON_MINUS, + ControlId.CLASSIC_MINUS_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_6.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.wiimote_home, + R.drawable.wiimote_home_pressed, + ButtonType.CLASSIC_BUTTON_HOME, + ControlId.CLASSIC_HOME_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_7.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.classic_l, + R.drawable.classic_l_pressed, + ButtonType.CLASSIC_TRIGGER_L, + ControlId.CLASSIC_L_DIGITAL, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_8.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.classic_r, + R.drawable.classic_r_pressed, + ButtonType.CLASSIC_TRIGGER_R, + ControlId.CLASSIC_R_DIGITAL, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_9.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.classic_zl, + R.drawable.classic_zl_pressed, + ButtonType.CLASSIC_BUTTON_ZL, + ControlId.CLASSIC_ZL_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_10.boolean) { + overlayButtons.add( + initializeOverlayButton( + context, + R.drawable.classic_zr, + R.drawable.classic_zr_pressed, + ButtonType.CLASSIC_BUTTON_ZR, + ControlId.CLASSIC_ZR_BUTTON, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_11.boolean) { + overlayDpads.add( + initializeOverlayDpad( + context, + R.drawable.gcwii_dpad, + R.drawable.gcwii_dpad_pressed_one_direction, + R.drawable.gcwii_dpad_pressed_two_directions, + ButtonType.CLASSIC_DPAD_UP, + ControlId.CLASSIC_DPAD_UP, + ControlId.CLASSIC_DPAD_DOWN, + ControlId.CLASSIC_DPAD_LEFT, + ControlId.CLASSIC_DPAD_RIGHT, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_12.boolean) { + overlayJoysticks.add( + initializeOverlayJoystick( + context, + R.drawable.gcwii_joystick_range, + R.drawable.gcwii_joystick, + R.drawable.gcwii_joystick_pressed, + ButtonType.CLASSIC_STICK_LEFT, + ControlId.CLASSIC_LEFT_STICK_X, + ControlId.CLASSIC_LEFT_STICK_Y, + orientation + ) + ) + } + if (BooleanSetting.MAIN_BUTTON_TOGGLE_CLASSIC_13.boolean) { + overlayJoysticks.add( + initializeOverlayJoystick( + context, + R.drawable.gcwii_joystick_range, + R.drawable.gcwii_joystick, + R.drawable.gcwii_joystick_pressed, + ButtonType.CLASSIC_STICK_RIGHT, + ControlId.CLASSIC_RIGHT_STICK_X, + ControlId.CLASSIC_RIGHT_STICK_Y, + orientation + ) + ) + } + } + + fun refreshControls() { + unregisterControllers() + + // Remove all the overlay buttons from the HashSet. + overlayButtons.removeAll(overlayButtons) + overlayDpads.removeAll(overlayDpads) + overlayJoysticks.removeAll(overlayJoysticks) + + val orientation = + if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) "-Portrait" else "" + + controllerType = configuredControllerType + + val controllerSetting = + if (NativeLibrary.IsEmulatingWii()) IntSetting.MAIN_OVERLAY_WII_CONTROLLER else IntSetting.MAIN_OVERLAY_GC_CONTROLLER + val controllerIndex = controllerSetting.int + + if (BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.boolean) { + // Add all the enabled overlay items back to the HashSet. + when (controllerType) { + OVERLAY_GAMECUBE -> { + if (getSettingForSIDevice(controllerIndex).int == DISABLED_GAMECUBE_CONTROLLER && isFirstRun) { + Toast.makeText( + context, + R.string.disabled_gc_overlay_notice, + Toast.LENGTH_SHORT + ).show() + } + + this.controllerIndex = controllerIndex + InputOverrider.registerGameCube(this.controllerIndex) + gcPadRegistered[this.controllerIndex] = true + + addGameCubeOverlayControls(orientation) + } + + OVERLAY_WIIMOTE, + OVERLAY_WIIMOTE_SIDEWAYS -> { + this.controllerIndex = controllerIndex - 4 + InputOverrider.registerWii(this.controllerIndex) + wiimoteRegistered[this.controllerIndex] = true + + addWiimoteOverlayControls(orientation) + } + + OVERLAY_WIIMOTE_NUNCHUK -> { + this.controllerIndex = controllerIndex - 4 + InputOverrider.registerWii(this.controllerIndex) + wiimoteRegistered[this.controllerIndex] = true + + addWiimoteOverlayControls(orientation) + addNunchukOverlayControls(orientation) + } + + OVERLAY_WIIMOTE_CLASSIC -> { + this.controllerIndex = controllerIndex - 4 + InputOverrider.registerWii(this.controllerIndex) + wiimoteRegistered[this.controllerIndex] = true + + addClassicOverlayControls(orientation) + } + + OVERLAY_NONE -> {} + } + } + + isFirstRun = false + invalidate() + } + + fun refreshOverlayPointer() { + if (overlayPointer != null) { + overlayPointer?.setMode(IntSetting.MAIN_IR_MODE.int) + overlayPointer?.setRecenter(BooleanSetting.MAIN_IR_ALWAYS_RECENTER.boolean) + } + } + + fun resetButtonPlacement() { + val isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE + + val controller = configuredControllerType + if (controller == OVERLAY_GAMECUBE) { + if (isLandscape) { + gcDefaultOverlay() + } else { + gcPortraitDefaultOverlay() + } + } else if (controller == OVERLAY_WIIMOTE_CLASSIC) { + if (isLandscape) { + wiiClassicDefaultOverlay() + } else { + wiiClassicPortraitDefaultOverlay() + } + } else { + if (isLandscape) { + wiiDefaultOverlay() + wiiOnlyDefaultOverlay() + } else { + wiiPortraitDefaultOverlay() + wiiOnlyPortraitDefaultOverlay() + } + } + refreshControls() + } + + private fun saveControlPosition(sharedPrefsId: Int, x: Int, y: Int, orientation: String) { + preferences.edit() + .putFloat(getXKey(sharedPrefsId, controllerType, orientation), x.toFloat()) + .putFloat(getYKey(sharedPrefsId, controllerType, orientation), y.toFloat()) + .apply() + } + + /** + * Initializes an InputOverlayDrawableButton, given by resId, with all of the + * parameters set for it to be properly shown on the InputOverlay. + * + * This works due to the way the X and Y coordinates are stored within + * the [SharedPreferences]. + * + * In the input overlay configuration menu, + * once a touch event begins and then ends (ie. Organizing the buttons to one's own liking for the overlay). + * the X and Y coordinates of the button at the END of its touch event + * (when you remove your finger/stylus from the touchscreen) are then stored + * within a SharedPreferences instance so that those values can be retrieved here. + * + * This has a few benefits over the conventional way of storing the values + * (ie. within the Dolphin ini file). + * + * * No native calls + * * Keeps Android-only values inside the Android environment + * + * Technically no modifications should need to be performed on the returned + * InputOverlayDrawableButton. Simply add it to the HashSet of overlay items and wait + * for Android to call the onDraw method. + * + * @param context The current [Context]. + * @param defaultResId The resource ID of the [Drawable] to get the [Bitmap] of (Default State). + * @param pressedResId The resource ID of the [Drawable] to get the [Bitmap] of (Pressed State). + * @param legacyId Legacy identifier for the button the InputOverlayDrawableButton represents. + * @param control Control identifier for the button the InputOverlayDrawableButton represents. + * @return An [InputOverlayDrawableButton] with the correct drawing bounds set. + */ + private fun initializeOverlayButton( + context: Context, + defaultResId: Int, pressedResId: Int, legacyId: Int, control: Int, orientation: String + ): InputOverlayDrawableButton { + // Decide scale based on button ID and user preference + var scale = when (legacyId) { + ButtonType.BUTTON_A, + ButtonType.WIIMOTE_BUTTON_B, + ButtonType.NUNCHUK_BUTTON_Z -> 0.2f + + ButtonType.BUTTON_X, + ButtonType.BUTTON_Y -> 0.175f + + ButtonType.BUTTON_Z, + ButtonType.TRIGGER_L, + ButtonType.TRIGGER_R -> 0.225f + + ButtonType.BUTTON_START -> 0.075f + ButtonType.WIIMOTE_BUTTON_1, + ButtonType.WIIMOTE_BUTTON_2 -> if (controllerType == OVERLAY_WIIMOTE_SIDEWAYS) 0.14f else 0.0875f + + ButtonType.WIIMOTE_BUTTON_PLUS, + ButtonType.WIIMOTE_BUTTON_MINUS, + ButtonType.WIIMOTE_BUTTON_HOME, + ButtonType.CLASSIC_BUTTON_PLUS, + ButtonType.CLASSIC_BUTTON_MINUS, + ButtonType.CLASSIC_BUTTON_HOME -> 0.0625f + + ButtonType.CLASSIC_TRIGGER_L, + ButtonType.CLASSIC_TRIGGER_R, + ButtonType.CLASSIC_BUTTON_ZL, + ButtonType.CLASSIC_BUTTON_ZR -> 0.25f + + else -> 0.125f + } + + scale *= (IntSetting.MAIN_CONTROL_SCALE.int + 50).toFloat() + scale /= 100f + + // Initialize the InputOverlayDrawableButton. + val defaultStateBitmap = + resizeBitmap(context, BitmapFactory.decodeResource(resources, defaultResId), scale) + val pressedStateBitmap = + resizeBitmap(context, BitmapFactory.decodeResource(resources, pressedResId), scale) + val overlayDrawable = InputOverlayDrawableButton( + resources, + defaultStateBitmap, + pressedStateBitmap, + legacyId, + control + ) + + // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. + // These were set in the input overlay configuration menu. + val drawableX = + preferences.getFloat(getXKey(legacyId, controllerType, orientation), 0f).toInt() + val drawableY = + preferences.getFloat(getYKey(legacyId, controllerType, orientation), 0f).toInt() + + val width = overlayDrawable.width + val height = overlayDrawable.height + + // Now set the bounds for the InputOverlayDrawableButton. + // This will dictate where on the screen (and the what the size) the InputOverlayDrawableButton will be. + overlayDrawable.setBounds(drawableX, drawableY, drawableX + width, drawableY + height) + + // Need to set the image's position + overlayDrawable.setPosition(drawableX, drawableY) + overlayDrawable.setOpacity(IntSetting.MAIN_CONTROL_OPACITY.int * 255 / 100) + + return overlayDrawable + } + + /** + * Initializes an [InputOverlayDrawableDpad] + * + * @param context The current [Context]. + * @param defaultResId The [Bitmap] resource ID of the default sate. + * @param pressedOneDirectionResId The [Bitmap] resource ID of the pressed sate in one direction. + * @param pressedTwoDirectionsResId The [Bitmap] resource ID of the pressed sate in two directions. + * @param legacyId Legacy identifier for the up button. + * @param upControl Control identifier for the up button. + * @param downControl Control identifier for the down button. + * @param leftControl Control identifier for the left button. + * @param rightControl Control identifier for the right button. + * @return the initialized [InputOverlayDrawableDpad] + */ + private fun initializeOverlayDpad( + context: Context, + defaultResId: Int, + pressedOneDirectionResId: Int, + pressedTwoDirectionsResId: Int, + legacyId: Int, + upControl: Int, + downControl: Int, + leftControl: Int, + rightControl: Int, + orientation: String + ): InputOverlayDrawableDpad { + // Decide scale based on button ID and user preference + var scale: Float = when (legacyId) { + ButtonType.BUTTON_UP -> 0.2375f + ButtonType.CLASSIC_DPAD_UP -> 0.275f + else -> if (controllerType == OVERLAY_WIIMOTE_SIDEWAYS || controllerType == OVERLAY_WIIMOTE) 0.275f else 0.2125f + } + + scale *= (IntSetting.MAIN_CONTROL_SCALE.int + 50).toFloat() + scale /= 100f + + // Initialize the InputOverlayDrawableDpad. + val defaultStateBitmap = + resizeBitmap(context, BitmapFactory.decodeResource(resources, defaultResId), scale) + val pressedOneDirectionStateBitmap = resizeBitmap( + context, + BitmapFactory.decodeResource(resources, pressedOneDirectionResId), + scale + ) + val pressedTwoDirectionsStateBitmap = resizeBitmap( + context, + BitmapFactory.decodeResource(resources, pressedTwoDirectionsResId), + scale + ) + val overlayDrawable = InputOverlayDrawableDpad( + resources, + defaultStateBitmap, + pressedOneDirectionStateBitmap, + pressedTwoDirectionsStateBitmap, + legacyId, + upControl, + downControl, + leftControl, + rightControl + ) + + // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay. + // These were set in the input overlay configuration menu. + val drawableX = + preferences.getFloat(getXKey(legacyId, controllerType, orientation), 0f).toInt() + val drawableY = + preferences.getFloat(getYKey(legacyId, controllerType, orientation), 0f).toInt() + + val width = overlayDrawable.width + val height = overlayDrawable.height + + // 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 + width, drawableY + height) + + // Need to set the image's position + overlayDrawable.setPosition(drawableX, drawableY) + overlayDrawable.setOpacity(IntSetting.MAIN_CONTROL_OPACITY.int * 255 / 100) + + return overlayDrawable + } + + /** + * Initializes an [InputOverlayDrawableJoystick] + * + * @param context The current [Context] + * @param resOuter Resource ID for the outer image of the joystick (the static image that shows the circular bounds). + * @param defaultResInner Resource ID for the default inner image of the joystick (the one you actually move around). + * @param pressedResInner Resource ID for the pressed inner image of the joystick. + * @param legacyId Legacy identifier (ButtonType) for which joystick this is. + * @param xControl Control identifier for the X axis. + * @param yControl Control identifier for the Y axis. + * @return the initialized [InputOverlayDrawableJoystick]. + */ + private fun initializeOverlayJoystick( + context: Context, + resOuter: Int, + defaultResInner: Int, + pressedResInner: Int, + legacyId: Int, + xControl: Int, + yControl: Int, + orientation: String + ): InputOverlayDrawableJoystick { + // Decide scale based on user preference + var scale = 0.275f + scale *= (IntSetting.MAIN_CONTROL_SCALE.int + 50).toFloat() + scale /= 100f + + // Initialize the InputOverlayDrawableJoystick. + val bitmapOuter = + resizeBitmap(context, BitmapFactory.decodeResource(resources, resOuter), scale) + val bitmapInnerDefault = BitmapFactory.decodeResource(resources, defaultResInner) + val bitmapInnerPressed = BitmapFactory.decodeResource(resources, pressedResInner) + + // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. + // These were set in the input overlay configuration menu. + val drawableX = + preferences.getFloat(getXKey(legacyId, controllerType, orientation), 0f).toInt() + val drawableY = + preferences.getFloat(getYKey(legacyId, controllerType, orientation), 0f).toInt() + + // Decide inner scale based on joystick ID + val innerScale: Float = if (legacyId == ButtonType.STICK_C) 1.833f else 1.375f + + // Now set the bounds for the InputOverlayDrawableJoystick. + // This will dictate where on the screen (and the what the size) the InputOverlayDrawableJoystick will be. + val outerSize = bitmapOuter.width + val outerRect = Rect(drawableX, drawableY, drawableX + outerSize, drawableY + outerSize) + val innerRect = + Rect(0, 0, (outerSize / innerScale).toInt(), (outerSize / innerScale).toInt()) + + // Send the drawableId to the joystick so it can be referenced when saving control position. + val overlayDrawable = InputOverlayDrawableJoystick( + resources, + bitmapOuter, + bitmapInnerDefault, + bitmapInnerPressed, + outerRect, + innerRect, + legacyId, + xControl, + yControl, + controllerIndex + ) + + // Need to set the image's position + overlayDrawable.setPosition(drawableX, drawableY) + overlayDrawable.setOpacity(IntSetting.MAIN_CONTROL_OPACITY.int * 255 / 100) + return overlayDrawable + } + + override fun isInEditMode(): Boolean { + return editMode + } + + private fun defaultOverlay() { + if (!preferences.getBoolean("OverlayInitV2", false)) { + // It's possible that a user has created their overlay before this was added + // Only change the overlay if the 'A' button is not in the upper corner. + // GameCube + if (preferences.getFloat(ButtonType.BUTTON_A.toString() + "-X", 0f) == 0f) { + gcDefaultOverlay() + } + if (preferences.getFloat( + ButtonType.BUTTON_A.toString() + "-Portrait" + "-X", + 0f + ) == 0f + ) { + gcPortraitDefaultOverlay() + } + + // Wii + if (preferences.getFloat(ButtonType.WIIMOTE_BUTTON_A.toString() + "-X", 0f) == 0f) { + wiiDefaultOverlay() + } + if (preferences.getFloat( + ButtonType.WIIMOTE_BUTTON_A.toString() + "-Portrait" + "-X", + 0f + ) == 0f + ) { + wiiPortraitDefaultOverlay() + } + + // Wii Classic + if (preferences.getFloat(ButtonType.CLASSIC_BUTTON_A.toString() + "-X", 0f) == 0f) { + wiiClassicDefaultOverlay() + } + if (preferences.getFloat( + ButtonType.CLASSIC_BUTTON_A.toString() + "-Portrait" + "-X", + 0f + ) == 0f + ) { + wiiClassicPortraitDefaultOverlay() + } + } + + if (!preferences.getBoolean("OverlayInitV3", false)) { + wiiOnlyDefaultOverlay() + wiiOnlyPortraitDefaultOverlay() + } + + preferences.edit() + .putBoolean("OverlayInitV2", true) + .putBoolean("OverlayInitV3", true) + .apply() + } + + private fun gcDefaultOverlay() { + // Get screen size + val display = (context as Activity).windowManager.defaultDisplay + val outMetrics = DisplayMetrics() + display.getMetrics(outMetrics) + var maxX = outMetrics.heightPixels.toFloat() + var maxY = outMetrics.widthPixels.toFloat() + // Height and width changes depending on orientation. Use the larger value for height. + if (maxY > maxX) { + val tmp = maxX + maxX = maxY + maxY = tmp + } + + // Each value is a percent from max X/Y stored as an int. Have to bring that value down + // to a decimal before multiplying by MAX X/Y. + preferences.edit() + .putFloat( + ButtonType.BUTTON_A.toString() + "-X", + resources.getInteger(R.integer.BUTTON_A_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_A.toString() + "-Y", + resources.getInteger(R.integer.BUTTON_A_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_B.toString() + "-X", + resources.getInteger(R.integer.BUTTON_B_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_B.toString() + "-Y", + resources.getInteger(R.integer.BUTTON_B_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_X.toString() + "-X", + resources.getInteger(R.integer.BUTTON_X_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_X.toString() + "-Y", + resources.getInteger(R.integer.BUTTON_X_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_Y.toString() + "-X", + resources.getInteger(R.integer.BUTTON_Y_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_Y.toString() + "-Y", + resources.getInteger(R.integer.BUTTON_Y_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_Z.toString() + "-X", + resources.getInteger(R.integer.BUTTON_Z_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_Z.toString() + "-Y", + resources.getInteger(R.integer.BUTTON_Z_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_UP.toString() + "-X", + resources.getInteger(R.integer.BUTTON_UP_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_UP.toString() + "-Y", + resources.getInteger(R.integer.BUTTON_UP_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.TRIGGER_L.toString() + "-X", + resources.getInteger(R.integer.TRIGGER_L_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.TRIGGER_L.toString() + "-Y", + resources.getInteger(R.integer.TRIGGER_L_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.TRIGGER_R.toString() + "-X", + resources.getInteger(R.integer.TRIGGER_R_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.TRIGGER_R.toString() + "-Y", + resources.getInteger(R.integer.TRIGGER_R_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_START.toString() + "-X", + resources.getInteger(R.integer.BUTTON_START_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_START.toString() + "-Y", + resources.getInteger(R.integer.BUTTON_START_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.STICK_C.toString() + "-X", + resources.getInteger(R.integer.STICK_C_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.STICK_C.toString() + "-Y", + resources.getInteger(R.integer.STICK_C_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.STICK_MAIN.toString() + "-X", + resources.getInteger(R.integer.STICK_MAIN_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.STICK_MAIN.toString() + "-Y", + resources.getInteger(R.integer.STICK_MAIN_Y).toFloat() / 1000 * maxY + ) + .apply() + } + + private fun gcPortraitDefaultOverlay() { + // Get screen size + val display = (context as Activity).windowManager.defaultDisplay + val outMetrics = DisplayMetrics() + display.getMetrics(outMetrics) + var maxX = outMetrics.heightPixels.toFloat() + var maxY = outMetrics.widthPixels.toFloat() + // Height and width changes depending on orientation. Use the larger value for height. + if (maxY < maxX) { + val tmp = maxX + maxX = maxY + maxY = tmp + } + val portrait = "-Portrait" + + // Each value is a percent from max X/Y stored as an int. Have to bring that value down + // to a decimal before multiplying by MAX X/Y. + preferences.edit() + .putFloat( + ButtonType.BUTTON_A.toString() + portrait + "-X", + resources.getInteger(R.integer.BUTTON_A_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_A.toString() + portrait + "-Y", + resources.getInteger(R.integer.BUTTON_A_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_B.toString() + portrait + "-X", + resources.getInteger(R.integer.BUTTON_B_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_B.toString() + portrait + "-Y", + resources.getInteger(R.integer.BUTTON_B_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_X.toString() + portrait + "-X", + resources.getInteger(R.integer.BUTTON_X_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_X.toString() + portrait + "-Y", + resources.getInteger(R.integer.BUTTON_X_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_Y.toString() + portrait + "-X", + resources.getInteger(R.integer.BUTTON_Y_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_Y.toString() + portrait + "-Y", + resources.getInteger(R.integer.BUTTON_Y_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_Z.toString() + portrait + "-X", + resources.getInteger(R.integer.BUTTON_Z_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_Z.toString() + portrait + "-Y", + resources.getInteger(R.integer.BUTTON_Z_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_UP.toString() + portrait + "-X", + resources.getInteger(R.integer.BUTTON_UP_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_UP.toString() + portrait + "-Y", + resources.getInteger(R.integer.BUTTON_UP_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.TRIGGER_L.toString() + portrait + "-X", + resources.getInteger(R.integer.TRIGGER_L_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.TRIGGER_L.toString() + portrait + "-Y", + resources.getInteger(R.integer.TRIGGER_L_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.TRIGGER_R.toString() + portrait + "-X", + resources.getInteger(R.integer.TRIGGER_R_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.TRIGGER_R.toString() + portrait + "-Y", + resources.getInteger(R.integer.TRIGGER_R_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.BUTTON_START.toString() + portrait + "-X", + resources.getInteger(R.integer.BUTTON_START_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.BUTTON_START.toString() + portrait + "-Y", + resources.getInteger(R.integer.BUTTON_START_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.STICK_C.toString() + portrait + "-X", + resources.getInteger(R.integer.STICK_C_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.STICK_C.toString() + portrait + "-Y", + resources.getInteger(R.integer.STICK_C_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.STICK_MAIN.toString() + portrait + "-X", + resources.getInteger(R.integer.STICK_MAIN_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.STICK_MAIN.toString() + portrait + "-Y", + resources.getInteger(R.integer.STICK_MAIN_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .apply() + } + + private fun wiiDefaultOverlay() { + // Get screen size + val display = (context as Activity).windowManager.defaultDisplay + val outMetrics = DisplayMetrics() + display.getMetrics(outMetrics) + var maxX = outMetrics.heightPixels.toFloat() + var maxY = outMetrics.widthPixels.toFloat() + // Height and width changes depending on orientation. Use the larger value for maxX. + if (maxY > maxX) { + val tmp = maxX + maxX = maxY + maxY = tmp + } + + // Each value is a percent from max X/Y stored as an int. Have to bring that value down + // to a decimal before multiplying by MAX X/Y. + preferences.edit() + .putFloat( + ButtonType.WIIMOTE_BUTTON_A.toString() + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_A_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_A.toString() + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_A_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_B.toString() + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_B_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_B.toString() + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_B_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_1.toString() + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_1_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_1.toString() + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_1_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_2.toString() + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_2_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_2.toString() + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_2_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.NUNCHUK_BUTTON_Z.toString() + "-X", + resources.getInteger(R.integer.NUNCHUK_BUTTON_Z_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.NUNCHUK_BUTTON_Z.toString() + "-Y", + resources.getInteger(R.integer.NUNCHUK_BUTTON_Z_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.NUNCHUK_BUTTON_C.toString() + "-X", + resources.getInteger(R.integer.NUNCHUK_BUTTON_C_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.NUNCHUK_BUTTON_C.toString() + "-Y", + resources.getInteger(R.integer.NUNCHUK_BUTTON_C_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_MINUS.toString() + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_MINUS_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_MINUS.toString() + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_MINUS_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_PLUS.toString() + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_PLUS_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_PLUS.toString() + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_PLUS_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_UP.toString() + "-X", + resources.getInteger(R.integer.WIIMOTE_UP_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_UP.toString() + "-Y", + resources.getInteger(R.integer.WIIMOTE_UP_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_HOME.toString() + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_HOME_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_HOME.toString() + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_HOME_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.NUNCHUK_STICK.toString() + "-X", + resources.getInteger(R.integer.NUNCHUK_STICK_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.NUNCHUK_STICK.toString() + "-Y", + resources.getInteger(R.integer.NUNCHUK_STICK_Y).toFloat() / 1000 * maxY + ) + .apply() + } + + private fun wiiOnlyDefaultOverlay() { + // Get screen size + val display = (context as Activity).windowManager.defaultDisplay + val outMetrics = DisplayMetrics() + display.getMetrics(outMetrics) + var maxX = outMetrics.heightPixels.toFloat() + var maxY = outMetrics.widthPixels.toFloat() + // Height and width changes depending on orientation. Use the larger value for maxX. + if (maxY > maxX) { + val tmp = maxX + maxX = maxY + maxY = tmp + } + + // Each value is a percent from max X/Y stored as an int. Have to bring that value down + // to a decimal before multiplying by MAX X/Y. + preferences.edit() + .putFloat( + ButtonType.WIIMOTE_BUTTON_A.toString() + "_H-X", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_A_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_A.toString() + "_H-Y", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_A_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_B.toString() + "_H-X", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_B_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_B.toString() + "_H-Y", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_B_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_1.toString() + "_H-X", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_1_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_1.toString() + "_H-Y", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_1_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_2.toString() + "_H-X", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_2_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_2.toString() + "_H-Y", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_2_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_UP.toString() + "_O-X", + resources.getInteger(R.integer.WIIMOTE_O_UP_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_UP.toString() + "_O-Y", + resources.getInteger(R.integer.WIIMOTE_O_UP_Y).toFloat() / 1000 * maxY + ) + // Horizontal dpad + .putFloat( + ButtonType.WIIMOTE_RIGHT.toString() + "-X", + resources.getInteger(R.integer.WIIMOTE_RIGHT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_RIGHT.toString() + "-Y", + resources.getInteger(R.integer.WIIMOTE_RIGHT_Y).toFloat() / 1000 * maxY + ) + .apply() + } + + private fun wiiPortraitDefaultOverlay() { + // Get screen size + val display = (context as Activity).windowManager.defaultDisplay + val outMetrics = DisplayMetrics() + display.getMetrics(outMetrics) + var maxX = outMetrics.heightPixels.toFloat() + var maxY = outMetrics.widthPixels.toFloat() + // Height and width changes depending on orientation. Use the larger value for maxX. + if (maxY < maxX) { + val tmp = maxX + maxX = maxY + maxY = tmp + } + val portrait = "-Portrait" + + // Each value is a percent from max X/Y stored as an int. Have to bring that value down + // to a decimal before multiplying by MAX X/Y. + preferences.edit() + .putFloat( + ButtonType.WIIMOTE_BUTTON_A.toString() + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_A_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_A.toString() + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_A_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_B.toString() + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_B_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_B.toString() + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_B_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_1.toString() + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_1_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_1.toString() + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_1_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_2.toString() + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_2_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_2.toString() + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_2_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.NUNCHUK_BUTTON_Z.toString() + portrait + "-X", + resources.getInteger(R.integer.NUNCHUK_BUTTON_Z_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.NUNCHUK_BUTTON_Z.toString() + portrait + "-Y", + resources.getInteger(R.integer.NUNCHUK_BUTTON_Z_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.NUNCHUK_BUTTON_C.toString() + portrait + "-X", + resources.getInteger(R.integer.NUNCHUK_BUTTON_C_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.NUNCHUK_BUTTON_C.toString() + portrait + "-Y", + resources.getInteger(R.integer.NUNCHUK_BUTTON_C_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_MINUS.toString() + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_MINUS_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_MINUS.toString() + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_MINUS_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_PLUS.toString() + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_PLUS_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_PLUS.toString() + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_PLUS_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_UP.toString() + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_UP_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_UP.toString() + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_UP_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_HOME.toString() + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_BUTTON_HOME_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_HOME.toString() + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_BUTTON_HOME_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.NUNCHUK_STICK.toString() + portrait + "-X", + resources.getInteger(R.integer.NUNCHUK_STICK_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.NUNCHUK_STICK.toString() + portrait + "-Y", + resources.getInteger(R.integer.NUNCHUK_STICK_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + // Horizontal dpad + .putFloat( + ButtonType.WIIMOTE_RIGHT.toString() + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_RIGHT_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_RIGHT.toString() + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_RIGHT_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .apply() + } + + private fun wiiOnlyPortraitDefaultOverlay() { + // Get screen size + val display = (context as Activity).windowManager.defaultDisplay + val outMetrics = DisplayMetrics() + display.getMetrics(outMetrics) + var maxX = outMetrics.heightPixels.toFloat() + var maxY = outMetrics.widthPixels.toFloat() + // Height and width changes depending on orientation. Use the larger value for maxX. + if (maxY < maxX) { + val tmp = maxX + maxX = maxY + maxY = tmp + } + val portrait = "-Portrait" + + // Each value is a percent from max X/Y stored as an int. Have to bring that value down + // to a decimal before multiplying by MAX X/Y. + preferences.edit() + .putFloat( + ButtonType.WIIMOTE_BUTTON_A.toString() + "_H" + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_A_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_A.toString() + "_H" + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_A_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_B.toString() + "_H" + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_B_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_B.toString() + "_H" + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_B_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_1.toString() + "_H" + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_1_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_1.toString() + "_H" + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_1_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_2.toString() + "_H" + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_2_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_BUTTON_2.toString() + "_H" + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_H_BUTTON_2_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.WIIMOTE_UP.toString() + "_O" + portrait + "-X", + resources.getInteger(R.integer.WIIMOTE_O_UP_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.WIIMOTE_UP.toString() + "_O" + portrait + "-Y", + resources.getInteger(R.integer.WIIMOTE_O_UP_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .apply() + } + + private fun wiiClassicDefaultOverlay() { + // Get screen size + val display = (context as Activity).windowManager.defaultDisplay + val outMetrics = DisplayMetrics() + display.getMetrics(outMetrics) + var maxX = outMetrics.heightPixels.toFloat() + var maxY = outMetrics.widthPixels.toFloat() + // Height and width changes depending on orientation. Use the larger value for maxX. + if (maxY > maxX) { + val tmp = maxX + maxX = maxY + maxY = tmp + } + + // Each value is a percent from max X/Y stored as an int. Have to bring that value down + // to a decimal before multiplying by MAX X/Y. + preferences.edit() + .putFloat( + ButtonType.CLASSIC_BUTTON_A.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_A_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_A.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_A_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_B.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_B_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_B.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_B_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_X.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_X_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_X.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_X_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_Y.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_Y_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_Y.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_Y_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_MINUS.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_MINUS_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_MINUS.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_MINUS_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_PLUS.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_PLUS_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_PLUS.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_PLUS_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_HOME.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_HOME_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_HOME.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_HOME_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_ZL.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_ZL_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_ZL.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_ZL_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_ZR.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_ZR_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_ZR.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_ZR_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_DPAD_UP.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_DPAD_UP_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_DPAD_UP.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_DPAD_UP_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_STICK_LEFT.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_STICK_LEFT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_STICK_LEFT.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_STICK_LEFT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_STICK_RIGHT.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_STICK_RIGHT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_STICK_RIGHT.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_STICK_RIGHT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_TRIGGER_L.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_TRIGGER_L_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_TRIGGER_L.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_TRIGGER_L_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_TRIGGER_R.toString() + "-X", + resources.getInteger(R.integer.CLASSIC_TRIGGER_R_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_TRIGGER_R.toString() + "-Y", + resources.getInteger(R.integer.CLASSIC_TRIGGER_R_Y).toFloat() / 1000 * maxY + ) + .apply() + } + + private fun wiiClassicPortraitDefaultOverlay() { + // Get screen size + val display = (context as Activity).windowManager.defaultDisplay + val outMetrics = DisplayMetrics() + display.getMetrics(outMetrics) + var maxX = outMetrics.heightPixels.toFloat() + var maxY = outMetrics.widthPixels.toFloat() + // Height and width changes depending on orientation. Use the larger value for maxX. + if (maxY < maxX) { + val tmp = maxX + maxX = maxY + maxY = tmp + } + val portrait = "-Portrait" + + // Each value is a percent from max X/Y stored as an int. Have to bring that value down + // to a decimal before multiplying by MAX X/Y. + preferences.edit() + .putFloat( + ButtonType.CLASSIC_BUTTON_A.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_A_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_A.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_A_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_B.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_B_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_B.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_B_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_X.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_X_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_X.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_X_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_Y.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_Y_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_Y.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_Y_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_MINUS.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_MINUS_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_MINUS.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_MINUS_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_PLUS.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_PLUS_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_PLUS.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_PLUS_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_HOME.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_HOME_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_HOME.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_HOME_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_ZL.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_ZL_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_ZL.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_ZL_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_ZR.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_BUTTON_ZR_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_BUTTON_ZR.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_BUTTON_ZR_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_DPAD_UP.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_DPAD_UP_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_DPAD_UP.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_DPAD_UP_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_STICK_LEFT.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_STICK_LEFT_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_STICK_LEFT.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_STICK_LEFT_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_STICK_RIGHT.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_STICK_RIGHT_PORTRAIT_X) + .toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_STICK_RIGHT.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_STICK_RIGHT_PORTRAIT_Y) + .toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_TRIGGER_L.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_TRIGGER_L_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_TRIGGER_L.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_TRIGGER_L_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .putFloat( + ButtonType.CLASSIC_TRIGGER_R.toString() + portrait + "-X", + resources.getInteger(R.integer.CLASSIC_TRIGGER_R_PORTRAIT_X).toFloat() / 1000 * maxX + ) + .putFloat( + ButtonType.CLASSIC_TRIGGER_R.toString() + portrait + "-Y", + resources.getInteger(R.integer.CLASSIC_TRIGGER_R_PORTRAIT_Y).toFloat() / 1000 * maxY + ) + .apply() + } + + companion object { + const val OVERLAY_GAMECUBE = 0 + const val OVERLAY_WIIMOTE = 1 + const val OVERLAY_WIIMOTE_SIDEWAYS = 2 + const val OVERLAY_WIIMOTE_NUNCHUK = 3 + const val OVERLAY_WIIMOTE_CLASSIC = 4 + const val OVERLAY_NONE = 5 + private const val DISABLED_GAMECUBE_CONTROLLER = 0 + private const val EMULATED_GAMECUBE_CONTROLLER = 6 + private const val GAMECUBE_ADAPTER = 12 + + // Buttons that have special positions in Wiimote only + private val WIIMOTE_H_BUTTONS = ArrayList() + + init { + WIIMOTE_H_BUTTONS.add(ButtonType.WIIMOTE_BUTTON_A) + WIIMOTE_H_BUTTONS.add(ButtonType.WIIMOTE_BUTTON_B) + WIIMOTE_H_BUTTONS.add(ButtonType.WIIMOTE_BUTTON_1) + WIIMOTE_H_BUTTONS.add(ButtonType.WIIMOTE_BUTTON_2) + } + + private val WIIMOTE_O_BUTTONS = ArrayList() + + init { + WIIMOTE_O_BUTTONS.add(ButtonType.WIIMOTE_UP) + } + + /** + * Resizes a [Bitmap] by a given scale factor + * + * @param context The current [Context] + * @param bitmap The [Bitmap] to scale. + * @param scale The scale factor for the bitmap. + * @return The scaled [Bitmap] + */ + fun resizeBitmap(context: Context, bitmap: Bitmap, scale: Float): Bitmap { + // Determine the button size based on the smaller screen dimension. + // This makes sure the buttons are the same size in both portrait and landscape. + val dm = context.resources.displayMetrics + val minScreenDimension = dm.widthPixels.coerceAtMost(dm.heightPixels) + + val maxBitmapDimension = bitmap.width.coerceAtLeast(bitmap.height) + val bitmapScale = scale * minScreenDimension / maxBitmapDimension + + return Bitmap.createScaledBitmap( + bitmap, + (bitmap.width * bitmapScale).toInt(), + (bitmap.height * bitmapScale).toInt(), + true + ) + } + + @JvmStatic + val configuredControllerType: Int + get() { + val controllerSetting = + if (NativeLibrary.IsEmulatingWii()) IntSetting.MAIN_OVERLAY_WII_CONTROLLER else IntSetting.MAIN_OVERLAY_GC_CONTROLLER + val controllerIndex = controllerSetting.int + + if (controllerIndex in 0 until 4) { + // GameCube controller + if (getSettingForSIDevice(controllerIndex).int == 6) + return OVERLAY_GAMECUBE + } else if (controllerIndex in 4 until 8) { + // Wii Remote + val wiimoteIndex = controllerIndex - 4 + if (getSettingForWiimoteSource(wiimoteIndex).int == 1) { + when (EmulatedController.getSelectedWiimoteAttachment(wiimoteIndex)) { + 1 -> return OVERLAY_WIIMOTE_NUNCHUK + 2 -> return OVERLAY_WIIMOTE_CLASSIC + } + + val sidewaysSetting = + EmulatedController.getSidewaysWiimoteSetting(wiimoteIndex) + val sideways: Boolean = + InputMappingBooleanSetting(sidewaysSetting).boolean + + return if (sideways) OVERLAY_WIIMOTE_SIDEWAYS else OVERLAY_WIIMOTE + } + } + return OVERLAY_NONE + } + + private fun getKey( + sharedPrefsId: Int, + controller: Int, + orientation: String, + suffix: String + ): String = + if (controller == OVERLAY_WIIMOTE_SIDEWAYS && WIIMOTE_H_BUTTONS.contains(sharedPrefsId)) { + sharedPrefsId.toString() + "_H" + orientation + suffix + } else if (controller == OVERLAY_WIIMOTE && WIIMOTE_O_BUTTONS.contains(sharedPrefsId)) { + sharedPrefsId.toString() + "_O" + orientation + suffix + } else { + sharedPrefsId.toString() + orientation + suffix + } + } + + private fun getXKey(sharedPrefsId: Int, controller: Int, orientation: String): String = + getKey(sharedPrefsId, controller, orientation, "-X") + + private fun getYKey(sharedPrefsId: Int, controller: Int, orientation: String): String = + getKey(sharedPrefsId, controller, orientation, "-Y") +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.java deleted file mode 100644 index d997da94bf..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2013 Dolphin Emulator Project - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -package org.dolphinemu.dolphinemu.overlay; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.view.MotionEvent; - -/** - * Custom {@link BitmapDrawable} that is capable - * of storing it's own ID. - */ -public final class InputOverlayDrawableButton -{ - // The legacy ID identifying what type of button this Drawable represents. - private int mLegacyId; - private int mControl; - private int mTrackId; - private int mPreviousTouchX, mPreviousTouchY; - private int mControlPositionX, mControlPositionY; - private int mWidth; - private int mHeight; - private BitmapDrawable mDefaultStateBitmap; - private BitmapDrawable mPressedStateBitmap; - private boolean mPressedState = false; - - /** - * Constructor - * - * @param res {@link Resources} instance. - * @param defaultStateBitmap {@link Bitmap} to use with the default state Drawable. - * @param pressedStateBitmap {@link Bitmap} to use with the pressed state Drawable. - * @param legacyId Legacy identifier (ButtonType) for this type of button. - * @param control Control ID for this type of button. - */ - public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap, - Bitmap pressedStateBitmap, int legacyId, int control) - { - mTrackId = -1; - mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap); - mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap); - mLegacyId = legacyId; - mControl = control; - - mWidth = mDefaultStateBitmap.getIntrinsicWidth(); - mHeight = mDefaultStateBitmap.getIntrinsicHeight(); - } - - /** - * Gets this InputOverlayDrawableButton's legacy button ID. - */ - public int getLegacyId() - { - return mLegacyId; - } - - public int getControl() - { - return mControl; - } - - public void setTrackId(int trackId) - { - mTrackId = trackId; - } - - public int getTrackId() - { - return mTrackId; - } - - public void onConfigureTouch(MotionEvent event) - { - switch (event.getAction()) - { - case MotionEvent.ACTION_DOWN: - mPreviousTouchX = (int) event.getX(); - mPreviousTouchY = (int) event.getY(); - break; - case MotionEvent.ACTION_MOVE: - mControlPositionX += (int) event.getX() - mPreviousTouchX; - mControlPositionY += (int) event.getY() - mPreviousTouchY; - setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX, - getHeight() + mControlPositionY); - mPreviousTouchX = (int) event.getX(); - mPreviousTouchY = (int) event.getY(); - break; - } - } - - public void setPosition(int x, int y) - { - mControlPositionX = x; - mControlPositionY = y; - } - - public void draw(Canvas canvas) - { - getCurrentStateBitmapDrawable().draw(canvas); - } - - private BitmapDrawable getCurrentStateBitmapDrawable() - { - return mPressedState ? mPressedStateBitmap : mDefaultStateBitmap; - } - - public void setBounds(int left, int top, int right, int bottom) - { - mDefaultStateBitmap.setBounds(left, top, right, bottom); - mPressedStateBitmap.setBounds(left, top, right, bottom); - } - - public void setOpacity(int value) - { - mDefaultStateBitmap.setAlpha(value); - mPressedStateBitmap.setAlpha(value); - } - - public Rect getBounds() - { - return mDefaultStateBitmap.getBounds(); - } - - public int getWidth() - { - return mWidth; - } - - public int getHeight() - { - return mHeight; - } - - public void setPressedState(boolean isPressed) - { - mPressedState = isPressed; - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.kt new file mode 100644 index 0000000000..220eb836d5 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableButton.kt @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.overlay + +import android.content.res.Resources +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Rect +import android.graphics.drawable.BitmapDrawable +import android.view.MotionEvent + +/** + * Custom [BitmapDrawable] that is capable + * of storing it's own ID. + * + * @param res [Resources] instance. + * @param defaultStateBitmap [Bitmap] to use with the default state Drawable. + * @param pressedStateBitmap [Bitmap] to use with the pressed state Drawable. + * @param legacyId Legacy identifier (ButtonType) for this type of button. + * @param control Control ID for this type of button. + */ +class InputOverlayDrawableButton( + res: Resources, + defaultStateBitmap: Bitmap, + pressedStateBitmap: Bitmap, + val legacyId: Int, + val control: Int +) { + var trackId: Int = -1 + private var previousTouchX = 0 + private var previousTouchY = 0 + private var controlPositionX = 0 + private var controlPositionY = 0 + val width: Int + val height: Int + private val defaultStateBitmap: BitmapDrawable + private val pressedStateBitmap: BitmapDrawable + private var pressedState = false + + init { + this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap) + this.pressedStateBitmap = BitmapDrawable(res, pressedStateBitmap) + width = this.defaultStateBitmap.intrinsicWidth + height = this.defaultStateBitmap.intrinsicHeight + } + + fun onConfigureTouch(event: MotionEvent) { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + previousTouchX = event.x.toInt() + previousTouchY = event.y.toInt() + } + + MotionEvent.ACTION_MOVE -> { + controlPositionX += event.x.toInt() - previousTouchX + controlPositionY += event.y.toInt() - previousTouchY + setBounds( + controlPositionX, + controlPositionY, + width + controlPositionX, + height + controlPositionY + ) + previousTouchX = event.x.toInt() + previousTouchY = event.y.toInt() + } + } + } + + fun setPosition(x: Int, y: Int) { + controlPositionX = x + controlPositionY = y + } + + fun draw(canvas: Canvas) { + currentStateBitmapDrawable.draw(canvas) + } + + private val currentStateBitmapDrawable: BitmapDrawable + get() = if (pressedState) pressedStateBitmap else defaultStateBitmap + + fun setBounds(left: Int, top: Int, right: Int, bottom: Int) { + defaultStateBitmap.setBounds(left, top, right, bottom) + pressedStateBitmap.setBounds(left, top, right, bottom) + } + + fun setOpacity(value: Int) { + defaultStateBitmap.alpha = value + pressedStateBitmap.alpha = value + } + + val bounds: Rect + get() = defaultStateBitmap.bounds + + fun setPressedState(isPressed: Boolean) { + pressedState = isPressed + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableDpad.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableDpad.java deleted file mode 100644 index 6542609ca0..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableDpad.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2016 Dolphin Emulator Project - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -package org.dolphinemu.dolphinemu.overlay; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.view.MotionEvent; - -/** - * Custom {@link BitmapDrawable} that is capable - * of storing it's own ID. - */ -public final class InputOverlayDrawableDpad -{ - // The legacy ID identifying what type of button this Drawable represents. - private int mLegacyId; - private int[] mControls = new int[4]; - private int mTrackId; - private int mPreviousTouchX, mPreviousTouchY; - private int mControlPositionX, mControlPositionY; - private int mWidth; - private int mHeight; - private BitmapDrawable mDefaultStateBitmap; - private BitmapDrawable mPressedOneDirectionStateBitmap; - private BitmapDrawable mPressedTwoDirectionsStateBitmap; - private int mPressState = STATE_DEFAULT; - - 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; - - /** - * Constructor - * - * @param res {@link Resources} instance. - * @param defaultStateBitmap {@link Bitmap} of the default state. - * @param pressedOneDirectionStateBitmap {@link Bitmap} of the pressed state in one direction. - * @param pressedTwoDirectionsStateBitmap {@link Bitmap} of the pressed state in two direction. - * @param legacyId Legacy identifier (ButtonType) for the up button. - * @param upControl Control identifier for the up button. - * @param downControl Control identifier for the down button. - * @param leftControl Control identifier for the left button. - * @param rightControl Control identifier for the right button. - */ - public InputOverlayDrawableDpad(Resources res, Bitmap defaultStateBitmap, - Bitmap pressedOneDirectionStateBitmap, Bitmap pressedTwoDirectionsStateBitmap, - int legacyId, int upControl, int downControl, int leftControl, int rightControl) - { - mTrackId = -1; - mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap); - mPressedOneDirectionStateBitmap = new BitmapDrawable(res, pressedOneDirectionStateBitmap); - mPressedTwoDirectionsStateBitmap = new BitmapDrawable(res, pressedTwoDirectionsStateBitmap); - - mWidth = mDefaultStateBitmap.getIntrinsicWidth(); - mHeight = mDefaultStateBitmap.getIntrinsicHeight(); - - mLegacyId = legacyId; - mControls[0] = upControl; - mControls[1] = downControl; - mControls[2] = leftControl; - mControls[3] = rightControl; - } - - public void draw(Canvas canvas) - { - int px = mControlPositionX + (getWidth() / 2); - int py = mControlPositionY + (getHeight() / 2); - switch (mPressState) - { - case STATE_DEFAULT: - mDefaultStateBitmap.draw(canvas); - break; - case STATE_PRESSED_UP: - 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; - } - } - - public int getLegacyId() - { - return mLegacyId; - } - - /** - * Gets one of the InputOverlayDrawableDpad's control IDs. - */ - public int getControl(int direction) - { - return mControls[direction]; - } - - public void setTrackId(int trackId) - { - mTrackId = trackId; - } - - public int getTrackId() - { - return mTrackId; - } - - public void onConfigureTouch(MotionEvent event) - { - switch (event.getAction()) - { - case MotionEvent.ACTION_DOWN: - mPreviousTouchX = (int) event.getX(); - mPreviousTouchY = (int) event.getY(); - break; - case MotionEvent.ACTION_MOVE: - mControlPositionX += (int) event.getX() - mPreviousTouchX; - mControlPositionY += (int) event.getY() - mPreviousTouchY; - setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX, - getHeight() + mControlPositionY); - mPreviousTouchX = (int) event.getX(); - mPreviousTouchY = (int) event.getY(); - break; - } - } - - public void setPosition(int x, int y) - { - mControlPositionX = x; - mControlPositionY = y; - } - - public void setBounds(int left, int top, int right, int bottom) - { - mDefaultStateBitmap.setBounds(left, top, right, bottom); - mPressedOneDirectionStateBitmap.setBounds(left, top, right, bottom); - mPressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom); - } - - public void setOpacity(int value) - { - mDefaultStateBitmap.setAlpha(value); - mPressedOneDirectionStateBitmap.setAlpha(value); - mPressedTwoDirectionsStateBitmap.setAlpha(value); - } - - public Rect getBounds() - { - return mDefaultStateBitmap.getBounds(); - } - - public int getWidth() - { - return mWidth; - } - - public int getHeight() - { - return mHeight; - } - - public void setState(int pressState) - { - mPressState = pressState; - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableDpad.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableDpad.kt new file mode 100644 index 0000000000..2b53046a1e --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableDpad.kt @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.overlay + +import android.content.res.Resources +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Rect +import android.graphics.drawable.BitmapDrawable +import android.view.MotionEvent + +/** + * Custom [BitmapDrawable] that is capable + * of storing it's own ID. + * + * @param res [Resources] instance. + * @param defaultStateBitmap [Bitmap] of the default state. + * @param pressedOneDirectionStateBitmap [Bitmap] of the pressed state in one direction. + * @param pressedTwoDirectionsStateBitmap [Bitmap] of the pressed state in two direction. + * @param legacyId Legacy identifier (ButtonType) for the up button. + * @param upControl Control identifier for the up button. + * @param downControl Control identifier for the down button. + * @param leftControl Control identifier for the left button. + * @param rightControl Control identifier for the right button. + */ +class InputOverlayDrawableDpad( + res: Resources, + defaultStateBitmap: Bitmap, + pressedOneDirectionStateBitmap: Bitmap, + pressedTwoDirectionsStateBitmap: Bitmap, + val legacyId: Int, + upControl: Int, + downControl: Int, + leftControl: Int, + rightControl: Int +) { + private val controls = IntArray(4) + var trackId: Int = -1 + private var previousTouchX = 0 + private var previousTouchY = 0 + private var controlPositionX = 0 + private var controlPositionY = 0 + val width: Int + val height: Int + private val defaultStateBitmap: BitmapDrawable + private val pressedOneDirectionStateBitmap: BitmapDrawable + private val pressedTwoDirectionsStateBitmap: BitmapDrawable + private var pressState = STATE_DEFAULT + + init { + this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap) + this.pressedOneDirectionStateBitmap = BitmapDrawable(res, pressedOneDirectionStateBitmap) + this.pressedTwoDirectionsStateBitmap = BitmapDrawable(res, pressedTwoDirectionsStateBitmap) + + width = this.defaultStateBitmap.intrinsicWidth + height = this.defaultStateBitmap.intrinsicHeight + + controls[0] = upControl + controls[1] = downControl + controls[2] = leftControl + controls[3] = rightControl + } + + fun draw(canvas: Canvas) { + val px = controlPositionX + width / 2 + val py = controlPositionY + height / 2 + when (pressState) { + STATE_DEFAULT -> defaultStateBitmap.draw(canvas) + STATE_PRESSED_UP -> pressedOneDirectionStateBitmap.draw(canvas) + STATE_PRESSED_RIGHT -> { + canvas.apply { + save() + rotate(90f, px.toFloat(), py.toFloat()) + pressedOneDirectionStateBitmap.draw(canvas) + restore() + } + } + + STATE_PRESSED_DOWN -> { + canvas.apply { + save() + rotate(180f, px.toFloat(), py.toFloat()) + pressedOneDirectionStateBitmap.draw(canvas) + restore() + } + } + + STATE_PRESSED_LEFT -> { + canvas.apply { + save() + rotate(270f, px.toFloat(), py.toFloat()) + pressedOneDirectionStateBitmap.draw(canvas) + restore() + } + } + + STATE_PRESSED_UP_LEFT -> pressedTwoDirectionsStateBitmap.draw(canvas) + STATE_PRESSED_UP_RIGHT -> { + canvas.apply { + save() + rotate(90f, px.toFloat(), py.toFloat()) + pressedTwoDirectionsStateBitmap.draw(canvas) + restore() + } + } + + STATE_PRESSED_DOWN_RIGHT -> { + canvas.apply { + save() + rotate(180f, px.toFloat(), py.toFloat()) + pressedTwoDirectionsStateBitmap.draw(canvas) + restore() + } + } + + STATE_PRESSED_DOWN_LEFT -> { + canvas.apply { + save() + rotate(270f, px.toFloat(), py.toFloat()) + pressedTwoDirectionsStateBitmap.draw(canvas) + restore() + } + } + } + } + + /** + * Gets one of the InputOverlayDrawableDpad's control IDs. + */ + fun getControl(direction: Int): Int { + return controls[direction] + } + + fun onConfigureTouch(event: MotionEvent) { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + previousTouchX = event.x.toInt() + previousTouchY = event.y.toInt() + } + + MotionEvent.ACTION_MOVE -> { + controlPositionX += event.x.toInt() - previousTouchX + controlPositionY += event.y.toInt() - previousTouchY + setBounds( + controlPositionX, controlPositionY, width + controlPositionX, + height + controlPositionY + ) + previousTouchX = event.x.toInt() + previousTouchY = event.y.toInt() + } + } + } + + fun setPosition(x: Int, y: Int) { + controlPositionX = x + controlPositionY = y + } + + fun setBounds(left: Int, top: Int, right: Int, bottom: Int) { + defaultStateBitmap.setBounds(left, top, right, bottom) + pressedOneDirectionStateBitmap.setBounds(left, top, right, bottom) + pressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom) + } + + fun setOpacity(value: Int) { + defaultStateBitmap.alpha = value + pressedOneDirectionStateBitmap.alpha = value + pressedTwoDirectionsStateBitmap.alpha = value + } + + val bounds: Rect + get() = defaultStateBitmap.bounds + + fun setState(pressState: Int) { + this.pressState = pressState + } + + companion object { + const val STATE_DEFAULT = 0 + const val STATE_PRESSED_UP = 1 + const val STATE_PRESSED_DOWN = 2 + const val STATE_PRESSED_LEFT = 3 + const val STATE_PRESSED_RIGHT = 4 + const val STATE_PRESSED_UP_LEFT = 5 + const val STATE_PRESSED_UP_RIGHT = 6 + const val STATE_PRESSED_DOWN_LEFT = 7 + const val STATE_PRESSED_DOWN_RIGHT = 8 + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java deleted file mode 100644 index 6ebe731341..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2013 Dolphin Emulator Project - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -package org.dolphinemu.dolphinemu.overlay; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.view.MotionEvent; - -import org.dolphinemu.dolphinemu.features.input.model.InputOverrider; -import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; - -/** - * Custom {@link BitmapDrawable} that is capable - * of storing it's own ID. - */ -public final class InputOverlayDrawableJoystick -{ - private float mCurrentX = 0.0f; - private float mCurrentY = 0.0f; - private int trackId = -1; - private final int mJoystickLegacyId; - private final int mJoystickXControl; - private final int mJoystickYControl; - private int mControlPositionX, mControlPositionY; - private int mPreviousTouchX, mPreviousTouchY; - private final int mWidth; - private final int mHeight; - private final int mControllerIndex; - private Rect mVirtBounds; - private Rect mOrigBounds; - private int mOpacity; - private final BitmapDrawable mOuterBitmap; - private final BitmapDrawable mDefaultStateInnerBitmap; - private final BitmapDrawable mPressedStateInnerBitmap; - private final BitmapDrawable mBoundsBoxBitmap; - private boolean mPressedState = false; - - /** - * Constructor - * - * @param res {@link Resources} instance. - * @param bitmapOuter {@link Bitmap} which represents the outer non-movable part of the joystick. - * @param bitmapInnerDefault {@link Bitmap} which represents the default inner movable part of the joystick. - * @param bitmapInnerPressed {@link Bitmap} which represents the pressed inner movable part of the joystick. - * @param rectOuter {@link Rect} which represents the outer joystick bounds. - * @param rectInner {@link Rect} which represents the inner joystick bounds. - * @param legacyId Legacy identifier (ButtonType) for which joystick this is. - * @param xControl The control which the x value of the joystick will be written to. - * @param yControl The control which the y value of the joystick will be written to. - */ - public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter, Bitmap bitmapInnerDefault, - Bitmap bitmapInnerPressed, Rect rectOuter, Rect rectInner, int legacyId, int xControl, - int yControl, int controllerIndex) - { - mJoystickLegacyId = legacyId; - mJoystickXControl = xControl; - mJoystickYControl = yControl; - - mOuterBitmap = new BitmapDrawable(res, bitmapOuter); - mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault); - mPressedStateInnerBitmap = new BitmapDrawable(res, bitmapInnerPressed); - mBoundsBoxBitmap = new BitmapDrawable(res, bitmapOuter); - mWidth = bitmapOuter.getWidth(); - mHeight = bitmapOuter.getHeight(); - - if (controllerIndex < 0 || controllerIndex >= 4) - throw new IllegalArgumentException("controllerIndex must be 0-3"); - mControllerIndex = controllerIndex; - - setBounds(rectOuter); - mDefaultStateInnerBitmap.setBounds(rectInner); - mPressedStateInnerBitmap.setBounds(rectInner); - mVirtBounds = getBounds(); - mOrigBounds = mOuterBitmap.copyBounds(); - mBoundsBoxBitmap.setAlpha(0); - mBoundsBoxBitmap.setBounds(getVirtBounds()); - SetInnerBounds(); - } - - /** - * Gets this InputOverlayDrawableJoystick's legacy ID. - * - * @return this InputOverlayDrawableJoystick's legacy ID. - */ - public int getLegacyId() - { - return mJoystickLegacyId; - } - - public void draw(Canvas canvas) - { - mOuterBitmap.draw(canvas); - getCurrentStateBitmapDrawable().draw(canvas); - mBoundsBoxBitmap.draw(canvas); - } - - public boolean TrackEvent(MotionEvent event) - { - boolean reCenter = BooleanSetting.MAIN_JOYSTICK_REL_CENTER.getBoolean(); - int action = event.getActionMasked(); - boolean firstPointer = action != MotionEvent.ACTION_POINTER_DOWN && - action != MotionEvent.ACTION_POINTER_UP; - int pointerIndex = firstPointer ? 0 : event.getActionIndex(); - boolean pressed = false; - - switch (action) - { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) - { - mPressedState = pressed = true; - mOuterBitmap.setAlpha(0); - mBoundsBoxBitmap.setAlpha(mOpacity); - if (reCenter) - { - getVirtBounds().offset((int) event.getX(pointerIndex) - getVirtBounds().centerX(), - (int) event.getY(pointerIndex) - getVirtBounds().centerY()); - } - mBoundsBoxBitmap.setBounds(getVirtBounds()); - trackId = event.getPointerId(pointerIndex); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - if (trackId == event.getPointerId(pointerIndex)) - { - pressed = true; - mPressedState = false; - mCurrentX = mCurrentY = 0.0f; - mOuterBitmap.setAlpha(mOpacity); - 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) - return pressed; - - for (int i = 0; i < event.getPointerCount(); i++) - { - if (trackId == event.getPointerId(i)) - { - 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(); - mCurrentX = touchX / maxX; - mCurrentY = touchY / maxY; - - SetInnerBounds(); - } - } - return pressed; - } - - public void onConfigureTouch(MotionEvent event) - { - switch (event.getAction()) - { - case MotionEvent.ACTION_DOWN: - mPreviousTouchX = (int) event.getX(); - mPreviousTouchY = (int) event.getY(); - break; - case MotionEvent.ACTION_MOVE: - int deltaX = (int) event.getX() - mPreviousTouchX; - int deltaY = (int) event.getY() - mPreviousTouchY; - mControlPositionX += deltaX; - mControlPositionY += deltaY; - setBounds(new Rect(mControlPositionX, mControlPositionY, - mOuterBitmap.getIntrinsicWidth() + mControlPositionX, - mOuterBitmap.getIntrinsicHeight() + mControlPositionY)); - setVirtBounds(new Rect(mControlPositionX, mControlPositionY, - mOuterBitmap.getIntrinsicWidth() + mControlPositionX, - mOuterBitmap.getIntrinsicHeight() + mControlPositionY)); - SetInnerBounds(); - setOrigBounds(new Rect(new Rect(mControlPositionX, mControlPositionY, - mOuterBitmap.getIntrinsicWidth() + mControlPositionX, - mOuterBitmap.getIntrinsicHeight() + mControlPositionY))); - mPreviousTouchX = (int) event.getX(); - mPreviousTouchY = (int) event.getY(); - break; - } - } - - public float getX() - { - return mCurrentX; - } - - public float getY() - { - return mCurrentY; - } - - public int getXControl() - { - return mJoystickXControl; - } - - public int getYControl() - { - return mJoystickYControl; - } - - private void SetInnerBounds() - { - double x = mCurrentX; - double y = mCurrentY; - - double angle = Math.atan2(y, x) + Math.PI + Math.PI; - double radius = Math.hypot(y, x); - double maxRadius = InputOverrider.getGateRadiusAtAngle(mControllerIndex, mJoystickXControl, - angle); - if (radius > maxRadius) - { - y = maxRadius * Math.sin(angle); - x = maxRadius * Math.cos(angle); - mCurrentY = (float) y; - mCurrentX = (float) x; - } - - int pixelX = getVirtBounds().centerX() + (int) (x * (getVirtBounds().width() / 2)); - int pixelY = getVirtBounds().centerY() + (int) (y * (getVirtBounds().height() / 2)); - - int width = mPressedStateInnerBitmap.getBounds().width() / 2; - int height = mPressedStateInnerBitmap.getBounds().height() / 2; - mDefaultStateInnerBitmap.setBounds(pixelX - width, pixelY - height, pixelX + width, - pixelY + height); - mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds()); - } - - public void setPosition(int x, int y) - { - mControlPositionX = x; - mControlPositionY = y; - } - - private BitmapDrawable getCurrentStateBitmapDrawable() - { - return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap; - } - - public void setBounds(Rect bounds) - { - mOuterBitmap.setBounds(bounds); - } - - public void setOpacity(int value) - { - mOpacity = value; - - mDefaultStateInnerBitmap.setAlpha(value); - mPressedStateInnerBitmap.setAlpha(value); - - if (trackId == -1) - { - mOuterBitmap.setAlpha(value); - mBoundsBoxBitmap.setAlpha(0); - } - else - { - mOuterBitmap.setAlpha(0); - mBoundsBoxBitmap.setAlpha(value); - } - } - - public Rect getBounds() - { - return mOuterBitmap.getBounds(); - } - - private void setVirtBounds(Rect bounds) - { - mVirtBounds = bounds; - } - - private void setOrigBounds(Rect bounds) - { - mOrigBounds = bounds; - } - - private Rect getVirtBounds() - { - return mVirtBounds; - } - - public int getWidth() - { - return mWidth; - } - - public int getHeight() - { - return mHeight; - } - - public int getTrackId() - { - return trackId; - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.kt new file mode 100644 index 0000000000..7dff339dcf --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayDrawableJoystick.kt @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.overlay + +import android.content.res.Resources +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Rect +import android.graphics.drawable.BitmapDrawable +import android.view.MotionEvent +import org.dolphinemu.dolphinemu.features.input.model.InputOverrider +import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting +import kotlin.math.atan2 +import kotlin.math.cos +import kotlin.math.hypot +import kotlin.math.sin + +/** + * Custom [BitmapDrawable] that is capable + * of storing it's own ID. + * + * @param res [Resources] instance. + * @param bitmapOuter [Bitmap] which represents the outer non-movable part of the joystick. + * @param bitmapInnerDefault [Bitmap] which represents the default inner movable part of the joystick. + * @param bitmapInnerPressed [Bitmap] which represents the pressed inner movable part of the joystick. + * @param rectOuter [Rect] which represents the outer joystick bounds. + * @param rectInner [Rect] which represents the inner joystick bounds. + * @param legacyId Legacy identifier (ButtonType) for which joystick this is. + * @param xControl The control which the x value of the joystick will be written to. + * @param yControl The control which the y value of the joystick will be written to. + */ +class InputOverlayDrawableJoystick( + res: Resources, + bitmapOuter: Bitmap, + bitmapInnerDefault: Bitmap, + bitmapInnerPressed: Bitmap, + rectOuter: Rect, + rectInner: Rect, + val legacyId: Int, + val xControl: Int, + val yControl: Int, + private val controllerIndex: Int +) { + var x = 0.0f + private set + var y = 0.0f + private set + var trackId = -1 + private set + private var controlPositionX = 0 + private var controlPositionY = 0 + private var previousTouchX = 0 + private var previousTouchY = 0 + val width: Int + val height: Int + private var virtBounds: Rect + private var origBounds: Rect + private var opacity = 0 + private val outerBitmap: BitmapDrawable + private val defaultStateInnerBitmap: BitmapDrawable + private val pressedStateInnerBitmap: BitmapDrawable + private val boundsBoxBitmap: BitmapDrawable + private var pressedState = false + + var bounds: Rect + get() = outerBitmap.bounds + set(bounds) { + outerBitmap.bounds = bounds + } + + init { + outerBitmap = BitmapDrawable(res, bitmapOuter) + defaultStateInnerBitmap = BitmapDrawable(res, bitmapInnerDefault) + pressedStateInnerBitmap = BitmapDrawable(res, bitmapInnerPressed) + boundsBoxBitmap = BitmapDrawable(res, bitmapOuter) + width = bitmapOuter.width + height = bitmapOuter.height + + require(!(controllerIndex < 0 || controllerIndex >= 4)) { "controllerIndex must be 0-3" } + + bounds = rectOuter + defaultStateInnerBitmap.bounds = rectInner + pressedStateInnerBitmap.bounds = rectInner + virtBounds = bounds + origBounds = outerBitmap.copyBounds() + boundsBoxBitmap.alpha = 0 + boundsBoxBitmap.bounds = virtBounds + setInnerBounds() + } + + fun draw(canvas: Canvas) { + outerBitmap.draw(canvas) + currentStateBitmapDrawable.draw(canvas) + boundsBoxBitmap.draw(canvas) + } + + fun trackEvent(event: MotionEvent): Boolean { + val reCenter = BooleanSetting.MAIN_JOYSTICK_REL_CENTER.boolean + val action = event.actionMasked + val firstPointer = action != MotionEvent.ACTION_POINTER_DOWN && + action != MotionEvent.ACTION_POINTER_UP + val pointerIndex = if (firstPointer) 0 else event.actionIndex + var pressed = false + + when (action) { + MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_POINTER_DOWN -> { + if (bounds.contains( + event.getX(pointerIndex).toInt(), + event.getY(pointerIndex).toInt() + ) + ) { + pressed = true + pressedState = true + outerBitmap.alpha = 0 + boundsBoxBitmap.alpha = opacity + if (reCenter) { + virtBounds.offset( + event.getX(pointerIndex).toInt() - virtBounds.centerX(), + event.getY(pointerIndex).toInt() - virtBounds.centerY() + ) + } + boundsBoxBitmap.bounds = virtBounds + trackId = event.getPointerId(pointerIndex) + } + } + + MotionEvent.ACTION_UP, + MotionEvent.ACTION_POINTER_UP -> { + if (trackId == event.getPointerId(pointerIndex)) { + pressed = true + pressedState = false + y = 0f + x = y + outerBitmap.alpha = opacity + boundsBoxBitmap.alpha = 0 + virtBounds = + Rect(origBounds.left, origBounds.top, origBounds.right, origBounds.bottom) + bounds = + Rect(origBounds.left, origBounds.top, origBounds.right, origBounds.bottom) + setInnerBounds() + trackId = -1 + } + } + } + + if (trackId == -1) + return pressed + + for (i in 0 until event.pointerCount) { + if (trackId == event.getPointerId(i)) { + var touchX = event.getX(i) + var touchY = event.getY(i) + var maxY = virtBounds.bottom.toFloat() + var maxX = virtBounds.right.toFloat() + touchX -= virtBounds.centerX().toFloat() + maxX -= virtBounds.centerX().toFloat() + touchY -= virtBounds.centerY().toFloat() + maxY -= virtBounds.centerY().toFloat() + x = touchX / maxX + y = touchY / maxY + + setInnerBounds() + } + } + return pressed + } + + fun onConfigureTouch(event: MotionEvent) { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + previousTouchX = event.x.toInt() + previousTouchY = event.y.toInt() + } + + MotionEvent.ACTION_MOVE -> { + val deltaX = event.x.toInt() - previousTouchX + val deltaY = event.y.toInt() - previousTouchY + controlPositionX += deltaX + controlPositionY += deltaY + bounds = Rect( + controlPositionX, + controlPositionY, + outerBitmap.intrinsicWidth + controlPositionX, + outerBitmap.intrinsicHeight + controlPositionY + ) + virtBounds = Rect( + controlPositionX, + controlPositionY, + outerBitmap.intrinsicWidth + controlPositionX, + outerBitmap.intrinsicHeight + controlPositionY + ) + setInnerBounds() + origBounds = Rect( + Rect( + controlPositionX, + controlPositionY, + outerBitmap.intrinsicWidth + controlPositionX, + outerBitmap.intrinsicHeight + controlPositionY + ) + ) + previousTouchX = event.x.toInt() + previousTouchY = event.y.toInt() + } + } + } + + private fun setInnerBounds() { + var x = x.toDouble() + var y = y.toDouble() + + val angle = atan2(y, x) + Math.PI + Math.PI + val radius = hypot(y, x) + val maxRadius = InputOverrider.getGateRadiusAtAngle(controllerIndex, xControl, angle) + if (radius > maxRadius) { + x = maxRadius * cos(angle) + y = maxRadius * sin(angle) + this.x = x.toFloat() + this.y = y.toFloat() + } + + val pixelX = virtBounds.centerX() + (x * (virtBounds.width() / 2)).toInt() + val pixelY = virtBounds.centerY() + (y * (virtBounds.height() / 2)).toInt() + + val width = pressedStateInnerBitmap.bounds.width() / 2 + val height = pressedStateInnerBitmap.bounds.height() / 2 + defaultStateInnerBitmap.setBounds( + pixelX - width, + pixelY - height, + pixelX + width, + pixelY + height + ) + pressedStateInnerBitmap.bounds = defaultStateInnerBitmap.bounds + } + + fun setPosition(x: Int, y: Int) { + controlPositionX = x + controlPositionY = y + } + + private val currentStateBitmapDrawable: BitmapDrawable + get() = if (pressedState) pressedStateInnerBitmap else defaultStateInnerBitmap + + fun setOpacity(value: Int) { + opacity = value + + defaultStateInnerBitmap.alpha = value + pressedStateInnerBitmap.alpha = value + + if (trackId == -1) { + outerBitmap.alpha = value + boundsBoxBitmap.alpha = 0 + } else { + outerBitmap.alpha = 0 + boundsBoxBitmap.alpha = value + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.java deleted file mode 100644 index 09d02a174a..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.java +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.overlay; - -import android.graphics.Rect; -import android.os.Handler; -import android.view.MotionEvent; - -import org.dolphinemu.dolphinemu.NativeLibrary; -import org.dolphinemu.dolphinemu.features.input.model.InputOverrider; - -import java.util.ArrayList; - -public class InputOverlayPointer -{ - public static final int MODE_DISABLED = 0; - public static final int MODE_FOLLOW = 1; - public static final int MODE_DRAG = 2; - - private float mCurrentX = 0.0f; - private float mCurrentY = 0.0f; - private float mOldX = 0.0f; - private float mOldY = 0.0f; - - private float mGameCenterX; - private float mGameCenterY; - private float mGameWidthHalfInv; - private float mGameHeightHalfInv; - - private float mTouchStartX; - private float mTouchStartY; - - private int mMode; - private boolean mRecenter; - private int mControllerIndex; - - private boolean doubleTap = false; - private int mDoubleTapControl; - private int trackId = -1; - - public static ArrayList DOUBLE_TAP_OPTIONS = new ArrayList<>(); - - static - { - DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.WIIMOTE_BUTTON_A); - DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.WIIMOTE_BUTTON_B); - DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.WIIMOTE_BUTTON_2); - DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.CLASSIC_BUTTON_A); - } - - public InputOverlayPointer(Rect surfacePosition, int doubleTapControl, int mode, boolean recenter, - int controllerIndex) - { - mDoubleTapControl = doubleTapControl; - mMode = mode; - mRecenter = recenter; - mControllerIndex = controllerIndex; - - mGameCenterX = (surfacePosition.left + surfacePosition.right) / 2.0f; - mGameCenterY = (surfacePosition.top + surfacePosition.bottom) / 2.0f; - - float gameWidth = surfacePosition.right - surfacePosition.left; - float gameHeight = surfacePosition.bottom - surfacePosition.top; - - // Adjusting for device's black bars. - float surfaceAR = gameWidth / gameHeight; - float gameAR = NativeLibrary.GetGameAspectRatio(); - - if (gameAR <= surfaceAR) - { - // Black bars on left/right - gameWidth = gameHeight * gameAR; - } - else - { - // Black bars on top/bottom - gameHeight = gameWidth / gameAR; - } - - mGameWidthHalfInv = 1.0f / (gameWidth * 0.5f); - mGameHeightHalfInv = 1.0f / (gameHeight * 0.5f); - } - - public void onTouch(MotionEvent event) - { - int action = event.getActionMasked(); - boolean firstPointer = action != MotionEvent.ACTION_POINTER_DOWN && - action != MotionEvent.ACTION_POINTER_UP; - int pointerIndex = firstPointer ? 0 : event.getActionIndex(); - - switch (action) - { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - trackId = event.getPointerId(pointerIndex); - mTouchStartX = event.getX(pointerIndex); - mTouchStartY = event.getY(pointerIndex); - touchPress(); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - if (trackId == event.getPointerId(pointerIndex)) - trackId = -1; - if (mMode == MODE_DRAG) - updateOldAxes(); - if (mRecenter) - reset(); - break; - } - - int eventPointerIndex = event.findPointerIndex(trackId); - if (trackId == -1 || eventPointerIndex == -1) - return; - - if (mMode == MODE_FOLLOW) - { - mCurrentX = (event.getX(eventPointerIndex) - mGameCenterX) * mGameWidthHalfInv; - mCurrentY = (event.getY(eventPointerIndex) - mGameCenterY) * mGameHeightHalfInv; - } - else if (mMode == MODE_DRAG) - { - mCurrentX = mOldX + - (event.getX(eventPointerIndex) - mTouchStartX) * mGameWidthHalfInv; - mCurrentY = mOldY + - (event.getY(eventPointerIndex) - mTouchStartY) * mGameHeightHalfInv; - } - } - - private void touchPress() - { - if (mMode != MODE_DISABLED) - { - if (doubleTap) - { - InputOverrider.setControlState(mControllerIndex, mDoubleTapControl, 1.0); - new Handler().postDelayed(() -> InputOverrider.setControlState(mControllerIndex, - mDoubleTapControl, 0.0), - 50); - } - else - { - doubleTap = true; - new Handler().postDelayed(() -> doubleTap = false, 300); - } - } - } - - private void updateOldAxes() - { - mOldX = mCurrentX; - mOldY = mCurrentY; - } - - private void reset() - { - mCurrentX = mCurrentY = mOldX = mOldY = 0.0f; - } - - public float getX() - { - return mCurrentX; - } - - public float getY() - { - return mCurrentY; - } - - public void setMode(int mode) - { - mMode = mode; - if (mode == MODE_DRAG) - updateOldAxes(); - } - - public void setRecenter(boolean recenter) - { - mRecenter = recenter; - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.kt new file mode 100644 index 0000000000..138effca6f --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.kt @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.overlay + +import android.graphics.Rect +import android.os.Handler +import android.os.Looper +import android.view.MotionEvent +import org.dolphinemu.dolphinemu.NativeLibrary +import org.dolphinemu.dolphinemu.features.input.model.InputOverrider + +class InputOverlayPointer( + surfacePosition: Rect, + private val doubleTapControl: Int, + private var mode: Int, + private var recenter: Boolean, + private val controllerIndex: Int +) { + var x = 0.0f + var y = 0.0f + private var oldX = 0.0f + private var oldY = 0.0f + + private val gameCenterX: Float + private val gameCenterY: Float + private val gameWidthHalfInv: Float + private val gameHeightHalfInv: Float + + private var touchStartX = 0f + private var touchStartY = 0f + + private var doubleTap = false + private var trackId = -1 + + init { + gameCenterX = (surfacePosition.left + surfacePosition.right) / 2f + gameCenterY = (surfacePosition.top + surfacePosition.bottom) / 2f + + var gameWidth = (surfacePosition.right - surfacePosition.left).toFloat() + var gameHeight = (surfacePosition.bottom - surfacePosition.top).toFloat() + + // Adjusting for device's black bars. + val surfaceAR = gameWidth / gameHeight + val gameAR = NativeLibrary.GetGameAspectRatio() + if (gameAR <= surfaceAR) { + // Black bars on left/right + gameWidth = gameHeight * gameAR + } else { + // Black bars on top/bottom + gameHeight = gameWidth / gameAR + } + + gameWidthHalfInv = 1f / (gameWidth * 0.5f) + gameHeightHalfInv = 1f / (gameHeight * 0.5f) + } + + fun onTouch(event: MotionEvent) { + val action = event.actionMasked + val firstPointer = action != MotionEvent.ACTION_POINTER_DOWN && + action != MotionEvent.ACTION_POINTER_UP + val pointerIndex = if (firstPointer) 0 else event.actionIndex + + when (action) { + MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_POINTER_DOWN -> { + trackId = event.getPointerId(pointerIndex) + touchStartX = event.getX(pointerIndex) + touchStartY = event.getY(pointerIndex) + touchPress() + } + + MotionEvent.ACTION_UP, + MotionEvent.ACTION_POINTER_UP -> { + if (trackId == event.getPointerId(pointerIndex)) + trackId = -1 + if (mode == MODE_DRAG) + updateOldAxes() + if (recenter) + reset() + } + } + + val eventPointerIndex = event.findPointerIndex(trackId) + if (trackId == -1 || eventPointerIndex == -1) + return + + if (mode == MODE_FOLLOW) { + x = (event.getX(eventPointerIndex) - gameCenterX) * gameWidthHalfInv + y = (event.getY(eventPointerIndex) - gameCenterY) * gameHeightHalfInv + } else if (mode == MODE_DRAG) { + x = oldX + (event.getX(eventPointerIndex) - touchStartX) * gameWidthHalfInv + y = oldY + (event.getY(eventPointerIndex) - touchStartY) * gameHeightHalfInv + } + } + + private fun touchPress() { + if (mode != MODE_DISABLED) { + if (doubleTap) { + InputOverrider.setControlState(controllerIndex, doubleTapControl, 1.0) + Handler(Looper.myLooper()!!).postDelayed( + { + InputOverrider.setControlState(controllerIndex, doubleTapControl, 0.0) + }, + 50 + ) + } else { + doubleTap = true + Handler(Looper.myLooper()!!).postDelayed({ doubleTap = false }, 300) + } + } + } + + private fun updateOldAxes() { + oldX = x + oldY = y + } + + private fun reset() { + oldY = 0.0f + oldX = 0.0f + y = 0.0f + x = 0.0f + } + + fun setMode(mode: Int) { + this.mode = mode + if (mode == MODE_DRAG) + updateOldAxes() + } + + fun setRecenter(recenter: Boolean) { + this.recenter = recenter + } + + companion object { + const val MODE_DISABLED = 0 + const val MODE_FOLLOW = 1 + const val MODE_DRAG = 2 + + @JvmField + var DOUBLE_TAP_OPTIONS = arrayListOf( + NativeLibrary.ButtonType.WIIMOTE_BUTTON_A, + NativeLibrary.ButtonType.WIIMOTE_BUTTON_B, + NativeLibrary.ButtonType.WIIMOTE_BUTTON_2, + NativeLibrary.ButtonType.CLASSIC_BUTTON_A + ) + } +}