From e8739156e4dc54b904af036d26609e624c997fcb Mon Sep 17 00:00:00 2001 From: zackhow Date: Sat, 19 Jan 2019 22:49:04 -0500 Subject: [PATCH] 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) {