From 47d6406fd4492d46613dbb107bc3deb36fd3254d Mon Sep 17 00:00:00 2001 From: zackhow Date: Fri, 5 Oct 2018 16:59:17 -0400 Subject: [PATCH 1/8] Android: Add touch to move pointer in overlay --- .../fragments/EmulationFragment.java | 16 +--- .../dolphinemu/overlay/InputOverlay.java | 87 +++++++++++++------ .../overlay/InputOverlayDrawableButton.java | 1 + .../overlay/InputOverlayDrawableDpad.java | 1 + .../overlay/InputOverlayDrawableJoystick.java | 14 ++- .../overlay/InputOverlayPointer.java | 60 +++++++++++++ .../ControllerInterface/Android/Android.h | 1 + 7 files changed, 136 insertions(+), 44 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.java 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 dc888d74d4..25b84a811a 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 @@ -102,14 +102,6 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C surfaceView.getHolder().addCallback(this); mInputOverlay = contents.findViewById(R.id.surface_input_overlay); - if (mInputOverlay != null) - { - // If the input overlay was previously disabled, then don't show it. - if (!mPreferences.getBoolean("showInputOverlay", true)) - { - mInputOverlay.setVisibility(View.GONE); - } - } Button doneButton = contents.findViewById(R.id.done_control_config); if (doneButton != null) @@ -199,18 +191,14 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C // If the overlay is currently set to INVISIBLE if (!mPreferences.getBoolean("showInputOverlay", false)) { - // Set it to VISIBLE - mInputOverlay.setVisibility(View.VISIBLE); editor.putBoolean("showInputOverlay", true); } else { - // Set it to INVISIBLE - mInputOverlay.setVisibility(View.GONE); editor.putBoolean("showInputOverlay", false); } - - editor.apply(); + editor.commit(); + mInputOverlay.refreshControls(); } public void refreshInputOverlay() 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 index de29e00ed5..e7ad7dbae7 100644 --- 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 @@ -43,6 +43,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener private final Set overlayButtons = new HashSet<>(); private final Set overlayDpads = new HashSet<>(); private final Set overlayJoysticks = new HashSet<>(); + private InputOverlayPointer overlayPointer; private boolean mIsInEditMode = false; private InputOverlayDrawableButton mButtonBeingConfigured; @@ -128,6 +129,8 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener } int pointerIndex = event.getActionIndex(); + // Tracks if any button/joystick is pressed down + boolean pressed = false; for (InputOverlayDrawableButton button : overlayButtons) { @@ -142,6 +145,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener { button.setPressedState(true); button.setTrackId(event.getPointerId(pointerIndex)); + pressed = true; NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), ButtonState.PRESSED); } @@ -154,6 +158,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener button.setPressedState(false); NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), ButtonState.RELEASED); + button.setTrackId(-1); } break; } @@ -166,35 +171,40 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: - case MotionEvent.ACTION_MOVE: - // Up, Down, Left, Right - boolean[] pressed = {false, false, false, false}; // 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)) - pressed[0] = true; + dpadPressed[0] = true; if (dpad.getBounds().bottom - (dpad.getHeight() / 3) < (int) event.getY(pointerIndex)) - pressed[1] = true; + dpadPressed[1] = true; if (dpad.getBounds().left + (dpad.getWidth() / 3) > (int) event.getX(pointerIndex)) - pressed[2] = true; + dpadPressed[2] = true; if (dpad.getBounds().right - (dpad.getWidth() / 3) < (int) event.getX(pointerIndex)) - pressed[3] = true; + dpadPressed[3] = true; // Release the buttons first, then press - for (int i = 0; i < pressed.length; i++) - if (!pressed[i]) + for (int i = 0; i < dpadPressed.length; i++) + if (!dpadPressed[i]) NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i), ButtonState.RELEASED); // Press buttons - for (int i = 0; i < pressed.length; i++) - if (pressed[i]) + for (int i = 0; i < dpadPressed.length; i++) + if (dpadPressed[i]) NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i), ButtonState.PRESSED); - setDpadState(dpad, pressed[0], pressed[1], pressed[2], pressed[3]); - dpad.setTrackId(event.getPointerId(pointerIndex)); + setDpadState(dpad, dpadPressed[0], dpadPressed[1], dpadPressed[2], dpadPressed[3]); } break; case MotionEvent.ACTION_UP: @@ -208,6 +218,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i), ButtonState.RELEASED); } + dpad.setTrackId(-1); } break; } @@ -215,7 +226,11 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener for (InputOverlayDrawableJoystick joystick : overlayJoysticks) { - joystick.TrackEvent(event); + if (joystick.TrackEvent(event)) + { + if (joystick.getTrackId() != -1) + pressed = true; + } int[] axisIDs = joystick.getAxisIDs(); float[] axises = joystick.getAxisValues(); @@ -225,6 +240,18 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener } } + // No button/joystick pressed, safe to move pointer + if (!pressed && overlayPointer != null) + { + overlayPointer.onTouch(event); + float[] axises = overlayPointer.getAxisValues(); + + NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, ButtonType.WIIMOTE_IR + 2, + axises[0]); + NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, ButtonType.WIIMOTE_IR + 4, + axises[1]); + } + invalidate(); return true; @@ -617,24 +644,30 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ? "-Portrait" : ""; - // Add all the enabled overlay items back to the HashSet. - if (EmulationActivity.isGameCubeGame() || mPreferences.getInt("wiiController", 3) == 0) + if (mPreferences.getBoolean("showInputOverlay", true)) { - addGameCubeOverlayControls(orientation); - } - else if (mPreferences.getInt("wiiController", 3) == 4) - { - addClassicOverlayControls(orientation); - } - else - { - addWiimoteOverlayControls(orientation); - if (mPreferences.getInt("wiiController", 3) == 3) + // Add all the enabled overlay items back to the HashSet. + if (EmulationActivity.isGameCubeGame() || mPreferences.getInt("wiiController", 3) == 0) { - addNunchukOverlayControls(orientation); + addGameCubeOverlayControls(orientation); + } + else if (mPreferences.getInt("wiiController", 3) == 4) + { + addClassicOverlayControls(orientation); + } + else + { + addWiimoteOverlayControls(orientation); + if (mPreferences.getInt("wiiController", 3) == 3) + { + addNunchukOverlayControls(orientation); + } } } + if (!EmulationActivity.isGameCubeGame()) + overlayPointer = new InputOverlayPointer(this.getContext()); + invalidate(); } 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 index 96b4aeca0a..266cd273c4 100644 --- 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 @@ -41,6 +41,7 @@ public final class InputOverlayDrawableButton public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap, Bitmap pressedStateBitmap, int buttonType) { + mTrackId = -1; mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap); mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap); mButtonType = buttonType; 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 index fd60f1fc98..5aa8c4846d 100644 --- 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 @@ -60,6 +60,7 @@ public final class InputOverlayDrawableDpad int buttonUp, int buttonDown, int buttonLeft, int buttonRight) { + mTrackId = -1; mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap); mPressedOneDirectionStateBitmap = new BitmapDrawable(res, pressedOneDirectionStateBitmap); mPressedTwoDirectionsStateBitmap = new BitmapDrawable(res, pressedTwoDirectionsStateBitmap); 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 index a54d01c7cf..55f6347096 100644 --- 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 @@ -94,10 +94,11 @@ public final class InputOverlayDrawableJoystick mBoundsBoxBitmap.draw(canvas); } - public void TrackEvent(MotionEvent event) + public boolean TrackEvent(MotionEvent event) { boolean reCenter = mPreferences.getBoolean("joystickRelCenter", true); int pointerIndex = event.getActionIndex(); + boolean pressed = false; switch (event.getAction() & MotionEvent.ACTION_MASK) { @@ -105,7 +106,7 @@ public final class InputOverlayDrawableJoystick case MotionEvent.ACTION_POINTER_DOWN: if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) { - mPressedState = true; + mPressedState = pressed = true; mOuterBitmap.setAlpha(0); mBoundsBoxBitmap.setAlpha(255); if (reCenter) @@ -121,6 +122,7 @@ public final class InputOverlayDrawableJoystick case MotionEvent.ACTION_POINTER_UP: if (trackId == event.getPointerId(pointerIndex)) { + pressed = true; mPressedState = false; axises[0] = axises[1] = 0.0f; mOuterBitmap.setAlpha(255); @@ -136,7 +138,7 @@ public final class InputOverlayDrawableJoystick } if (trackId == -1) - return; + return pressed; for (int i = 0; i < event.getPointerCount(); i++) { @@ -158,6 +160,7 @@ public final class InputOverlayDrawableJoystick SetInnerBounds(); } } + return pressed; } public boolean onConfigureTouch(MotionEvent event) @@ -274,4 +277,9 @@ public final class InputOverlayDrawableJoystick { return mHeight; } + + public int getTrackId() + { + return trackId; + } } 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 new file mode 100644 index 0000000000..1191d2dc7a --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/overlay/InputOverlayPointer.java @@ -0,0 +1,60 @@ +package org.dolphinemu.dolphinemu.overlay; + +import android.app.Activity; +import android.content.Context; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.MotionEvent; + +public class InputOverlayPointer +{ + private final float[] axes = {0f, 0f}; + private float maxHeight; + private float maxWidth; + private int trackId = -1; + + public InputOverlayPointer(Context context) + { + Display display = ((Activity) context).getWindowManager().getDefaultDisplay(); + DisplayMetrics outMetrics = new DisplayMetrics(); + display.getMetrics(outMetrics); + maxWidth = outMetrics.widthPixels / 2; + maxHeight = outMetrics.heightPixels / 2; + } + + public boolean onTouch(MotionEvent event) + { + int pointerIndex = event.getActionIndex(); + + switch (event.getAction() & MotionEvent.ACTION_MASK) + { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + trackId = event.getPointerId(pointerIndex); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + if (trackId == event.getPointerId(pointerIndex)) + trackId = -1; + break; + } + + if (trackId == -1) + return false; + + int x = (int) event.getX(event.findPointerIndex(trackId)); + int y = (int) event.getY(event.findPointerIndex(trackId)); + axes[0] = (y - maxHeight) / maxHeight; + axes[1] = (x - maxWidth) / maxWidth; + + return false; + } + + public float[] getAxisValues() + { + float[] ir = {0f, 0f}; + ir[0] = axes[0]; + ir[1] = axes[1]; + return axes; + } +} diff --git a/Source/Core/InputCommon/ControllerInterface/Android/Android.h b/Source/Core/InputCommon/ControllerInterface/Android/Android.h index deb23539ce..59919982ef 100644 --- a/Source/Core/InputCommon/ControllerInterface/Android/Android.h +++ b/Source/Core/InputCommon/ControllerInterface/Android/Android.h @@ -30,6 +30,7 @@ private: { public: std::string GetName() const; + bool IsDetectable() override { return false; } Axis(int padID, ButtonManager::ButtonType index, float neg = 1.0f) : _padID(padID), _index(index), _neg(neg) { From 1db02c14c7d289eb2e6466928fe7ccf7e074ba7a Mon Sep 17 00:00:00 2001 From: zackhow Date: Sat, 13 Oct 2018 07:17:14 -0400 Subject: [PATCH 2/8] Android: add IR width/height/center option in emu menu This sets the IR/Width, IR/Height, and IR/Center per game, so a controller profile is used to save the value, then enable the profile in the game ini, then reload the control configs. --- .../dolphinemu/dolphinemu/NativeLibrary.java | 2 + .../activities/EmulationActivity.java | 141 +++++++++++++++++- .../features/settings/utils/SettingsFile.java | 3 + .../main/res/layout/dialog_ir_sensitivity.xml | 115 ++++++++++++++ .../src/main/res/menu/menu_emulation_wii.xml | 5 + .../app/src/main/res/values/strings.xml | 7 + Source/Android/jni/MainAndroid.cpp | 6 + 7 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 Source/Android/app/src/main/res/layout/dialog_ir_sensitivity.xml diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 6574d22199..585506f419 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -397,6 +397,8 @@ public final class NativeLibrary */ public static native void RefreshWiimotes(); + public static native void ReloadWiimoteConfig(); + private static boolean alertResult = false; public static boolean displayAlertMsg(final String caption, final String text, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index f5309869d5..012b11de7c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -74,12 +74,14 @@ public final class EmulationActivity extends AppCompatActivity private boolean activityRecreated; private String mSelectedTitle; + private String mSelectedGameId; private int mPlatform; private String[] mPaths; private boolean backPressedOnce = false; public static final String EXTRA_SELECTED_GAMES = "SelectedGames"; public static final String EXTRA_SELECTED_TITLE = "SelectedTitle"; + public static final String EXTRA_SELECTED_GAMEID = "SelectedGameId"; public static final String EXTRA_PLATFORM = "Platform"; @Retention(SOURCE) @@ -91,7 +93,7 @@ public final class EmulationActivity extends AppCompatActivity MENU_ACTION_SAVE_SLOT6, MENU_ACTION_LOAD_SLOT1, MENU_ACTION_LOAD_SLOT2, MENU_ACTION_LOAD_SLOT3, MENU_ACTION_LOAD_SLOT4, MENU_ACTION_LOAD_SLOT5, MENU_ACTION_LOAD_SLOT6, MENU_ACTION_EXIT, MENU_ACTION_CHANGE_DISC, - MENU_ACTION_RESET_OVERLAY}) + MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_SENSITIVITY}) public @interface MenuAction { } @@ -123,6 +125,7 @@ public final class EmulationActivity extends AppCompatActivity public static final int MENU_ACTION_JOYSTICK_REL_CENTER = 24; public static final int MENU_ACTION_RUMBLE = 25; public static final int MENU_ACTION_RESET_OVERLAY = 26; + public static final int MENU_SET_IR_SENSITIVITY = 27; private static SparseIntArray buttonsActionsMap = new SparseIntArray(); @@ -165,6 +168,8 @@ public final class EmulationActivity extends AppCompatActivity buttonsActionsMap.append(R.id.menu_emulation_rumble, EmulationActivity.MENU_ACTION_RUMBLE); buttonsActionsMap .append(R.id.menu_emulation_reset_overlay, EmulationActivity.MENU_ACTION_RESET_OVERLAY); + buttonsActionsMap.append(R.id.menu_emulation_set_ir_sensitivity, + EmulationActivity.MENU_SET_IR_SENSITIVITY); } private static String[] scanForSecondDisc(GameFile gameFile) @@ -182,6 +187,7 @@ public final class EmulationActivity extends AppCompatActivity launcher.putExtra(EXTRA_SELECTED_GAMES, scanForSecondDisc(gameFile)); launcher.putExtra(EXTRA_SELECTED_TITLE, gameFile.getTitle()); + launcher.putExtra(EXTRA_SELECTED_GAMEID, gameFile.getGameId()); launcher.putExtra(EXTRA_PLATFORM, gameFile.getPlatform()); activity.startActivityForResult(launcher, MainPresenter.REQUEST_EMULATE_GAME); } @@ -201,6 +207,7 @@ public final class EmulationActivity extends AppCompatActivity Intent gameToEmulate = getIntent(); mPaths = gameToEmulate.getStringArrayExtra(EXTRA_SELECTED_GAMES); mSelectedTitle = gameToEmulate.getStringExtra(EXTRA_SELECTED_TITLE); + mSelectedGameId = gameToEmulate.getStringExtra(EXTRA_SELECTED_GAMEID); mPlatform = gameToEmulate.getIntExtra(EXTRA_PLATFORM, 0); activityRecreated = false; } @@ -294,6 +301,7 @@ public final class EmulationActivity extends AppCompatActivity } outState.putStringArray(EXTRA_SELECTED_GAMES, mPaths); outState.putString(EXTRA_SELECTED_TITLE, mSelectedTitle); + outState.putString(EXTRA_SELECTED_GAMEID, mSelectedGameId); outState.putInt(EXTRA_PLATFORM, mPlatform); super.onSaveInstanceState(outState); } @@ -302,6 +310,7 @@ public final class EmulationActivity extends AppCompatActivity { mPaths = savedInstanceState.getStringArray(EXTRA_SELECTED_GAMES); mSelectedTitle = savedInstanceState.getString(EXTRA_SELECTED_TITLE); + mSelectedGameId = savedInstanceState.getString(EXTRA_SELECTED_GAMEID); mPlatform = savedInstanceState.getInt(EXTRA_PLATFORM); } @@ -578,6 +587,10 @@ public final class EmulationActivity extends AppCompatActivity FileBrowserHelper.openFilePicker(this, REQUEST_CHANGE_DISC); return; + case MENU_SET_IR_SENSITIVITY: + setIRSensitivity(); + return; + case MENU_ACTION_EXIT: // ATV menu is built using a fragment, this will pop that fragment before emulation ends. if (TvUtil.isLeanback(getApplicationContext())) @@ -785,6 +798,132 @@ public final class EmulationActivity extends AppCompatActivity } + private void setIRSensitivity() + { + int irHeight = Integer.valueOf( + mPreferences.getString(SettingsFile.KEY_WIIBIND_IR_HEIGHT + mSelectedGameId, "50")); + + LayoutInflater inflater = LayoutInflater.from(this); + View view = inflater.inflate(R.layout.dialog_ir_sensitivity, null); + + TextView mTextSliderValueHeight = (TextView) view.findViewById(R.id.text_ir_height); + TextView units = (TextView) view.findViewById(R.id.text_ir_height_units); + SeekBar seekbarHeight = view.findViewById(R.id.seekbar_height); + + mTextSliderValueHeight.setText(String.valueOf(irHeight)); + units.setText(getString(R.string.height)); + seekbarHeight.setMax(100); + seekbarHeight.setProgress(irHeight); + seekbarHeight.setKeyProgressIncrement(5); + seekbarHeight.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() + { + @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) + { + mTextSliderValueHeight.setText(String.valueOf(progress)); + } + + @Override public void onStartTrackingTouch(SeekBar seekBar) + { + // Do nothing + } + + @Override public void onStopTrackingTouch(SeekBar seekBar) + { + // Do nothing + } + }); + + int irWidth = Integer.valueOf( + mPreferences.getString(SettingsFile.KEY_WIIBIND_IR_WIDTH + mSelectedGameId, "50")); + + TextView mTextSliderValueWidth = (TextView) view.findViewById(R.id.text_ir_width); + TextView unitsWidth = (TextView) view.findViewById(R.id.text_ir_width_units); + SeekBar seekbarWidth = view.findViewById(R.id.seekbar_width); + + mTextSliderValueWidth.setText(String.valueOf(irWidth)); + unitsWidth.setText(getString(R.string.width)); + seekbarWidth.setMax(100); + seekbarWidth.setProgress(irWidth); + seekbarWidth.setKeyProgressIncrement(5); + seekbarWidth.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() + { + @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) + { + mTextSliderValueWidth.setText(String.valueOf(progress)); + } + + @Override public void onStartTrackingTouch(SeekBar seekBar) + { + // Do nothing + } + + @Override public void onStopTrackingTouch(SeekBar seekBar) + { + // Do nothing + } + }); + + + int irCenter = Integer.valueOf( + mPreferences.getString(SettingsFile.KEY_WIIBIND_IR_CENTER + mSelectedGameId, "50")); + + TextView mTextSliderValueCenter = (TextView) view.findViewById(R.id.text_ir_center); + TextView unitsCenter = (TextView) view.findViewById(R.id.text_ir_center_units); + SeekBar seekbarCenter = view.findViewById(R.id.seekbar_center); + + mTextSliderValueCenter.setText(String.valueOf(irCenter)); + unitsCenter.setText(getString(R.string.center)); + seekbarCenter.setMax(100); + seekbarCenter.setProgress(irCenter); + seekbarCenter.setKeyProgressIncrement(5); + seekbarCenter.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() + { + @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) + { + mTextSliderValueCenter.setText(String.valueOf(progress)); + } + + @Override public void onStartTrackingTouch(SeekBar seekBar) + { + // Do nothing + } + + @Override public void onStopTrackingTouch(SeekBar seekBar) + { + // Do nothing + } + }); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.emulation_ir_sensitivity)); + builder.setView(view); + builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> + { + SettingsFile.saveSingleCustomSetting(mSelectedGameId, Settings.SECTION_CONTROLS, + SettingsFile.KEY_WIIBIND_IR_HEIGHT, mTextSliderValueHeight.getText().toString()); + SettingsFile.saveSingleCustomSetting(mSelectedGameId, Settings.SECTION_CONTROLS, + SettingsFile.KEY_WIIBIND_IR_WIDTH, mTextSliderValueWidth.getText().toString()); + SettingsFile.saveSingleCustomSetting(mSelectedGameId, Settings.SECTION_CONTROLS, + SettingsFile.KEY_WIIBIND_IR_CENTER, mTextSliderValueCenter.getText().toString()); + + NativeLibrary.ReloadWiimoteConfig(); + + SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString(SettingsFile.KEY_WIIBIND_IR_HEIGHT + mSelectedGameId, + mTextSliderValueHeight.getText().toString()); + editor.putString(SettingsFile.KEY_WIIBIND_IR_WIDTH + mSelectedGameId, + mTextSliderValueWidth.getText().toString()); + editor.putString(SettingsFile.KEY_WIIBIND_IR_CENTER + mSelectedGameId, + mTextSliderValueCenter.getText().toString()); + editor.apply(); + }); + builder.setNegativeButton(R.string.cancel, (dialogInterface, i) -> + { + // Do nothing + }); + builder.show(); + } + private void resetOverlay() { new AlertDialog.Builder(this) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java index 0dd027cd80..df51a38e04 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java @@ -151,6 +151,9 @@ public final class SettingsFile public static final String KEY_WIIBIND_IR_FORWARD = "IRForward_"; public static final String KEY_WIIBIND_IR_BACKWARD = "IRBackward_"; public static final String KEY_WIIBIND_IR_HIDE = "IRHide_"; + public static final String KEY_WIIBIND_IR_HEIGHT = "IRHeight"; + public static final String KEY_WIIBIND_IR_WIDTH = "IRWidth"; + public static final String KEY_WIIBIND_IR_CENTER = "IRCenter"; public static final String KEY_WIIBIND_SWING_UP = "SwingUp_"; public static final String KEY_WIIBIND_SWING_DOWN = "SwingDown_"; public static final String KEY_WIIBIND_SWING_LEFT = "SwingLeft_"; diff --git a/Source/Android/app/src/main/res/layout/dialog_ir_sensitivity.xml b/Source/Android/app/src/main/res/layout/dialog_ir_sensitivity.xml new file mode 100644 index 0000000000..8f60d318e2 --- /dev/null +++ b/Source/Android/app/src/main/res/layout/dialog_ir_sensitivity.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/menu/menu_emulation_wii.xml b/Source/Android/app/src/main/res/menu/menu_emulation_wii.xml index 5a26d61814..8a5a729783 100644 --- a/Source/Android/app/src/main/res/menu/menu_emulation_wii.xml +++ b/Source/Android/app/src/main/res/menu/menu_emulation_wii.xml @@ -113,6 +113,11 @@ android:id="@+id/menu_emulation_choose_controller" android:title="@string/emulation_choose_controller"/> + + diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 8c2c821aaf..a33db04ac8 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -298,6 +298,7 @@ You may have to reload the game after changing extensions. Swipe down from the top of the screen to access the menu. Reset Overlay + IR Sensitivity Enable Vibration @@ -322,4 +323,10 @@ Favorites Select This Directory + + + Height + Width + Center + diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index c606345abe..8fe7c4942f 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -571,6 +571,12 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimo WiimoteReal::Refresh(); } +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadWiimoteConfig(JNIEnv* env, + jobject obj) +{ + Wiimote::LoadConfig(); +} + static void Run(const std::vector& paths, bool first_open, std::optional savestate_path = {}, bool delete_savestate = false) { From d0b42286cff1e5f9c9f2de205213c16f98bd34fe Mon Sep 17 00:00:00 2001 From: zackhow Date: Wed, 24 Oct 2018 21:29:48 -0400 Subject: [PATCH 3/8] Load custom game IR values if they are not set This is mostly for android so that a user can use the touchscreen to accurately emulate pointer movements --- Source/Core/InputCommon/InputConfig.cpp | 33 ++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/Source/Core/InputCommon/InputConfig.cpp b/Source/Core/InputCommon/InputConfig.cpp index 65cfdef086..0a6a82d540 100644 --- a/Source/Core/InputCommon/InputConfig.cpp +++ b/Source/Core/InputCommon/InputConfig.cpp @@ -33,6 +33,11 @@ bool InputConfig::LoadConfig(bool isGC) std::string profile[MAX_BBMOTES]; std::string path; +#if defined(ANDROID) + bool use_ir_config = false; + std::string ir_values[3]; +#endif + if (SConfig::GetInstance().GetGameID() != "00000000") { std::string type; @@ -73,6 +78,18 @@ bool InputConfig::LoadConfig(bool isGC) } } } +#if defined(ANDROID) + // For use on android touchscreen IR pointer + // Check for IR values + if (control_section->Exists("IRWidth") && control_section->Exists("IRHeight") && + control_section->Exists("IRCenter")) + { + use_ir_config = true; + control_section->Get("IRWidth", &ir_values[0]); + control_section->Get("IRHeight", &ir_values[1]); + control_section->Get("IRCenter", &ir_values[2]); + } +#endif } if (inifile.Load(File::GetUserPath(D_CONFIG_IDX) + m_ini_name + ".ini")) @@ -80,6 +97,7 @@ bool InputConfig::LoadConfig(bool isGC) int n = 0; for (auto& controller : m_controllers) { + IniFile::Section config; // Load settings from ini if (useProfile[n]) { @@ -91,13 +109,22 @@ bool InputConfig::LoadConfig(bool isGC) IniFile profile_ini; profile_ini.Load(profile[n]); - controller->LoadConfig(profile_ini.GetOrCreateSection("Profile")); + config = *profile_ini.GetOrCreateSection("Profile"); } else { - controller->LoadConfig(inifile.GetOrCreateSection(controller->GetName())); + config = *inifile.GetOrCreateSection(controller->GetName()); } - +#if defined(ANDROID) + // Only set for wii pads + if (!isGC && use_ir_config) + { + config.Set("IR/Width", ir_values[0]); + config.Set("IR/Height", ir_values[1]); + config.Set("IR/Center", ir_values[2]); + } +#endif + controller->LoadConfig(&config); // Update refs controller->UpdateReferences(g_controller_interface); From 8c3129697cb3b287b4eeac6b9be5a837c34b51b6 Mon Sep 17 00:00:00 2001 From: zackhow Date: Sun, 28 Oct 2018 11:35:49 -0400 Subject: [PATCH 4/8] Android/GameSettings: Add IR defaults for RMG, RUU, RZD, RMC, SB4, and ROD --- Data/Sys/GameSettings/RMC.ini | 5 +++++ Data/Sys/GameSettings/RMG.ini | 5 +++++ Data/Sys/GameSettings/ROD.ini | 4 ++++ Data/Sys/GameSettings/RUU.ini | 4 ++++ Data/Sys/GameSettings/RZD.ini | 4 ++++ Data/Sys/GameSettings/SB4.ini | 4 ++++ 6 files changed, 26 insertions(+) diff --git a/Data/Sys/GameSettings/RMC.ini b/Data/Sys/GameSettings/RMC.ini index 5dcaf1d11b..2f933454a1 100644 --- a/Data/Sys/GameSettings/RMC.ini +++ b/Data/Sys/GameSettings/RMC.ini @@ -1,5 +1,10 @@ # RMCE01, RMCJ01, RMCK01, RMCP01 - Mario Kart Wii +[Controls] +IRHeight = 50 +IRWidth = 30 +IRCenter = 50 + [Core] # Values set here will override the main Dolphin settings. diff --git a/Data/Sys/GameSettings/RMG.ini b/Data/Sys/GameSettings/RMG.ini index e599c21f3d..ac715ed28b 100644 --- a/Data/Sys/GameSettings/RMG.ini +++ b/Data/Sys/GameSettings/RMG.ini @@ -1,5 +1,10 @@ # RMGE01, RMGJ01, RMGK01, RMGP01 - SUPER MARIO GALAXY +[Controls] +IRHeight = 50 +IRWidth = 30 +IRCenter = 50 + [Core] # Values set here will override the main Dolphin settings. diff --git a/Data/Sys/GameSettings/ROD.ini b/Data/Sys/GameSettings/ROD.ini index 229988d24c..90c26ba2cd 100644 --- a/Data/Sys/GameSettings/ROD.ini +++ b/Data/Sys/GameSettings/ROD.ini @@ -1,4 +1,8 @@ # RODE01, RODJ01, RODK01, RODP01 - WarioWare: Smooth Moves +[Controls] +IRHeight = 71 +IRWidth = 64 +IRCenter = 99 [Core] # Values set here will override the main Dolphin settings. diff --git a/Data/Sys/GameSettings/RUU.ini b/Data/Sys/GameSettings/RUU.ini index c9ce0e9055..6a9159d4d6 100644 --- a/Data/Sys/GameSettings/RUU.ini +++ b/Data/Sys/GameSettings/RUU.ini @@ -1,4 +1,8 @@ # RUUE01, RUUJ01, RUUK01, RUUP01 - Animal Crossing Wii +[Controls] +IRHeight = 50 +IRWidth = 30 +IRCenter = 50 [Core] # Values set here will override the main Dolphin settings. diff --git a/Data/Sys/GameSettings/RZD.ini b/Data/Sys/GameSettings/RZD.ini index bf2a80008f..0ceb74c8ac 100644 --- a/Data/Sys/GameSettings/RZD.ini +++ b/Data/Sys/GameSettings/RZD.ini @@ -1,4 +1,8 @@ # RZDE01, RZDJ01, RZDK01, RZDP01 - The Legend of Zelda: Twilight Princess [Wii] +[Controls] +IRHeight = 39 +IRWidth = 37 +IRCenter = 91 [Core] # Values set here will override the main Dolphin settings. diff --git a/Data/Sys/GameSettings/SB4.ini b/Data/Sys/GameSettings/SB4.ini index 00cce48a86..2fccf50960 100644 --- a/Data/Sys/GameSettings/SB4.ini +++ b/Data/Sys/GameSettings/SB4.ini @@ -1,4 +1,8 @@ # SB4E01, SB4J01, SB4P01 - Super Mario Galaxy 2 +[Controls] +IRHeight = 50 +IRWidth = 30 +IRCenter = 50 [Core] # Values set here will override the main Dolphin settings. From f9936592493d46392e0def1c04936679009b972f Mon Sep 17 00:00:00 2001 From: zackhow Date: Tue, 8 Jan 2019 23:47:59 -0500 Subject: [PATCH 5/8] Android: Add IR width/height/center defaults The added values were the most common from the few games tested this can be changed later if thats not the case --- Source/Android/app/src/main/assets/WiimoteNew.ini | 12 ++++++++++++ .../Android/app/src/main/assets/WiimoteProfile.ini | 3 +++ 2 files changed, 15 insertions(+) diff --git a/Source/Android/app/src/main/assets/WiimoteNew.ini b/Source/Android/app/src/main/assets/WiimoteNew.ini index e8efbaf794..caa82c3268 100644 --- a/Source/Android/app/src/main/assets/WiimoteNew.ini +++ b/Source/Android/app/src/main/assets/WiimoteNew.ini @@ -18,6 +18,9 @@ IR/Right = `Axis 115` IR/Forward = `Axis 116` IR/Backward = `Axis 117` IR/Hide = `Button 118` +IR/Height = 50 +IR/Width = 30 +IR/Center = 50 Swing/Up = `Axis 120` Swing/Down = `Axis 121` Swing/Left = `Axis 122` @@ -154,6 +157,9 @@ IR/Right = `Axis 115` IR/Forward = `Axis 116` IR/Backward = `Axis 117` IR/Hide = `Button 118` +IR/Height = 50 +IR/Width = 30 +IR/Center = 50 Swing/Up = `Axis 120` Swing/Down = `Axis 121` Swing/Left = `Axis 122` @@ -290,6 +296,9 @@ IR/Right = `Axis 115` IR/Forward = `Axis 116` IR/Backward = `Axis 117` IR/Hide = `Button 118` +IR/Height = 50 +IR/Width = 30 +IR/Center = 50 Swing/Up = `Axis 120` Swing/Down = `Axis 121` Swing/Left = `Axis 122` @@ -426,6 +435,9 @@ IR/Right = `Axis 115` IR/Forward = `Axis 116` IR/Backward = `Axis 117` IR/Hide = `Button 118` +IR/Height = 50 +IR/Width = 30 +IR/Center = 50 Swing/Up = `Axis 120` Swing/Down = `Axis 121` Swing/Left = `Axis 122` diff --git a/Source/Android/app/src/main/assets/WiimoteProfile.ini b/Source/Android/app/src/main/assets/WiimoteProfile.ini index 6c036c1a37..f31f68346c 100644 --- a/Source/Android/app/src/main/assets/WiimoteProfile.ini +++ b/Source/Android/app/src/main/assets/WiimoteProfile.ini @@ -18,6 +18,9 @@ IR/Right = `Axis 115` IR/Forward = `Axis 116` IR/Backward = `Axis 117` IR/Hide = `Button 118` +IR/Height = 50 +IR/Width = 30 +IR/Center = 50 Swing/Up = `Axis 120` Swing/Down = `Axis 121` Swing/Left = `Axis 122` From ec557eb3a2ffa331254a002da3be7b3081be92ce Mon Sep 17 00:00:00 2001 From: zackhow Date: Thu, 10 Jan 2019 21:18:16 -0500 Subject: [PATCH 6/8] Android: double tap screen to press button Added ingame option to select either wiimote A, B, 2 or Classic A --- .../activities/EmulationActivity.java | 45 ++++++++++++++++++- .../dolphinemu/overlay/InputOverlay.java | 18 +++++++- .../overlay/InputOverlayPointer.java | 42 ++++++++++++++++- .../src/main/res/menu/menu_emulation_wii.xml | 19 +++++--- .../app/src/main/res/values/arrays.xml | 13 ++++++ .../app/src/main/res/values/strings.xml | 2 + 6 files changed, 131 insertions(+), 8 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 012b11de7c..001676b900 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -2,6 +2,7 @@ package org.dolphinemu.dolphinemu.activities; import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; @@ -38,6 +39,8 @@ import org.dolphinemu.dolphinemu.fragments.MenuFragment; import org.dolphinemu.dolphinemu.fragments.SaveLoadStateFragment; import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.services.GameFileCacheService; +import org.dolphinemu.dolphinemu.overlay.InputOverlay; +import org.dolphinemu.dolphinemu.overlay.InputOverlayPointer; import org.dolphinemu.dolphinemu.ui.main.MainActivity; import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.ui.platform.Platform; @@ -93,7 +96,7 @@ public final class EmulationActivity extends AppCompatActivity MENU_ACTION_SAVE_SLOT6, MENU_ACTION_LOAD_SLOT1, MENU_ACTION_LOAD_SLOT2, MENU_ACTION_LOAD_SLOT3, MENU_ACTION_LOAD_SLOT4, MENU_ACTION_LOAD_SLOT5, MENU_ACTION_LOAD_SLOT6, MENU_ACTION_EXIT, MENU_ACTION_CHANGE_DISC, - MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_SENSITIVITY}) + MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_SENSITIVITY, MENU_ACTION_CHOOSE_DOUBLETAP}) public @interface MenuAction { } @@ -126,6 +129,7 @@ public final class EmulationActivity extends AppCompatActivity public static final int MENU_ACTION_RUMBLE = 25; public static final int MENU_ACTION_RESET_OVERLAY = 26; public static final int MENU_SET_IR_SENSITIVITY = 27; + public static final int MENU_ACTION_CHOOSE_DOUBLETAP = 28; private static SparseIntArray buttonsActionsMap = new SparseIntArray(); @@ -170,6 +174,8 @@ public final class EmulationActivity extends AppCompatActivity .append(R.id.menu_emulation_reset_overlay, EmulationActivity.MENU_ACTION_RESET_OVERLAY); buttonsActionsMap.append(R.id.menu_emulation_set_ir_sensitivity, EmulationActivity.MENU_SET_IR_SENSITIVITY); + buttonsActionsMap.append(R.id.menu_emulation_choose_doubletap, + EmulationActivity.MENU_ACTION_CHOOSE_DOUBLETAP); } private static String[] scanForSecondDisc(GameFile gameFile) @@ -591,6 +597,10 @@ public final class EmulationActivity extends AppCompatActivity setIRSensitivity(); return; + case MENU_ACTION_CHOOSE_DOUBLETAP: + chooseDoubleTapButton(); + return; + case MENU_ACTION_EXIT: // ATV menu is built using a fragment, this will pop that fragment before emulation ends. if (TvUtil.isLeanback(getApplicationContext())) @@ -721,6 +731,39 @@ public final class EmulationActivity extends AppCompatActivity alertDialog.show(); } + public void chooseDoubleTapButton() + { + final SharedPreferences.Editor editor = mPreferences.edit(); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + int currentController = + mPreferences.getInt("wiiController", InputOverlay.OVERLAY_WIIMOTE_NUNCHUCK); + + int currentValue = mPreferences.getInt("doubleTapButton", + InputOverlayPointer.DOUBLE_TAP_OPTIONS.get(InputOverlayPointer.DOUBLE_TAP_A)); + + int buttonList = currentController == InputOverlay.OVERLAY_WIIMOTE_CLASSIC ? + R.array.doubleTapWithClassic : R.array.doubleTap; + + if (currentController != InputOverlay.OVERLAY_WIIMOTE_CLASSIC && + currentValue == InputOverlay.OVERLAY_WIIMOTE_CLASSIC) + { + currentValue = InputOverlay.OVERLAY_WIIMOTE; + } + + builder.setSingleChoiceItems(buttonList, currentValue, (DialogInterface dialog, int which) -> + editor.putInt("doubleTapButton", InputOverlayPointer.DOUBLE_TAP_OPTIONS.get(which))); + + builder.setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> + { + editor.commit(); + mEmulationFragment.refreshInputOverlay(); + }); + + AlertDialog alertDialog = builder.create(); + alertDialog.show(); + } + private void adjustScale() { LayoutInflater inflater = LayoutInflater.from(this); 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 index e7ad7dbae7..86edc6b38a 100644 --- 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 @@ -40,6 +40,12 @@ import java.util.Set; */ 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_NUNCHUCK = 3; + public static final int OVERLAY_WIIMOTE_CLASSIC = 4; + private final Set overlayButtons = new HashSet<>(); private final Set overlayDpads = new HashSet<>(); private final Set overlayJoysticks = new HashSet<>(); @@ -666,7 +672,17 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener } if (!EmulationActivity.isGameCubeGame()) - overlayPointer = new InputOverlayPointer(this.getContext()); + { + int doubleTapButton = mPreferences.getInt("doubleTapButton", + InputOverlayPointer.DOUBLE_TAP_OPTIONS.get(InputOverlayPointer.DOUBLE_TAP_A)); + + if (mPreferences.getInt("wiiController", OVERLAY_WIIMOTE_NUNCHUCK) != + InputOverlay.OVERLAY_WIIMOTE_CLASSIC && + doubleTapButton == InputOverlayPointer.DOUBLE_TAP_CLASSIC_A) + doubleTapButton = InputOverlayPointer.DOUBLE_TAP_A; + + overlayPointer = new InputOverlayPointer(this.getContext(), doubleTapButton); + } invalidate(); } 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 index 1191d2dc7a..917a3f4436 100644 --- 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 @@ -2,22 +2,45 @@ package org.dolphinemu.dolphinemu.overlay; import android.app.Activity; import android.content.Context; +import android.os.Handler; import android.util.DisplayMetrics; import android.view.Display; import android.view.MotionEvent; +import org.dolphinemu.dolphinemu.NativeLibrary; + +import java.util.ArrayList; + public class InputOverlayPointer { + public static final int DOUBLE_TAP_A = 0; + public static final int DOUBLE_TAP_B = 1; + public static final int DOUBLE_TAP_2 = 2; + public static final int DOUBLE_TAP_CLASSIC_A = 3; + private final float[] axes = {0f, 0f}; private float maxHeight; private float maxWidth; + private boolean doubleTap = false; + private int doubleTapButton; private int trackId = -1; - public InputOverlayPointer(Context context) + 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(Context context, int button) { Display display = ((Activity) context).getWindowManager().getDefaultDisplay(); DisplayMetrics outMetrics = new DisplayMetrics(); display.getMetrics(outMetrics); + doubleTapButton = button; maxWidth = outMetrics.widthPixels / 2; maxHeight = outMetrics.heightPixels / 2; } @@ -31,6 +54,7 @@ public class InputOverlayPointer case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: trackId = event.getPointerId(pointerIndex); + touchPress(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: @@ -50,6 +74,22 @@ public class InputOverlayPointer return false; } + private void touchPress() + { + if (doubleTap) + { + NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, + doubleTapButton, NativeLibrary.ButtonState.PRESSED); + new Handler().postDelayed(() -> NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, + doubleTapButton, NativeLibrary.ButtonState.RELEASED), 50); + } + else + { + doubleTap = true; + new Handler().postDelayed(() -> doubleTap = false, 300); + } + } + public float[] getAxisValues() { float[] ir = {0f, 0f}; diff --git a/Source/Android/app/src/main/res/menu/menu_emulation_wii.xml b/Source/Android/app/src/main/res/menu/menu_emulation_wii.xml index 8a5a729783..465e582aff 100644 --- a/Source/Android/app/src/main/res/menu/menu_emulation_wii.xml +++ b/Source/Android/app/src/main/res/menu/menu_emulation_wii.xml @@ -112,12 +112,21 @@ - - + android:id="@+id/menu_emulation_ir_group" + android:title="@string/emulation_ir_group" + app:showAsAction="never"> + + + + + diff --git a/Source/Android/app/src/main/res/values/arrays.xml b/Source/Android/app/src/main/res/values/arrays.xml index 403e27b2b1..503788998a 100644 --- a/Source/Android/app/src/main/res/values/arrays.xml +++ b/Source/Android/app/src/main/res/values/arrays.xml @@ -306,6 +306,19 @@ Right Stick + + Button A + Button B + Button 2 + + + + Button A + Button B + Button 2 + Classic A + + Core Settings GFX Settings diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index a33db04ac8..0e13855779 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -298,7 +298,9 @@ You may have to reload the game after changing extensions. Swipe down from the top of the screen to access the menu. Reset Overlay + Touch IR Pointer IR Sensitivity + Double tap button Enable Vibration From e8739156e4dc54b904af036d26609e624c997fcb Mon Sep 17 00:00:00 2001 From: zackhow Date: Sat, 19 Jan 2019 22:49:04 -0500 Subject: [PATCH 7/8] Android: Normalize pointer touches based on rendered aspect ratio This allows the defaults to be actual defaults across devices with different screen sizes --- .../dolphinemu/dolphinemu/NativeLibrary.java | 15 +++++++ .../activities/EmulationActivity.java | 7 ++- .../fragments/EmulationFragment.java | 5 +++ .../dolphinemu/overlay/InputOverlay.java | 44 ++++++++++++------ .../overlay/InputOverlayPointer.java | 45 ++++++++++++++++--- Source/Android/jni/AndroidCommon/IDCache.cpp | 8 ++++ Source/Android/jni/AndroidCommon/IDCache.h | 1 + Source/Android/jni/MainAndroid.cpp | 12 +++++ 8 files changed, 117 insertions(+), 20 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 585506f419..442a4e8644 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -492,4 +492,19 @@ public final class NativeLibrary sEmulationActivity.clear(); } + + public static void updateTouchPointer() + { + final EmulationActivity emulationActivity = sEmulationActivity.get(); + if (emulationActivity == null) + { + Log.warning("[NativeLibrary] EmulationActivity is null."); + } + else + { + emulationActivity.runOnUiThread(emulationActivity::initInputPointer); + } + } + + public static native float GetGameAspectRatio(); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 001676b900..42a3f3d463 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -757,7 +757,7 @@ public final class EmulationActivity extends AppCompatActivity builder.setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> { editor.commit(); - mEmulationFragment.refreshInputOverlay(); + mEmulationFragment.initInputPointer(); }); AlertDialog alertDialog = builder.create(); @@ -1064,4 +1064,9 @@ public final class EmulationActivity extends AppCompatActivity { return mSettings; } + + public void initInputPointer() + { + mEmulationFragment.initInputPointer(); + } } 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 25b84a811a..f817414add 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 @@ -201,6 +201,11 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C mInputOverlay.refreshControls(); } + public void initInputPointer() + { + mInputOverlay.initTouchPointer(); + } + public void refreshInputOverlay() { mInputOverlay.refreshControls(); 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 index 86edc6b38a..c679838d3b 100644 --- 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 @@ -92,6 +92,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener mPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); if (!mPreferences.getBoolean("OverlayInitV2", false)) defaultOverlay(); + // Load the controls. refreshControls(); @@ -105,6 +106,27 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener requestFocus(); } + public void initTouchPointer() + { + // Refresh before starting the pointer + refreshControls(); + + if (!EmulationActivity.isGameCubeGame()) + { + int doubleTapButton = mPreferences.getInt("doubleTapButton", + InputOverlayPointer.DOUBLE_TAP_OPTIONS.get(InputOverlayPointer.DOUBLE_TAP_A)); + + if (mPreferences.getInt("wiiController", OVERLAY_WIIMOTE_NUNCHUCK) != + InputOverlay.OVERLAY_WIIMOTE_CLASSIC && + doubleTapButton == InputOverlayPointer.DOUBLE_TAP_CLASSIC_A) + { + doubleTapButton = InputOverlayPointer.DOUBLE_TAP_A; + } + + overlayPointer = new InputOverlayPointer(this.getContext(), doubleTapButton); + } + } + @Override public void draw(Canvas canvas) { @@ -201,15 +223,22 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener // Release the buttons first, then press for (int i = 0; i < dpadPressed.length; i++) + { if (!dpadPressed[i]) + { NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i), ButtonState.RELEASED); + } + } // Press buttons for (int i = 0; i < dpadPressed.length; i++) + { if (dpadPressed[i]) + { NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, dpad.getId(i), ButtonState.PRESSED); - + } + } setDpadState(dpad, dpadPressed[0], dpadPressed[1], dpadPressed[2], dpadPressed[3]); } break; @@ -671,19 +700,6 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener } } - if (!EmulationActivity.isGameCubeGame()) - { - int doubleTapButton = mPreferences.getInt("doubleTapButton", - InputOverlayPointer.DOUBLE_TAP_OPTIONS.get(InputOverlayPointer.DOUBLE_TAP_A)); - - if (mPreferences.getInt("wiiController", OVERLAY_WIIMOTE_NUNCHUCK) != - InputOverlay.OVERLAY_WIIMOTE_CLASSIC && - doubleTapButton == InputOverlayPointer.DOUBLE_TAP_CLASSIC_A) - doubleTapButton = InputOverlayPointer.DOUBLE_TAP_A; - - overlayPointer = new InputOverlayPointer(this.getContext(), doubleTapButton); - } - invalidate(); } 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 index 917a3f4436..492cf186eb 100644 --- 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 @@ -19,8 +19,11 @@ public class InputOverlayPointer public static final int DOUBLE_TAP_CLASSIC_A = 3; private final float[] axes = {0f, 0f}; + private float maxHeight; private float maxWidth; + private float aspectAdjusted; + private boolean xAdjusted; private boolean doubleTap = false; private int doubleTapButton; private int trackId = -1; @@ -41,8 +44,33 @@ public class InputOverlayPointer DisplayMetrics outMetrics = new DisplayMetrics(); display.getMetrics(outMetrics); doubleTapButton = button; - maxWidth = outMetrics.widthPixels / 2; - maxHeight = outMetrics.heightPixels / 2; + + Integer y = outMetrics.heightPixels; + Integer x = outMetrics.widthPixels; + + // Adjusting for device's black bars. + Float deviceAR = (float) x / y; + Float gameAR = NativeLibrary.GetGameAspectRatio(); + aspectAdjusted = gameAR / deviceAR; + + if (gameAR < deviceAR) // Black bars on left/right + { + xAdjusted = true; + Integer gameX = Math.round((float) y * gameAR); + Integer buffer = (x - gameX); + + maxWidth = (float) (x - buffer) / 2; + maxHeight = (float) y / 2; + } + else // Bars on top/bottom + { + xAdjusted = false; + Integer gameY = Math.round((float) x * gameAR); + Integer buffer = (y - gameY); + + maxWidth = (float) x / 2; + maxHeight = (float) (y - buffer) / 2; + } } public boolean onTouch(MotionEvent event) @@ -68,9 +96,16 @@ public class InputOverlayPointer int x = (int) event.getX(event.findPointerIndex(trackId)); int y = (int) event.getY(event.findPointerIndex(trackId)); - axes[0] = (y - maxHeight) / maxHeight; - axes[1] = (x - maxWidth) / maxWidth; - + if (xAdjusted) + { + axes[0] = (y - maxHeight) / maxHeight; + axes[1] = ((x * aspectAdjusted) - maxWidth) / maxWidth; + } + else + { + axes[0] = ((y * aspectAdjusted) - maxHeight) / maxHeight; + axes[1] = (x - maxWidth) / maxWidth; + } return false; } diff --git a/Source/Android/jni/AndroidCommon/IDCache.cpp b/Source/Android/jni/AndroidCommon/IDCache.cpp index 42a5632139..9841506fab 100644 --- a/Source/Android/jni/AndroidCommon/IDCache.cpp +++ b/Source/Android/jni/AndroidCommon/IDCache.cpp @@ -12,6 +12,7 @@ static JavaVM* s_java_vm; static jclass s_native_library_class; static jmethodID s_display_alert_msg; +static jmethodID s_get_update_touch_pointer; static jclass s_game_file_class; static jfieldID s_game_file_pointer; @@ -41,6 +42,11 @@ jmethodID GetDisplayAlertMsg() return s_display_alert_msg; } +jmethodID GetUpdateTouchPointer() +{ + return s_get_update_touch_pointer; +} + jclass GetAnalyticsClass() { return s_analytics_class; @@ -98,6 +104,8 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) s_native_library_class = reinterpret_cast(env->NewGlobalRef(native_library_class)); s_display_alert_msg = env->GetStaticMethodID(s_native_library_class, "displayAlertMsg", "(Ljava/lang/String;Ljava/lang/String;Z)Z"); + s_get_update_touch_pointer = + env->GetStaticMethodID(IDCache::GetNativeLibraryClass(), "updateTouchPointer", "()V"); const jclass game_file_class = env->FindClass("org/dolphinemu/dolphinemu/model/GameFile"); s_game_file_class = reinterpret_cast(env->NewGlobalRef(game_file_class)); diff --git a/Source/Android/jni/AndroidCommon/IDCache.h b/Source/Android/jni/AndroidCommon/IDCache.h index 5b302353ce..26262ac8d7 100644 --- a/Source/Android/jni/AndroidCommon/IDCache.h +++ b/Source/Android/jni/AndroidCommon/IDCache.h @@ -14,6 +14,7 @@ JavaVM* GetJavaVM(); jclass GetNativeLibraryClass(); jmethodID GetDisplayAlertMsg(); +jmethodID GetUpdateTouchPointer(); jclass GetAnalyticsClass(); jmethodID GetSendAnalyticsReport(); diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 8fe7c4942f..686053496e 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -107,6 +107,11 @@ void Host_UpdateMainFrame() void Host_RequestRenderWindowSize(int width, int height) { + // Update touch pointer + JNIEnv* env; + IDCache::GetJavaVM()->AttachCurrentThread(&env, nullptr); + env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetUpdateTouchPointer()); + IDCache::GetJavaVM()->DetachCurrentThread(); } bool Host_UINeedsControllerState() @@ -564,6 +569,13 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestr s_surf = nullptr; } } + +JNIEXPORT jfloat JNICALL +Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameAspectRatio(JNIEnv* env, jobject obj) +{ + return g_renderer->CalculateDrawAspectRatio(); +} + JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv* env, jobject obj) { From e15af5077f8c9605248a58e3172c8c1c45bd8589 Mon Sep 17 00:00:00 2001 From: zackhow Date: Sun, 20 Jan 2019 11:38:41 -0500 Subject: [PATCH 8/8] Android: don't init touch pointer when device doesn't have touch --- .../dolphinemu/dolphinemu/activities/EmulationActivity.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 42a3f3d463..cf75b127e0 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -1067,6 +1067,7 @@ public final class EmulationActivity extends AppCompatActivity public void initInputPointer() { - mEmulationFragment.initInputPointer(); + if (deviceHasTouchScreen()) + mEmulationFragment.initInputPointer(); } }