261 lines
8.6 KiB
C#
261 lines
8.6 KiB
C#
using Ryujinx.Ava.UI.ViewModels;
|
|
using Ryujinx.Ava.UI.ViewModels.Input;
|
|
using Ryujinx.Input;
|
|
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Ryujinx.Ava.UI.Models.Input
|
|
{
|
|
public class StickVisualizer : BaseModel, IDisposable
|
|
{
|
|
public const int DrawStickPollRate = 50; // Milliseconds per poll.
|
|
public const int DrawStickCircumference = 5;
|
|
public const float DrawStickScaleFactor = DrawStickCanvasCenter;
|
|
public const int DrawStickCanvasSize = 100;
|
|
public const int DrawStickBorderSize = DrawStickCanvasSize + 5;
|
|
public const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2;
|
|
public const float MaxVectorLength = DrawStickCanvasSize / 2;
|
|
|
|
public CancellationTokenSource PollTokenSource;
|
|
public CancellationToken PollToken;
|
|
|
|
private static float _vectorLength;
|
|
private static float _vectorMultiplier;
|
|
|
|
private bool disposedValue;
|
|
|
|
private DeviceType _type;
|
|
public DeviceType Type
|
|
{
|
|
get => _type;
|
|
set
|
|
{
|
|
_type = value;
|
|
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
|
|
private GamepadInputConfig _gamepadConfig;
|
|
public GamepadInputConfig GamepadConfig
|
|
{
|
|
get => _gamepadConfig;
|
|
set
|
|
{
|
|
_gamepadConfig = value;
|
|
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
|
|
private KeyboardInputConfig _keyboardConfig;
|
|
public KeyboardInputConfig KeyboardConfig
|
|
{
|
|
get => _keyboardConfig;
|
|
set
|
|
{
|
|
_keyboardConfig = value;
|
|
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
|
|
private (float, float) _uiStickLeft;
|
|
public (float, float) UiStickLeft
|
|
{
|
|
get => (_uiStickLeft.Item1 * DrawStickScaleFactor, _uiStickLeft.Item2 * DrawStickScaleFactor);
|
|
set
|
|
{
|
|
_uiStickLeft = value;
|
|
|
|
OnPropertyChanged();
|
|
OnPropertyChanged(nameof(UiStickRightX));
|
|
OnPropertyChanged(nameof(UiStickRightY));
|
|
OnPropertyChanged(nameof(UiDeadzoneRight));
|
|
}
|
|
}
|
|
|
|
private (float, float) _uiStickRight;
|
|
public (float, float) UiStickRight
|
|
{
|
|
get => (_uiStickRight.Item1 * DrawStickScaleFactor, _uiStickRight.Item2 * DrawStickScaleFactor);
|
|
set
|
|
{
|
|
_uiStickRight = value;
|
|
|
|
OnPropertyChanged();
|
|
OnPropertyChanged(nameof(UiStickLeftX));
|
|
OnPropertyChanged(nameof(UiStickLeftY));
|
|
OnPropertyChanged(nameof(UiDeadzoneLeft));
|
|
}
|
|
}
|
|
|
|
public float UiStickLeftX => ClampVector(UiStickLeft).Item1;
|
|
public float UiStickLeftY => ClampVector(UiStickLeft).Item2;
|
|
public float UiStickRightX => ClampVector(UiStickRight).Item1;
|
|
public float UiStickRightY => ClampVector(UiStickRight).Item2;
|
|
|
|
public int UiStickCircumference => DrawStickCircumference;
|
|
public int UiCanvasSize => DrawStickCanvasSize;
|
|
public int UiStickBorderSize => DrawStickBorderSize;
|
|
|
|
public float? UiDeadzoneLeft => _gamepadConfig?.DeadzoneLeft * DrawStickCanvasSize - DrawStickCircumference;
|
|
public float? UiDeadzoneRight => _gamepadConfig?.DeadzoneRight * DrawStickCanvasSize - DrawStickCircumference;
|
|
|
|
private InputViewModel Parent;
|
|
|
|
public StickVisualizer(InputViewModel parent)
|
|
{
|
|
Parent = parent;
|
|
|
|
PollTokenSource = new CancellationTokenSource();
|
|
PollToken = PollTokenSource.Token;
|
|
|
|
Task.Run(Initialize, PollToken);
|
|
}
|
|
|
|
public void UpdateConfig(object config)
|
|
{
|
|
if (config is ControllerInputViewModel padConfig)
|
|
{
|
|
GamepadConfig = padConfig.Config;
|
|
Type = DeviceType.Controller;
|
|
|
|
return;
|
|
}
|
|
else if (config is KeyboardInputViewModel keyConfig)
|
|
{
|
|
KeyboardConfig = keyConfig.Config;
|
|
Type = DeviceType.Keyboard;
|
|
|
|
return;
|
|
}
|
|
|
|
Type = DeviceType.None;
|
|
}
|
|
|
|
public async Task Initialize()
|
|
{
|
|
(float, float) leftBuffer;
|
|
(float, float) rightBuffer;
|
|
|
|
while (!PollToken.IsCancellationRequested)
|
|
{
|
|
leftBuffer = (0f, 0f);
|
|
rightBuffer = (0f, 0f);
|
|
|
|
switch (Type)
|
|
{
|
|
case DeviceType.Keyboard:
|
|
IKeyboard keyboard = (IKeyboard)Parent.AvaloniaKeyboardDriver.GetGamepad("0");
|
|
|
|
if (keyboard != null)
|
|
{
|
|
KeyboardStateSnapshot snapshot = keyboard.GetKeyboardStateSnapshot();
|
|
|
|
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickRight))
|
|
{
|
|
leftBuffer.Item1 += 1;
|
|
}
|
|
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickLeft))
|
|
{
|
|
leftBuffer.Item1 -= 1;
|
|
}
|
|
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickUp))
|
|
{
|
|
leftBuffer.Item2 += 1;
|
|
}
|
|
if (snapshot.IsPressed((Key)KeyboardConfig.LeftStickDown))
|
|
{
|
|
leftBuffer.Item2 -= 1;
|
|
}
|
|
|
|
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickRight))
|
|
{
|
|
rightBuffer.Item1 += 1;
|
|
}
|
|
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickLeft))
|
|
{
|
|
rightBuffer.Item1 -= 1;
|
|
}
|
|
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickUp))
|
|
{
|
|
rightBuffer.Item2 += 1;
|
|
}
|
|
if (snapshot.IsPressed((Key)KeyboardConfig.RightStickDown))
|
|
{
|
|
rightBuffer.Item2 -= 1;
|
|
}
|
|
|
|
UiStickLeft = leftBuffer;
|
|
UiStickRight = rightBuffer;
|
|
}
|
|
break;
|
|
|
|
case DeviceType.Controller:
|
|
IGamepad controller = Parent.SelectedGamepad;
|
|
|
|
if (controller != null)
|
|
{
|
|
leftBuffer = controller.GetStick((StickInputId)GamepadConfig.LeftJoystick);
|
|
rightBuffer = controller.GetStick((StickInputId)GamepadConfig.RightJoystick);
|
|
}
|
|
break;
|
|
|
|
case DeviceType.None:
|
|
break;
|
|
default:
|
|
throw new ArgumentException($"Unable to poll device type \"{Type}\"");
|
|
}
|
|
|
|
UiStickLeft = leftBuffer;
|
|
UiStickRight = rightBuffer;
|
|
|
|
await Task.Delay(DrawStickPollRate, PollToken);
|
|
}
|
|
|
|
PollTokenSource.Dispose();
|
|
}
|
|
|
|
public static (float, float) ClampVector((float, float) vect)
|
|
{
|
|
_vectorMultiplier = 1;
|
|
_vectorLength = MathF.Sqrt((vect.Item1 * vect.Item1) + (vect.Item2 * vect.Item2));
|
|
|
|
if (_vectorLength > MaxVectorLength)
|
|
{
|
|
_vectorMultiplier = MaxVectorLength / _vectorLength;
|
|
}
|
|
|
|
vect.Item1 = vect.Item1 * _vectorMultiplier + DrawStickCanvasCenter;
|
|
vect.Item2 = vect.Item2 * _vectorMultiplier + DrawStickCanvasCenter;
|
|
|
|
return vect;
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!disposedValue)
|
|
{
|
|
if (disposing)
|
|
{
|
|
PollTokenSource.Cancel();
|
|
}
|
|
|
|
KeyboardConfig = null;
|
|
GamepadConfig = null;
|
|
Parent = null;
|
|
|
|
disposedValue = true;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(disposing: true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
}
|