From 918b0fa302ba7668c81ecbda21025ff6612705ca Mon Sep 17 00:00:00 2001
From: Emmanuel Hansen <emmausssss@gmail.com>
Date: Thu, 20 Jul 2023 16:07:23 +0000
Subject: [PATCH] fix touch, add toggle for virtual gamepad

---
 .../org/ryujinx/android/GameController.kt     |  11 ++
 .../main/java/org/ryujinx/android/GameHost.kt |  20 --
 .../org/ryujinx/android/views/MainView.kt     | 179 +++++++++++++++++-
 3 files changed, 184 insertions(+), 26 deletions(-)

diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameController.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameController.kt
index 7323876c6..5cc1e20c3 100644
--- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameController.kt
+++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameController.kt
@@ -50,6 +50,14 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative =
     var leftGamePad: GamePad
     var rightGamePad: GamePad
     var controllerId: Int = -1
+    val isVisible : Boolean
+        get() {
+            controllerView?.apply {
+                return this.isVisible
+            }
+
+            return false;
+        }
 
     init {
         leftGamePad = GamePad(generateConfig(true), 16f, activity)
@@ -97,6 +105,9 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative =
     fun setVisible(isVisible: Boolean){
         controllerView?.apply {
             this.isVisible = isVisible
+
+            if(isVisible)
+                connect()
         }
     }
 
diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt
index 2c99d5f04..6cc28cc33 100644
--- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt
+++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/GameHost.kt
@@ -33,26 +33,6 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo
         holder.addCallback(this)
     }
 
-    override fun onTouchEvent(event: MotionEvent?): Boolean {
-        if (_isStarted)
-            return  when (event!!.actionMasked) {
-                MotionEvent.ACTION_MOVE -> {
-                    _nativeRyujinx.inputSetTouchPoint(event.x.roundToInt(), event.y.roundToInt())
-                    true
-                }
-                MotionEvent.ACTION_DOWN -> {
-                    _nativeRyujinx.inputSetTouchPoint(event.x.roundToInt(), event.y.roundToInt())
-                    true
-                }
-                MotionEvent.ACTION_UP -> {
-                    _nativeRyujinx.inputReleaseTouchPoint()
-                    true
-                }
-                else -> super.onTouchEvent(event)
-            }
-        return super.onTouchEvent(event)
-    }
-
     override fun surfaceCreated(holder: SurfaceHolder) {
     }
 
diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt
index faa2c9351..ed3487433 100644
--- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt
+++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/MainView.kt
@@ -1,17 +1,30 @@
 package org.ryujinx.android.views
 
+import androidx.compose.foundation.Image
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.StrokeJoin
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.input.pointer.PointerEventType
+import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.viewinterop.AndroidView
 import androidx.lifecycle.lifecycleScope
@@ -20,8 +33,10 @@ import androidx.navigation.compose.composable
 import androidx.navigation.compose.rememberNavController
 import org.ryujinx.android.GameController
 import org.ryujinx.android.GameHost
+import org.ryujinx.android.RyujinxNative
 import org.ryujinx.android.viewmodels.MainViewModel
 import org.ryujinx.android.viewmodels.SettingsViewModel
+import kotlin.math.roundToInt
 
 class MainView {
     companion object {
@@ -40,9 +55,8 @@ class MainView {
         @Composable
         fun GameView(mainViewModel: MainViewModel){
             Box(modifier = Modifier.fillMaxSize()) {
-                var controller = GameController(mainViewModel.activity)
-                Surface(color = Color.Green, modifier = Modifier.fillMaxSize()) {
-                    
+                val controller = remember {
+                    GameController(mainViewModel.activity)
                 }
                 AndroidView(
                     modifier = Modifier.fillMaxSize(),
@@ -50,11 +64,164 @@ class MainView {
                         GameHost(context, controller, mainViewModel)
                     }
                 )
-                GameStats(mainViewModel)
-                controller.Compose(mainViewModel.activity.lifecycleScope, mainViewModel.activity.lifecycle)
+                GameOverlay(mainViewModel, controller)
             }
         }
-        
+
+        @Composable
+        fun GameOverlay(mainViewModel: MainViewModel, controller: GameController){
+            Box(modifier = Modifier.fillMaxSize()) {
+                GameStats(mainViewModel)
+
+                var ryujinxNative = RyujinxNative()
+
+                // touch surface
+                Surface(color = Color.Transparent, modifier = Modifier
+                    .fillMaxSize()
+                    .padding(0.dp)
+                    .pointerInput(Unit) {
+                        awaitPointerEventScope {
+                            while (true) {
+                                Thread.sleep(2);
+                                val event = awaitPointerEvent()
+
+                                if(controller.isVisible)
+                                    continue
+
+                                var change = event
+                                    .component1()
+                                    .firstOrNull()
+                                change?.apply {
+                                    var position = this.position
+
+                                    if (event.type == PointerEventType.Press) {
+                                        ryujinxNative.inputSetTouchPoint(
+                                            position.x.roundToInt(),
+                                            position.y.roundToInt()
+                                        )
+                                    } else if (event.type == PointerEventType.Release) {
+                                        ryujinxNative.inputReleaseTouchPoint()
+
+                                    } else if (event.type == PointerEventType.Move) {
+                                        ryujinxNative.inputSetTouchPoint(
+                                            position.x.roundToInt(),
+                                            position.y.roundToInt()
+                                        )
+
+                                    }
+                                }
+                            }
+                        }
+                    }) {
+                }
+                controller.Compose(mainViewModel.activity.lifecycleScope, mainViewModel.activity.lifecycle)
+                Row(modifier = Modifier
+                    .align(Alignment.BottomCenter)
+                    .padding(8.dp)) {
+                    IconButton(modifier = Modifier.padding(4.dp),onClick = {
+                        controller.setVisible(!controller.isVisible)
+                    }) {
+                        Icon(imageVector = rememberVideogameAsset(), contentDescription = "Toggle Virtual Pad")
+                    }
+                }
+            }
+        }
+        @Composable
+        fun rememberVideogameAsset(): ImageVector {
+            var primaryColor = MaterialTheme.colorScheme.primary
+            return remember {
+                ImageVector.Builder(
+                    name = "videogame_asset",
+                    defaultWidth = 40.0.dp,
+                    defaultHeight = 40.0.dp,
+                    viewportWidth = 40.0f,
+                    viewportHeight = 40.0f
+                ).apply {
+                    path(
+                        fill = SolidColor(Color.Black.copy(alpha = 0.5f)),
+                        fillAlpha = 1f,
+                        stroke = SolidColor(primaryColor),
+                        strokeAlpha = 1f,
+                        strokeLineWidth = 1.0f,
+                        strokeLineCap = StrokeCap.Butt,
+                        strokeLineJoin = StrokeJoin.Miter,
+                        strokeLineMiter = 1f,
+                        pathFillType = PathFillType.NonZero
+                    ) {
+                        moveTo(6.25f, 29.792f)
+                        quadToRelative(-1.083f, 0f, -1.854f, -0.792f)
+                        quadToRelative(-0.771f, -0.792f, -0.771f, -1.833f)
+                        verticalLineTo(12.833f)
+                        quadToRelative(0f, -1.083f, 0.771f, -1.854f)
+                        quadToRelative(0.771f, -0.771f, 1.854f, -0.771f)
+                        horizontalLineToRelative(27.5f)
+                        quadToRelative(1.083f, 0f, 1.854f, 0.771f)
+                        quadToRelative(0.771f, 0.771f, 0.771f, 1.854f)
+                        verticalLineToRelative(14.334f)
+                        quadToRelative(0f, 1.041f, -0.771f, 1.833f)
+                        reflectiveQuadToRelative(-1.854f, 0.792f)
+                        close()
+                        moveToRelative(0f, -2.625f)
+                        horizontalLineToRelative(27.5f)
+                        verticalLineTo(12.833f)
+                        horizontalLineTo(6.25f)
+                        verticalLineToRelative(14.334f)
+                        close()
+                        moveToRelative(7.167f, -1.792f)
+                        quadToRelative(0.541f, 0f, 0.916f, -0.375f)
+                        reflectiveQuadToRelative(0.375f, -0.917f)
+                        verticalLineToRelative(-2.791f)
+                        horizontalLineToRelative(2.75f)
+                        quadToRelative(0.584f, 0f, 0.959f, -0.375f)
+                        reflectiveQuadToRelative(0.375f, -0.917f)
+                        quadToRelative(0f, -0.542f, -0.375f, -0.938f)
+                        quadToRelative(-0.375f, -0.395f, -0.959f, -0.395f)
+                        horizontalLineToRelative(-2.75f)
+                        verticalLineToRelative(-2.75f)
+                        quadToRelative(0f, -0.542f, -0.375f, -0.938f)
+                        quadToRelative(-0.375f, -0.396f, -0.916f, -0.396f)
+                        quadToRelative(-0.584f, 0f, -0.959f, 0.396f)
+                        reflectiveQuadToRelative(-0.375f, 0.938f)
+                        verticalLineToRelative(2.75f)
+                        horizontalLineToRelative(-2.75f)
+                        quadToRelative(-0.541f, 0f, -0.937f, 0.395f)
+                        quadTo(8f, 19.458f, 8f, 20f)
+                        quadToRelative(0f, 0.542f, 0.396f, 0.917f)
+                        reflectiveQuadToRelative(0.937f, 0.375f)
+                        horizontalLineToRelative(2.75f)
+                        verticalLineToRelative(2.791f)
+                        quadToRelative(0f, 0.542f, 0.396f, 0.917f)
+                        reflectiveQuadToRelative(0.938f, 0.375f)
+                        close()
+                        moveToRelative(11.125f, -0.5f)
+                        quadToRelative(0.791f, 0f, 1.396f, -0.583f)
+                        quadToRelative(0.604f, -0.584f, 0.604f, -1.375f)
+                        quadToRelative(0f, -0.834f, -0.604f, -1.417f)
+                        quadToRelative(-0.605f, -0.583f, -1.396f, -0.583f)
+                        quadToRelative(-0.834f, 0f, -1.417f, 0.583f)
+                        quadToRelative(-0.583f, 0.583f, -0.583f, 1.375f)
+                        quadToRelative(0f, 0.833f, 0.583f, 1.417f)
+                        quadToRelative(0.583f, 0.583f, 1.417f, 0.583f)
+                        close()
+                        moveToRelative(3.916f, -5.833f)
+                        quadToRelative(0.834f, 0f, 1.417f, -0.584f)
+                        quadToRelative(0.583f, -0.583f, 0.583f, -1.416f)
+                        quadToRelative(0f, -0.792f, -0.583f, -1.375f)
+                        quadToRelative(-0.583f, -0.584f, -1.417f, -0.584f)
+                        quadToRelative(-0.791f, 0f, -1.375f, 0.584f)
+                        quadToRelative(-0.583f, 0.583f, -0.583f, 1.375f)
+                        quadToRelative(0f, 0.833f, 0.583f, 1.416f)
+                        quadToRelative(0.584f, 0.584f, 1.375f, 0.584f)
+                        close()
+                        moveTo(6.25f, 27.167f)
+                        verticalLineTo(12.833f)
+                        verticalLineToRelative(14.334f)
+                        close()
+                    }
+                }.build()
+            }
+        }
+
         @Composable
         fun GameStats(mainViewModel: MainViewModel){
             var fifo = remember {