Ryujinx-ryubing/src/Ryujinx.Input.SDL3/SDL3MotionDriver.cs
2025-02-18 18:20:59 +03:00

86 lines
2.3 KiB
C#

using SDL3;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using static SDL3.SDL3;
namespace Ryujinx.Input.SDL3
{
public unsafe class SDL3MotionDriver : IHandheld, IDisposable
{
private readonly Dictionary<SDL_SensorType, SDL_Sensor> sensors;
private bool _disposed;
public SDL3MotionDriver()
{
int result = SDL_Init(SDL_InitFlags.Sensor);
if (result < 0)
{
throw new InvalidOperationException($"SDL sensor initialization failed: {SDL_GetError()}");
}
sensors = SDL_GetSensors().ToArray().ToDictionary(SDL_GetSensorTypeForID, SDL_OpenSensor);
}
~SDL3MotionDriver()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing && sensors != null)
{
foreach (var sensor in sensors.Values)
{
if (sensor != IntPtr.Zero)
{
SDL_CloseSensor(sensor);
}
}
}
_disposed = true;
}
public Vector3 GetMotionData(MotionInputId inputType)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return inputType switch
{
MotionInputId.Gyroscope => GetSensorVector(SDL_SensorType.Gyro) * 180 / MathF.PI,
MotionInputId.Accelerometer => GetSensorVector(SDL_SensorType.Accel) / SDL_STANDARD_GRAVITY,
_ => Vector3.Zero
};
}
private Vector3 GetSensorVector(SDL_SensorType sensorType)
{
if (!sensors.TryGetValue(sensorType, out SDL_Sensor sensor))
{
return Vector3.Zero;
}
var data = stackalloc float[3];
if (SDL_GetSensorData(sensor, data, 3) < 0)
{
return Vector3.Zero;
}
return new Vector3(data[0], data[1], data[2]);
}
}
}