Files
Ryujinx-greemdev/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs

186 lines
5.8 KiB
C#

using Avalonia.Svg.Skia;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Views.Input;
using Ryujinx.Input;
using System.Threading;
using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public partial class ControllerInputViewModel : BaseModel
{
private const int DrawStickPollRate = 50; // Milliseconds per poll.
private const int DrawStickCircumference = 5;
private const float DrawStickScaleFactor = DrawStickCanvasCenter;
private const int DrawStickCanvasSize = 100;
private const int DrawStickBorderSize = DrawStickCanvasSize + 5;
private const float DrawStickCanvasCenter = (DrawStickCanvasSize - DrawStickCircumference) / 2;
private const float MaxVectorLength = DrawStickCanvasSize / 2;
private IGamepad _selectedGamepad;
private StickVisualizer _stickVisualizer;
public StickVisualizer StickVisualizer
{
get => _stickVisualizer;
set
{
_stickVisualizer = value;
OnPropertyChanged();
}
}
private GamepadInputConfig _config;
public GamepadInputConfig Config
{
get => _config;
set
{
_config = value;
StickVisualizer.UpdateConfig(Config);
OnPropertyChanged();
}
}
private bool _isLeft;
public bool IsLeft
{
get => _isLeft;
set
{
_isLeft = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
private bool _isRight;
public bool IsRight
{
get => _isRight;
set
{
_isRight = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
public bool HasSides => IsLeft ^ IsRight;
[ObservableProperty] private SvgImage _image;
public InputViewModel ParentModel { get; }
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 int UiStickCircumference => DrawStickCircumference;
public int UiCanvasSize => DrawStickCanvasSize;
public int UiStickBorderSize => DrawStickBorderSize;
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 float UiDeadzoneLeft => Config.DeadzoneLeft * DrawStickCanvasSize - DrawStickCircumference;
public float UiDeadzoneRight => Config.DeadzoneRight * DrawStickCanvasSize - DrawStickCircumference;
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config)
{
ParentModel = model;
model.NotifyChangesEvent += OnParentModelChanged;
OnParentModelChanged();
_stickVisualizer = new();
Config = config;
StickVisualizer.PollToken = StickVisualizer.PollTokenSource.Token;
Task.Run(() => PollSticks(StickVisualizer.PollToken));
}
public async void ShowMotionConfig()
{
await MotionInputView.Show(this);
}
public async void ShowRumbleConfig()
{
await RumbleInputView.Show(this);
}
public RelayCommand LedDisabledChanged => Commands.Create(() =>
{
if (!Config.EnableLedChanging) return;
if (Config.TurnOffLed)
ParentModel.SelectedGamepad.ClearLed();
else
ParentModel.SelectedGamepad.SetLed(Config.LedColor.ToUInt32());
});
private async Task PollSticks(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
_selectedGamepad = ParentModel.SelectedGamepad;
if (_selectedGamepad != null && _selectedGamepad is not AvaloniaKeyboard)
{
StickVisualizer.UiStickLeft = _selectedGamepad.GetStick(StickInputId.Left);
StickVisualizer.UiStickRight = _selectedGamepad.GetStick(StickInputId.Right);
}
await Task.Delay(StickVisualizer.DrawStickPollRate, token);
}
StickVisualizer.PollTokenSource.Dispose();
}
public void OnParentModelChanged()
{
IsLeft = ParentModel.IsLeft;
IsRight = ParentModel.IsRight;
Image = ParentModel.Image;
}
}
}