11package io.github.kitswas.virtualgamepadmobile.ui.screens
22
33import android.annotation.SuppressLint
4- import android.content.Context
54import android.content.res.Configuration
6- import android.hardware.Sensor
7- import android.hardware.SensorEvent
8- import android.hardware.SensorEventListener
9- import android.hardware.SensorManager
105import android.util.Log
11- import android.view.Surface
126import android.widget.Toast
137import androidx.compose.runtime.Composable
14- import androidx.compose.runtime.DisposableEffect
158import androidx.compose.runtime.LaunchedEffect
169import androidx.compose.runtime.collectAsState
1710import androidx.compose.runtime.getValue
@@ -37,26 +30,14 @@ import io.github.kitswas.virtualgamepadmobile.data.defaultMotionStickControl
3730import io.github.kitswas.virtualgamepadmobile.data.defaultPollingDelay
3831import io.github.kitswas.virtualgamepadmobile.network.ConnectionViewModel
3932import io.github.kitswas.virtualgamepadmobile.ui.composables.DrawGamepad
33+ import io.github.kitswas.virtualgamepadmobile.ui.utils.BindMotionStickControl
4034import io.github.kitswas.virtualgamepadmobile.ui.utils.findActivity
4135import kotlinx.coroutines.CoroutineScope
4236import kotlinx.coroutines.Dispatchers
4337import kotlinx.coroutines.delay
4438import kotlinx.coroutines.launch
45- import kotlin.math.PI
4639
4740private const val tag = " GamePadScreen"
48- private const val maxTiltDegrees = 30f
49- private const val gravityAlpha = 0.8f
50-
51- private fun toStickValue (angleRad : Float , sensitivity : Float ): Float {
52- val maxTiltRadians = (maxTiltDegrees / 180f * PI ).toFloat()
53- return (angleRad / maxTiltRadians * sensitivity).coerceIn(- 1f , 1f )
54- }
55-
56- private fun toStickValueFromGravity (gravityComponent : Float , sensitivity : Float ): Float {
57- val normalized = (gravityComponent / SensorManager .GRAVITY_EARTH ).coerceIn(- 1f , 1f )
58- return (normalized * sensitivity).coerceIn(- 1f , 1f )
59- }
6041
6142@SuppressLint(" ConfigurationScreenWidthHeight" )
6243@Composable
@@ -96,117 +77,13 @@ fun GamePad(
9677 motionStickY = motionStickY.value,
9778 )
9879
99- val sensorManager = remember {
100- context.getSystemService(Context .SENSOR_SERVICE ) as SensorManager
101- }
102- val motionSensor = remember {
103- sensorManager.getDefaultSensor(Sensor .TYPE_GAME_ROTATION_VECTOR )
104- ? : sensorManager.getDefaultSensor(Sensor .TYPE_ROTATION_VECTOR )
105- ? : sensorManager.getDefaultSensor(Sensor .TYPE_ACCELEROMETER )
106- }
107- val displayRotation =
108- LocalContext .current.findActivity()?.display?.rotation ? : Surface .ROTATION_0
109-
110- DisposableEffect (motionStickControl, motionSensitivity, motionSensor, displayRotation) {
111- if (motionStickControl == MotionStickControl .OFF || motionSensor == null ) {
112- motionStickX.value = 0f
113- motionStickY.value = 0f
114- if (motionStickControl == MotionStickControl .LEFT ) {
115- gamepadState.LeftThumbstickX = 0f
116- gamepadState.LeftThumbstickY = 0f
117- }
118- if (motionStickControl == MotionStickControl .RIGHT ) {
119- gamepadState.RightThumbstickX = 0f
120- gamepadState.RightThumbstickY = 0f
121- }
122- return @DisposableEffect onDispose { }
123- }
124-
125- val rotationMatrix = FloatArray (9 )
126- val remappedRotationMatrix = FloatArray (9 )
127- val orientation = FloatArray (3 )
128- val gravity = FloatArray (3 )
129-
130- val axisConfig = when (displayRotation) {
131- Surface .ROTATION_90 -> SensorManager .AXIS_Z to SensorManager .AXIS_MINUS_X
132- Surface .ROTATION_180 -> SensorManager .AXIS_MINUS_X to SensorManager .AXIS_MINUS_Z
133- Surface .ROTATION_270 -> SensorManager .AXIS_MINUS_Z to SensorManager .AXIS_X
134- else -> SensorManager .AXIS_X to SensorManager .AXIS_Z
135- }
136-
137- fun applyStickValues (stickX : Float , stickY : Float ) {
138- motionStickX.value = stickX
139- motionStickY.value = stickY
140- when (motionStickControl) {
141- MotionStickControl .LEFT -> {
142- gamepadState.LeftThumbstickX = stickX
143- gamepadState.LeftThumbstickY = stickY
144- }
145-
146- MotionStickControl .RIGHT -> {
147- gamepadState.RightThumbstickX = stickX
148- gamepadState.RightThumbstickY = stickY
149- }
150-
151- MotionStickControl .OFF -> Unit
152- }
153- }
154-
155- val listener = object : SensorEventListener {
156- override fun onSensorChanged (event : SensorEvent ) {
157- if (event.sensor.type == Sensor .TYPE_ACCELEROMETER ) {
158- gravity[0 ] = gravityAlpha * gravity[0 ] + (1f - gravityAlpha) * event.values[0 ]
159- gravity[1 ] = gravityAlpha * gravity[1 ] + (1f - gravityAlpha) * event.values[1 ]
160-
161- val (rawX, rawY) = when (displayRotation) {
162- Surface .ROTATION_90 -> gravity[1 ] to gravity[0 ]
163- Surface .ROTATION_180 -> gravity[0 ] to - gravity[1 ]
164- Surface .ROTATION_270 -> - gravity[1 ] to - gravity[0 ]
165- else -> - gravity[0 ] to gravity[1 ]
166- }
167- applyStickValues(
168- stickX = toStickValueFromGravity(rawX, motionSensitivity),
169- stickY = toStickValueFromGravity(rawY, motionSensitivity),
170- )
171- return
172- }
173-
174- SensorManager .getRotationMatrixFromVector(rotationMatrix, event.values)
175- SensorManager .remapCoordinateSystem(
176- rotationMatrix,
177- axisConfig.first,
178- axisConfig.second,
179- remappedRotationMatrix,
180- )
181- SensorManager .getOrientation(remappedRotationMatrix, orientation)
182-
183- val pitch = orientation[1 ]
184- val roll = orientation[2 ]
185- applyStickValues(
186- stickX = toStickValue(- roll, motionSensitivity),
187- stickY = toStickValue(pitch, motionSensitivity),
188- )
189- }
190-
191- override fun onAccuracyChanged (sensor : Sensor ? , accuracy : Int ) = Unit
192- }
193-
194- sensorManager.registerListener(listener, motionSensor, SensorManager .SENSOR_DELAY_GAME )
195-
196- onDispose {
197- sensorManager.unregisterListener(listener)
198- motionStickX.value = 0f
199- motionStickY.value = 0f
200- if (motionStickControl == MotionStickControl .LEFT ) {
201- gamepadState.LeftThumbstickX = 0f
202- gamepadState.LeftThumbstickY = 0f
203- }
204- if (motionStickControl == MotionStickControl .RIGHT ) {
205- gamepadState.RightThumbstickX = 0f
206- gamepadState.RightThumbstickY = 0f
207- }
208- }
209- }
80+ BindMotionStickControl (
81+ gamepadState = gamepadState,
82+ motionStickControl = motionStickControl,
83+ motionSensitivity = motionSensitivity,
84+ motionStickX = motionStickX,
85+ motionStickY = motionStickY,
86+ )
21087
21188 val activity = LocalContext .current.findActivity()
21289 // disconnect on back press
0 commit comments