diff --git a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt index eec388463..e53354dc9 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt @@ -96,6 +96,24 @@ object NativeLibrary { */ external fun onTouchMoved(xAxis: Float, yAxis: Float) + /** + * Handles touch events on the secondary display. + * + * @param xAxis The value of the x-axis. + * @param yAxis The value of the y-axis. + * @param pressed To identify if the touch held down or released. + * @return true if the pointer is within the touchscreen + */ + external fun onSecondaryTouchEvent(xAxis: Float, yAxis: Float, pressed: Boolean): Boolean + + /** + * Handles touch movement on the secondary display. + * + * @param xAxis The value of the instantaneous x-axis. + * @param yAxis The value of the instantaneous y-axis. + */ + external fun onSecondaryTouchMoved(xAxis: Float, yAxis: Float) + external fun reloadSettings() external fun getTitleId(filename: String): Long diff --git a/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt b/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt index 709bb222e..e0594a7e5 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt @@ -11,11 +11,14 @@ import android.hardware.display.DisplayManager import android.hardware.display.VirtualDisplay import android.os.Bundle import android.view.Display +import android.view.MotionEvent import android.view.Surface import android.view.SurfaceHolder import android.view.SurfaceView -import org.citra.citra_emu.NativeLibrary +import android.view.WindowManager import org.citra.citra_emu.features.settings.model.IntSetting +import org.citra.citra_emu.display.SecondaryDisplayLayout +import org.citra.citra_emu.NativeLibrary class SecondaryDisplay(val context: Context) { private var pres: SecondaryDisplayPresentation? = null @@ -41,16 +44,23 @@ class SecondaryDisplay(val context: Context) { NativeLibrary.secondarySurfaceDestroyed() } + private fun getExternalDisplay(context: Context): Display? { + val dm = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager + val internalId = context.display.displayId ?: Display.DEFAULT_DISPLAY + val displays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION) + return displays.firstOrNull { it.displayId != internalId && it.name != "HiddenDisplay" } + } + fun updateDisplay() { // decide if we are going to the external display or the internal one - var display = getCustomerDisplay() + var display = getExternalDisplay(context) if (display == null || IntSetting.SECONDARY_DISPLAY_LAYOUT.int == SecondaryDisplayLayout.NONE.int) { display = vd.display } // if our presentation is already on the right display, ignore - if (pres?.display == display) return; + if (pres?.display == display) return // otherwise, make a new presentation releasePresentation() @@ -58,13 +68,6 @@ class SecondaryDisplay(val context: Context) { pres?.show() } - private fun getCustomerDisplay(): Display? { - val displays = displayManager.displays - // code taken from MelonDS dual screen - should fix odin 2 detection bug - return displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION) - .firstOrNull { it.displayId != Display.DEFAULT_DISPLAY && it.name != "Built-in Screen" && it.name != "HiddenDisplay"} - } - fun releasePresentation() { pres?.dismiss() pres = null @@ -78,9 +81,16 @@ class SecondaryDisplayPresentation( context: Context, display: Display, val parent: SecondaryDisplay ) : Presentation(context, display) { private lateinit var surfaceView: SurfaceView + private var touchscreenPointerId = -1 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + window?.setFlags( + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + ) // Initialize SurfaceView surfaceView = SurfaceView(context) @@ -100,6 +110,42 @@ class SecondaryDisplayPresentation( } }) + this.surfaceView.setOnTouchListener { _, event -> + + val pointerIndex = event.actionIndex + val pointerId = event.getPointerId(pointerIndex) + when (event.actionMasked) { + MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> { + if (touchscreenPointerId == -1) { + touchscreenPointerId = pointerId + NativeLibrary.onSecondaryTouchEvent( + event.getX(pointerIndex), + event.getY(pointerIndex), + true + ) + } + } + + MotionEvent.ACTION_MOVE -> { + val index = event.findPointerIndex(touchscreenPointerId) + if (index != -1) { + NativeLibrary.onSecondaryTouchMoved( + event.getX(index), + event.getY(index) + ) + } + } + + MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_CANCEL -> { + if (pointerId == touchscreenPointerId) { + NativeLibrary.onSecondaryTouchEvent(0f, 0f, false) + touchscreenPointerId = -1 + } + } + } + true + } + setContentView(surfaceView) // Set SurfaceView as content } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt index 9828dd046..f7519bb81 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt @@ -153,8 +153,7 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex if (isActionMove) { NativeLibrary.onTouchMoved(xPosition.toFloat(), yPosition.toFloat()) continue - } - else if (isActionUp) { + } else if (isActionUp) { NativeLibrary.onTouchEvent(0f, 0f, false) break // Up and down actions shouldn't loop } diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 2cb34cbd0..a2880d6dc 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -657,6 +657,25 @@ void Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEn window->OnTouchMoved((int)x, (int)y); } +jboolean Java_org_citra_citra_1emu_NativeLibrary_onSecondaryTouchEvent([[maybe_unused]] JNIEnv* env, + [[maybe_unused]] jobject obj, + jfloat x, jfloat y, + jboolean pressed) { + if (!secondary_window) { + return JNI_FALSE; + } + return static_cast(secondary_window->OnTouchEvent( + static_cast(x + 0.5), static_cast(y + 0.5), pressed)); +} + +void Java_org_citra_citra_1emu_NativeLibrary_onSecondaryTouchMoved([[maybe_unused]] JNIEnv* env, + [[maybe_unused]] jobject obj, + jfloat x, jfloat y) { + if (secondary_window) { + secondary_window->OnTouchMoved((int)x, (int)y); + } +} + jlong Java_org_citra_citra_1emu_NativeLibrary_getTitleId(JNIEnv* env, [[maybe_unused]] jobject obj, jstring j_filename) { std::string filepath = GetJString(env, j_filename); diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index c352dbdf0..ee81b177e 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -66,6 +66,10 @@ bool EmuWindow::IsWithinTouchscreen(const Layout::FramebufferLayout& layout, uns } #endif + if (!layout.bottom_screen_enabled) { + return false; + } + Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue(); if (render_3d_mode == Settings::StereoRenderOption::SideBySide ||