diff --git a/src/Ryujinx.Common/Configuration/Hid/Controller/GenericControllerInputConfig.cs b/src/Ryujinx.Common/Configuration/Hid/Controller/GenericControllerInputConfig.cs index e6fe74d53..fbb19767c 100644 --- a/src/Ryujinx.Common/Configuration/Hid/Controller/GenericControllerInputConfig.cs +++ b/src/Ryujinx.Common/Configuration/Hid/Controller/GenericControllerInputConfig.cs @@ -78,5 +78,10 @@ namespace Ryujinx.Common.Configuration.Hid.Controller /// Controller Rumble Settings /// public RumbleConfigController Rumble { get; set; } + + /// + /// Controller LED Settings + /// + public LedConfigController Led { get; set; } } } diff --git a/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs b/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs new file mode 100644 index 000000000..21727d62e --- /dev/null +++ b/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Common.Configuration.Hid.Controller +{ + public class LedConfigController + { + /// + /// Packed RGB int of the color + /// + public uint LedColor { get; set; } + + /// + /// Enable LED color changing by the emulator + /// + public bool EnableLed { get; set; } + } +} diff --git a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs b/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs index 12bfab4bb..ed22c3661 100644 --- a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs +++ b/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs @@ -1,6 +1,7 @@ using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Logging; +using SDL2; using System; using System.Collections.Generic; using System.Numerics; @@ -118,6 +119,11 @@ namespace Ryujinx.Input.SDL2 result |= GamepadFeaturesFlag.Rumble; } + if (SDL_GameControllerHasLED(_gamepadHandle) == SDL_bool.SDL_TRUE) + { + result |= GamepadFeaturesFlag.Led; + } + return result; } diff --git a/src/Ryujinx.Input/GamepadFeaturesFlag.cs b/src/Ryujinx.Input/GamepadFeaturesFlag.cs index 69ec23686..52e8519d1 100644 --- a/src/Ryujinx.Input/GamepadFeaturesFlag.cs +++ b/src/Ryujinx.Input/GamepadFeaturesFlag.cs @@ -24,5 +24,10 @@ namespace Ryujinx.Input /// Also named sixaxis /// Motion, + + /// + /// The LED on the back of modern PlayStation controllers (DualSense & DualShock 4). + /// + Led, } } diff --git a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs index 833670bdc..ea7dd34c3 100644 --- a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs +++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs @@ -1,3 +1,4 @@ +using Avalonia.Media; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; @@ -387,6 +388,30 @@ namespace Ryujinx.Ava.UI.Models.Input } } + private bool _enableLedChanging; + + public bool EnableLedChanging + { + get => _enableLedChanging; + set + { + _enableLedChanging = value; + OnPropertyChanged(); + } + } + + private Color _ledColor; + + public Color LedColor + { + get => _ledColor; + set + { + _ledColor = value; + OnPropertyChanged(); + } + } + private bool _enableMotion; public bool EnableMotion { @@ -483,12 +508,23 @@ namespace Ryujinx.Ava.UI.Models.Input WeakRumble = controllerInput.Rumble.WeakRumble; StrongRumble = controllerInput.Rumble.StrongRumble; } + + if (controllerInput.Led != null) + { + EnableLedChanging = controllerInput.Led.EnableLed; + uint rawColor = controllerInput.Led.LedColor; + byte alpha = (byte)(rawColor >> 24); + byte red = (byte)(rawColor >> 16); + byte green = (byte)(rawColor >> 8); + byte blue = (byte)(rawColor % 256); + LedColor = new Color(alpha, red, green, blue); + } } } public InputConfig GetConfig() { - var config = new StandardControllerInputConfig + StandardControllerInputConfig config = new() { Id = Id, Backend = InputBackendType.GamepadSDL2, @@ -540,6 +576,11 @@ namespace Ryujinx.Ava.UI.Models.Input WeakRumble = WeakRumble, StrongRumble = StrongRumble, }, + Led = new LedConfigController + { + EnableLed = EnableLedChanging, + LedColor = LedColor.ToUInt32() + }, Version = InputConfig.CurrentVersion, DeadzoneLeft = DeadzoneLeft, DeadzoneRight = DeadzoneRight, diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index 482fe2981..0380ef598 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input [ObservableProperty] private SvgImage _image; - public readonly InputViewModel ParentModel; + public InputViewModel ParentModel { get; } public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) { diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 05f479d9f..7fda4e2d0 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -68,6 +68,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public bool IsKeyboard => !IsController; public bool IsRight { get; set; } public bool IsLeft { get; set; } + + public bool HasLed => SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led); public bool IsModified { get; set; } public event Action NotifyChangesEvent; diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 7daf23eb6..73f74e36f 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -4,6 +4,7 @@ xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" @@ -486,6 +487,37 @@ + + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs index ee84fbc37..52a6d51b9 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs @@ -4,14 +4,11 @@ using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.LogicalTree; -using DiscordRPC; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Common.Configuration.Hid.Controller; -using Ryujinx.Common.Logging; using Ryujinx.Input; using Ryujinx.Input.Assigner; -using System; using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; namespace Ryujinx.Ava.UI.Views.Input diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs index 6d3570850..4bbc5e622 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs @@ -17,7 +17,7 @@ namespace Ryujinx.Ava.Utilities.Configuration /// /// The current version of the file format /// - public const int CurrentVersion = 60; + public const int CurrentVersion = 61; /// /// Version of the configuration file format diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs index 943aab513..521780e94 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs @@ -263,15 +263,12 @@ namespace Ryujinx.Ava.Utilities.Configuration }), (30, static cff => { - foreach (InputConfig config in cff.InputConfig) + foreach (StandardControllerInputConfig config in cff.InputConfig.OfType()) { - if (config is StandardControllerInputConfig controllerConfig) + config.Rumble = new RumbleConfigController { - controllerConfig.Rumble = new RumbleConfigController - { - EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f, - }; - } + EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f, + }; } }), (31, static cff => cff.BackendThreading = BackendThreading.Auto), @@ -416,7 +413,18 @@ namespace Ryujinx.Ava.Utilities.Configuration // so as a compromise users who want to use it will simply need to re-enable it once after updating. cff.IgnoreApplet = false; }), - (60, static cff => cff.StartNoUI = false) + (60, static cff => cff.StartNoUI = false), + (61, static cff => + { + foreach (StandardControllerInputConfig config in cff.InputConfig.OfType()) + { + config.Led = new LedConfigController + { + EnableLed = false, + LedColor = 328189 + }; + } + }) ); } }