forked from MeloNX/MeloNX
android - add motion support
This commit is contained in:
parent
521403b0ea
commit
60f320bc07
@ -553,6 +553,20 @@ namespace LibRyujinx
|
|||||||
SetButtonReleased((GamepadButtonInputId)(int)button, id);
|
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")]
|
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetStickAxis")]
|
||||||
public static void JniSetStickAxis(JEnvRef jEnv, JObjectLocalRef jObj, JInt stick, JFloat x, JFloat y, JInt id)
|
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;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
@ -83,6 +83,16 @@ namespace LibRyujinx
|
|||||||
_gamepadDriver?.SetButtonReleased(button, id);
|
_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)
|
public static void SetStickAxis(StickInputId stick, Vector2 axes, int deviceId)
|
||||||
{
|
{
|
||||||
_gamepadDriver?.SetStickAxis(stick, axes, deviceId);
|
_gamepadDriver?.SetStickAxis(stick, axes, deviceId);
|
||||||
@ -460,6 +470,22 @@ namespace LibRyujinx
|
|||||||
gamePad.ButtonInputs[(int)button] = false;
|
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
|
public class VirtualGamepad : IGamepad
|
||||||
@ -481,7 +507,7 @@ namespace LibRyujinx
|
|||||||
|
|
||||||
public void Dispose() { }
|
public void Dispose() { }
|
||||||
|
|
||||||
public GamepadFeaturesFlag Features { get; }
|
public GamepadFeaturesFlag Features { get; } = GamepadFeaturesFlag.Motion;
|
||||||
public string Id { get; }
|
public string Id { get; }
|
||||||
|
|
||||||
internal readonly int IdInt;
|
internal readonly int IdInt;
|
||||||
@ -490,6 +516,8 @@ namespace LibRyujinx
|
|||||||
public bool IsConnected { get; }
|
public bool IsConnected { get; }
|
||||||
public Vector2[] StickInputs { get => _stickInputs; set => _stickInputs = value; }
|
public Vector2[] StickInputs { get => _stickInputs; set => _stickInputs = value; }
|
||||||
public bool[] ButtonInputs { get => _buttonInputs; set => _buttonInputs = 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)
|
public bool IsPressed(GamepadButtonInputId inputId)
|
||||||
{
|
{
|
||||||
@ -505,9 +533,18 @@ namespace LibRyujinx
|
|||||||
|
|
||||||
public Vector3 GetMotionData(MotionInputId inputId)
|
public Vector3 GetMotionData(MotionInputId inputId)
|
||||||
{
|
{
|
||||||
|
if (inputId == MotionInputId.Accelerometer)
|
||||||
|
return Accelerometer;
|
||||||
|
else if (inputId == MotionInputId.Gyroscope)
|
||||||
|
return RadToDegree(Gyro);
|
||||||
return new Vector3();
|
return new Vector3();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Vector3 RadToDegree(Vector3 rad)
|
||||||
|
{
|
||||||
|
return rad * (180 / MathF.PI);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetTriggerThreshold(float triggerThreshold)
|
public void SetTriggerThreshold(float triggerThreshold)
|
||||||
{
|
{
|
||||||
//throw new System.NotImplementedException();
|
//throw new System.NotImplementedException();
|
||||||
|
@ -96,7 +96,8 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
|||||||
mainViewModel.controller?.connect()
|
mainViewModel.controller?.connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
mainViewModel.physicalControllerManager?.connect()
|
val id = mainViewModel.physicalControllerManager?.connect()
|
||||||
|
mainViewModel.motionSensorManager?.setControllerId(id ?: -1)
|
||||||
|
|
||||||
_nativeRyujinx.graphicsRendererSetSize(
|
_nativeRyujinx.graphicsRendererSetSize(
|
||||||
surfaceHolder.surfaceFrame.width(),
|
surfaceHolder.surfaceFrame.width(),
|
||||||
|
@ -28,6 +28,7 @@ import kotlin.math.abs
|
|||||||
class MainActivity : BaseActivity() {
|
class MainActivity : BaseActivity() {
|
||||||
private var physicalControllerManager: PhysicalControllerManager =
|
private var physicalControllerManager: PhysicalControllerManager =
|
||||||
PhysicalControllerManager(this)
|
PhysicalControllerManager(this)
|
||||||
|
private lateinit var motionSensorManager: MotionSensorManager
|
||||||
private var _isInit: Boolean = false
|
private var _isInit: Boolean = false
|
||||||
var isGameRunning = false
|
var isGameRunning = false
|
||||||
var storageHelper: SimpleStorageHelper? = null
|
var storageHelper: SimpleStorageHelper? = null
|
||||||
@ -80,6 +81,8 @@ class MainActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
motionSensorManager = MotionSensorManager(this)
|
||||||
Thread.setDefaultUncaughtExceptionHandler(crashHandler)
|
Thread.setDefaultUncaughtExceptionHandler(crashHandler)
|
||||||
|
|
||||||
if(
|
if(
|
||||||
@ -97,6 +100,7 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
mainViewModel = MainViewModel(this)
|
mainViewModel = MainViewModel(this)
|
||||||
mainViewModel!!.physicalControllerManager = physicalControllerManager
|
mainViewModel!!.physicalControllerManager = physicalControllerManager
|
||||||
|
mainViewModel!!.motionSensorManager = motionSensorManager
|
||||||
|
|
||||||
mainViewModel?.apply {
|
mainViewModel?.apply {
|
||||||
setContent {
|
setContent {
|
||||||
@ -194,6 +198,7 @@ class MainActivity : BaseActivity() {
|
|||||||
setFullScreen(true)
|
setFullScreen(true)
|
||||||
NativeHelpers.instance.setTurboMode(true)
|
NativeHelpers.instance.setTurboMode(true)
|
||||||
force60HzRefreshRate(true)
|
force60HzRefreshRate(true)
|
||||||
|
motionSensorManager.register()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,5 +209,7 @@ class MainActivity : BaseActivity() {
|
|||||||
NativeHelpers.instance.setTurboMode(false)
|
NativeHelpers.instance.setTurboMode(false)
|
||||||
force60HzRefreshRate(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)
|
controllerId = ryujinxNative.inputConnectGamepad(0)
|
||||||
|
return controllerId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disconnect(){
|
||||||
|
controllerId = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGamePadButtonInputId(keycode: Int): GamePadButtonInputId {
|
private fun getGamePadButtonInputId(keycode: Int): GamePadButtonInputId {
|
||||||
|
@ -49,6 +49,8 @@ class RyujinxNative {
|
|||||||
external fun inputSetButtonReleased(button: Int, id: Int)
|
external fun inputSetButtonReleased(button: Int, id: Int)
|
||||||
external fun inputConnectGamepad(index: Int): Int
|
external fun inputConnectGamepad(index: Int): Int
|
||||||
external fun inputSetStickAxis(stick: Int, x: Float, y: Float, id: 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 graphicsSetSurface(surface: Long, window: Long)
|
||||||
external fun deviceCloseEmulation()
|
external fun deviceCloseEmulation()
|
||||||
external fun deviceSignalEmulationClose()
|
external fun deviceSignalEmulationClose()
|
||||||
|
@ -14,6 +14,7 @@ import org.ryujinx.android.GameHost
|
|||||||
import org.ryujinx.android.GraphicsConfiguration
|
import org.ryujinx.android.GraphicsConfiguration
|
||||||
import org.ryujinx.android.Logging
|
import org.ryujinx.android.Logging
|
||||||
import org.ryujinx.android.MainActivity
|
import org.ryujinx.android.MainActivity
|
||||||
|
import org.ryujinx.android.MotionSensorManager
|
||||||
import org.ryujinx.android.NativeGraphicsInterop
|
import org.ryujinx.android.NativeGraphicsInterop
|
||||||
import org.ryujinx.android.NativeHelpers
|
import org.ryujinx.android.NativeHelpers
|
||||||
import org.ryujinx.android.PerformanceManager
|
import org.ryujinx.android.PerformanceManager
|
||||||
@ -26,6 +27,7 @@ import java.io.File
|
|||||||
@SuppressLint("WrongConstant")
|
@SuppressLint("WrongConstant")
|
||||||
class MainViewModel(val activity: MainActivity) {
|
class MainViewModel(val activity: MainActivity) {
|
||||||
var physicalControllerManager: PhysicalControllerManager? = null
|
var physicalControllerManager: PhysicalControllerManager? = null
|
||||||
|
var motionSensorManager: MotionSensorManager? = null
|
||||||
var gameModel: GameModel? = null
|
var gameModel: GameModel? = null
|
||||||
var controller: GameController? = null
|
var controller: GameController? = null
|
||||||
var performanceManager: PerformanceManager? = null
|
var performanceManager: PerformanceManager? = null
|
||||||
@ -62,6 +64,9 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
RyujinxNative.instance.deviceSignalEmulationClose()
|
RyujinxNative.instance.deviceSignalEmulationClose()
|
||||||
gameHost?.close()
|
gameHost?.close()
|
||||||
RyujinxNative.instance.deviceCloseEmulation()
|
RyujinxNative.instance.deviceCloseEmulation()
|
||||||
|
motionSensorManager?.unregister()
|
||||||
|
physicalControllerManager?.disconnect()
|
||||||
|
motionSensorManager?.setControllerId(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadGame(game:GameModel) : Boolean {
|
fun loadGame(game:GameModel) : Boolean {
|
||||||
@ -354,6 +359,7 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
activity.setFullScreen(true)
|
activity.setFullScreen(true)
|
||||||
navController?.navigate("game")
|
navController?.navigate("game")
|
||||||
activity.isGameRunning = true
|
activity.isGameRunning = true
|
||||||
|
motionSensorManager?.register()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setProgressStates(
|
fun setProgressStates(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user