forked from MeloNX/MeloNX
android - add motion support
This commit is contained in:
parent
5538227fce
commit
27059ded86
@ -553,6 +553,20 @@ namespace LibRyujinx
|
||||
SetButtonReleased((GamepadButtonInputId)(int)button, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetAccelerometerData")]
|
||||
public static void JniSetAccelerometerData(JEnvRef jEnv, JObjectLocalRef jObj, JFloat x, JFloat y, JFloat z, JInt id)
|
||||
{
|
||||
var accel = new Vector3(x, y, z);
|
||||
SetAccelerometerData(accel, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetGyroData")]
|
||||
public static void JniSetGyroData(JEnvRef jEnv, JObjectLocalRef jObj, JFloat x, JFloat y, JFloat z, JInt id)
|
||||
{
|
||||
var gryo = new Vector3(x, y, z);
|
||||
SetGryoData(gryo, id);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetStickAxis")]
|
||||
public static void JniSetStickAxis(JEnvRef jEnv, JObjectLocalRef jObj, JInt stick, JFloat x, JFloat y, JInt id)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
using DiscordRPC;
|
||||
using DiscordRPC;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
@ -83,6 +83,16 @@ namespace LibRyujinx
|
||||
_gamepadDriver?.SetButtonReleased(button, id);
|
||||
}
|
||||
|
||||
public static void SetAccelerometerData(Vector3 accel, int id)
|
||||
{
|
||||
_gamepadDriver?.SetAccelerometerData(accel, id);
|
||||
}
|
||||
|
||||
public static void SetGryoData(Vector3 gyro, int id)
|
||||
{
|
||||
_gamepadDriver?.SetGryoData(gyro, id);
|
||||
}
|
||||
|
||||
public static void SetStickAxis(StickInputId stick, Vector2 axes, int deviceId)
|
||||
{
|
||||
_gamepadDriver?.SetStickAxis(stick, axes, deviceId);
|
||||
@ -460,6 +470,22 @@ namespace LibRyujinx
|
||||
gamePad.ButtonInputs[(int)button] = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAccelerometerData(Vector3 accel, int deviceId)
|
||||
{
|
||||
if (_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||
{
|
||||
gamePad.Accelerometer = accel;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetGryoData(Vector3 gyro, int deviceId)
|
||||
{
|
||||
if (_gamePads.TryGetValue(deviceId, out var gamePad))
|
||||
{
|
||||
gamePad.Gyro = gyro;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class VirtualGamepad : IGamepad
|
||||
@ -481,7 +507,7 @@ namespace LibRyujinx
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public GamepadFeaturesFlag Features { get; }
|
||||
public GamepadFeaturesFlag Features { get; } = GamepadFeaturesFlag.Motion;
|
||||
public string Id { get; }
|
||||
|
||||
internal readonly int IdInt;
|
||||
@ -490,6 +516,8 @@ namespace LibRyujinx
|
||||
public bool IsConnected { get; }
|
||||
public Vector2[] StickInputs { get => _stickInputs; set => _stickInputs = value; }
|
||||
public bool[] ButtonInputs { get => _buttonInputs; set => _buttonInputs = value; }
|
||||
public Vector3 Accelerometer { get; internal set; }
|
||||
public Vector3 Gyro { get; internal set; }
|
||||
|
||||
public bool IsPressed(GamepadButtonInputId inputId)
|
||||
{
|
||||
@ -505,9 +533,18 @@ namespace LibRyujinx
|
||||
|
||||
public Vector3 GetMotionData(MotionInputId inputId)
|
||||
{
|
||||
if (inputId == MotionInputId.Accelerometer)
|
||||
return Accelerometer;
|
||||
else if (inputId == MotionInputId.Gyroscope)
|
||||
return RadToDegree(Gyro);
|
||||
return new Vector3();
|
||||
}
|
||||
|
||||
private static Vector3 RadToDegree(Vector3 rad)
|
||||
{
|
||||
return rad * (180 / MathF.PI);
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
//throw new System.NotImplementedException();
|
||||
|
@ -96,7 +96,8 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
||||
mainViewModel.controller?.connect()
|
||||
}
|
||||
|
||||
mainViewModel.physicalControllerManager?.connect()
|
||||
val id = mainViewModel.physicalControllerManager?.connect()
|
||||
mainViewModel.motionSensorManager?.setControllerId(id ?: -1)
|
||||
|
||||
_nativeRyujinx.graphicsRendererSetSize(
|
||||
surfaceHolder.surfaceFrame.width(),
|
||||
|
@ -28,6 +28,7 @@ import kotlin.math.abs
|
||||
class MainActivity : BaseActivity() {
|
||||
private var physicalControllerManager: PhysicalControllerManager =
|
||||
PhysicalControllerManager(this)
|
||||
private lateinit var motionSensorManager: MotionSensorManager
|
||||
private var _isInit: Boolean = false
|
||||
var isGameRunning = false
|
||||
var storageHelper: SimpleStorageHelper? = null
|
||||
@ -80,6 +81,8 @@ class MainActivity : BaseActivity() {
|
||||
}
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
motionSensorManager = MotionSensorManager(this)
|
||||
Thread.setDefaultUncaughtExceptionHandler(crashHandler)
|
||||
|
||||
if(
|
||||
@ -97,6 +100,7 @@ class MainActivity : BaseActivity() {
|
||||
|
||||
mainViewModel = MainViewModel(this)
|
||||
mainViewModel!!.physicalControllerManager = physicalControllerManager
|
||||
mainViewModel!!.motionSensorManager = motionSensorManager
|
||||
|
||||
mainViewModel?.apply {
|
||||
setContent {
|
||||
@ -194,6 +198,7 @@ class MainActivity : BaseActivity() {
|
||||
setFullScreen(true)
|
||||
NativeHelpers.instance.setTurboMode(true)
|
||||
force60HzRefreshRate(true)
|
||||
motionSensorManager.register()
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,5 +209,7 @@ class MainActivity : BaseActivity() {
|
||||
NativeHelpers.instance.setTurboMode(false)
|
||||
force60HzRefreshRate(false)
|
||||
}
|
||||
|
||||
motionSensorManager.unregister()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,111 @@
|
||||
package org.ryujinx.android
|
||||
|
||||
import android.app.Activity
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorEvent
|
||||
import android.hardware.SensorEventListener2
|
||||
import android.hardware.SensorManager
|
||||
import android.view.OrientationEventListener
|
||||
|
||||
class MotionSensorManager(val activity: MainActivity) : SensorEventListener2 {
|
||||
private var isRegistered: Boolean = false
|
||||
private var gyro: Sensor?
|
||||
private var accelerometer: Sensor?
|
||||
private var sensorManager: SensorManager =
|
||||
activity.getSystemService(Activity.SENSOR_SERVICE) as SensorManager
|
||||
private var controllerId: Int = -1
|
||||
|
||||
private val motionGyroOrientation : FloatArray = FloatArray(3)
|
||||
private val motionAcelOrientation : FloatArray = FloatArray(3)
|
||||
init {
|
||||
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
|
||||
gyro = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
|
||||
setOrientation90()
|
||||
var orientationListener = object : OrientationEventListener(activity){
|
||||
override fun onOrientationChanged(orientation: Int) {
|
||||
when{
|
||||
isWithinOrientationRange(orientation, 270) -> {
|
||||
setOrientation270()
|
||||
}
|
||||
isWithinOrientationRange(orientation, 90) -> {
|
||||
setOrientation90()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isWithinOrientationRange(
|
||||
currentOrientation : Int, targetOrientation : Int, epsilon : Int = 90
|
||||
) : Boolean {
|
||||
return currentOrientation > targetOrientation - epsilon
|
||||
&& currentOrientation < targetOrientation + epsilon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setOrientation270() {
|
||||
motionGyroOrientation[0] = -1.0f
|
||||
motionGyroOrientation[1] = 1.0f
|
||||
motionGyroOrientation[2] = 1.0f
|
||||
motionAcelOrientation[0] = 1.0f
|
||||
motionAcelOrientation[1] = -1.0f
|
||||
motionAcelOrientation[2] = -1.0f
|
||||
}
|
||||
fun setOrientation90() {
|
||||
motionGyroOrientation[0] = 1.0f
|
||||
motionGyroOrientation[1] = -1.0f
|
||||
motionGyroOrientation[2] = 1.0f
|
||||
motionAcelOrientation[0] = -1.0f
|
||||
motionAcelOrientation[1] = 1.0f
|
||||
motionAcelOrientation[2] = -1.0f
|
||||
}
|
||||
|
||||
fun setControllerId(id: Int){
|
||||
controllerId = id
|
||||
}
|
||||
|
||||
fun register(){
|
||||
if(isRegistered)
|
||||
return
|
||||
gyro?.apply {
|
||||
sensorManager.registerListener(this@MotionSensorManager, gyro, SensorManager.SENSOR_DELAY_GAME)
|
||||
}
|
||||
accelerometer?.apply {
|
||||
sensorManager.registerListener(this@MotionSensorManager, accelerometer, SensorManager.SENSOR_DELAY_GAME)
|
||||
}
|
||||
|
||||
isRegistered = true;
|
||||
}
|
||||
|
||||
fun unregister(){
|
||||
sensorManager.unregisterListener(this)
|
||||
isRegistered = false
|
||||
}
|
||||
|
||||
override fun onSensorChanged(event: SensorEvent?) {
|
||||
if (controllerId != -1)
|
||||
event?.apply {
|
||||
when (sensor.type) {
|
||||
Sensor.TYPE_ACCELEROMETER -> {
|
||||
val x = motionAcelOrientation[0] * event.values[1]
|
||||
val y = motionAcelOrientation[1] * event.values[0]
|
||||
val z = motionAcelOrientation[2] * event.values[2]
|
||||
|
||||
RyujinxNative.instance.inputSetAccelerometerData(x, y, z, controllerId)
|
||||
}
|
||||
|
||||
Sensor.TYPE_GYROSCOPE -> {
|
||||
val x = motionGyroOrientation[0] * event.values[1]
|
||||
val y = motionGyroOrientation[1] * event.values[0]
|
||||
val z = motionGyroOrientation[2] * event.values[2]
|
||||
RyujinxNative.instance.inputSetGyroData(x, y, z, controllerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
|
||||
}
|
||||
|
||||
override fun onFlushCompleted(sensor: Sensor?) {
|
||||
}
|
||||
}
|
@ -41,8 +41,13 @@ class PhysicalControllerManager(val activity: MainActivity) {
|
||||
}
|
||||
}
|
||||
|
||||
fun connect(){
|
||||
fun connect() : Int {
|
||||
controllerId = ryujinxNative.inputConnectGamepad(0)
|
||||
return controllerId
|
||||
}
|
||||
|
||||
fun disconnect(){
|
||||
controllerId = -1
|
||||
}
|
||||
|
||||
private fun getGamePadButtonInputId(keycode: Int): GamePadButtonInputId {
|
||||
|
@ -49,6 +49,8 @@ class RyujinxNative {
|
||||
external fun inputSetButtonReleased(button: Int, id: Int)
|
||||
external fun inputConnectGamepad(index: Int): Int
|
||||
external fun inputSetStickAxis(stick: Int, x: Float, y: Float, id: Int)
|
||||
external fun inputSetAccelerometerData(x: Float, y: Float, z: Float, id: Int)
|
||||
external fun inputSetGyroData(x: Float, y: Float, z: Float, id: Int)
|
||||
external fun graphicsSetSurface(surface: Long, window: Long)
|
||||
external fun deviceCloseEmulation()
|
||||
external fun deviceSignalEmulationClose()
|
||||
|
@ -14,6 +14,7 @@ import org.ryujinx.android.GameHost
|
||||
import org.ryujinx.android.GraphicsConfiguration
|
||||
import org.ryujinx.android.Logging
|
||||
import org.ryujinx.android.MainActivity
|
||||
import org.ryujinx.android.MotionSensorManager
|
||||
import org.ryujinx.android.NativeGraphicsInterop
|
||||
import org.ryujinx.android.NativeHelpers
|
||||
import org.ryujinx.android.PerformanceManager
|
||||
@ -26,6 +27,7 @@ import java.io.File
|
||||
@SuppressLint("WrongConstant")
|
||||
class MainViewModel(val activity: MainActivity) {
|
||||
var physicalControllerManager: PhysicalControllerManager? = null
|
||||
var motionSensorManager: MotionSensorManager? = null
|
||||
var gameModel: GameModel? = null
|
||||
var controller: GameController? = null
|
||||
var performanceManager: PerformanceManager? = null
|
||||
@ -62,6 +64,9 @@ class MainViewModel(val activity: MainActivity) {
|
||||
RyujinxNative.instance.deviceSignalEmulationClose()
|
||||
gameHost?.close()
|
||||
RyujinxNative.instance.deviceCloseEmulation()
|
||||
motionSensorManager?.unregister()
|
||||
physicalControllerManager?.disconnect()
|
||||
motionSensorManager?.setControllerId(-1)
|
||||
}
|
||||
|
||||
fun loadGame(game:GameModel) : Boolean {
|
||||
@ -354,6 +359,7 @@ class MainViewModel(val activity: MainActivity) {
|
||||
activity.setFullScreen(true)
|
||||
navController?.navigate("game")
|
||||
activity.isGameRunning = true
|
||||
motionSensorManager?.register()
|
||||
}
|
||||
|
||||
fun setProgressStates(
|
||||
|
Loading…
x
Reference in New Issue
Block a user