Ver Fonte

UI: Add the ability to change a DualSense/DualShock 4's LED color.
Not functional yet. This is the UI & persistence side of #572.

Evan Husted há 1 ano atrás
pai
commit
c03cd50fa3

+ 5 - 0
src/Ryujinx.Common/Configuration/Hid/Controller/GenericControllerInputConfig.cs

@@ -78,5 +78,10 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
         /// Controller Rumble Settings
         /// </summary>
         public RumbleConfigController Rumble { get; set; }
+        
+        /// <summary>
+        /// Controller LED Settings
+        /// </summary>
+        public LedConfigController Led { get; set; }
     }
 }

+ 15 - 0
src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs

@@ -0,0 +1,15 @@
+namespace Ryujinx.Common.Configuration.Hid.Controller
+{
+    public class LedConfigController
+    {
+        /// <summary>
+        ///     Packed RGB int of the color
+        /// </summary>
+        public uint LedColor { get; set; }
+
+        /// <summary>
+        /// Enable LED color changing by the emulator
+        /// </summary>
+        public bool EnableLed { get; set; }
+    }
+}

+ 6 - 0
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;
         }
 

+ 5 - 0
src/Ryujinx.Input/GamepadFeaturesFlag.cs

@@ -24,5 +24,10 @@ namespace Ryujinx.Input
         /// <remarks>Also named sixaxis</remarks>
         /// </summary>
         Motion,
+        
+        /// <summary>
+        ///     The LED on the back of modern PlayStation controllers (DualSense &amp; DualShock 4).
+        /// </summary>
+        Led,
     }
 }

+ 42 - 1
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,

+ 1 - 1
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)
         {

+ 2 - 0
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;

+ 32 - 0
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 @@
                             </Button>
                         </Grid>
                     </Border>
+                    <Border
+                        BorderBrush="{DynamicResource ThemeControlBorderColor}"
+                        BorderThickness="1"
+                        CornerRadius="5"
+                        HorizontalAlignment="Stretch"
+                        Margin="0,-1,0,0">
+                        <Grid IsVisible="{Binding ParentModel.HasLed}">
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition Width="*" />
+                                <ColumnDefinition Width="Auto" />
+                            </Grid.ColumnDefinitions>
+                            <CheckBox
+                                Margin="10"
+                                MinWidth="0"
+                                Grid.Column="0"
+                                IsChecked="{Binding Config.EnableLedChanging, Mode=TwoWay}">
+                                <TextBlock Text="Custom LED color" />
+                            </CheckBox>
+                            <ui:ColorPickerButton 
+                                Grid.Column="1"
+                                Margin="10"
+                                IsMoreButtonVisible="False"
+                                UseColorPalette="False"
+                                UseColorTriangle="False"
+                                UseColorWheel="False"
+                                ShowAcceptDismissButtons="False"
+                                IsAlphaEnabled="False"
+                                Color="{Binding Config.LedColor, Mode=TwoWay}">
+                            </ui:ColorPickerButton>
+                        </Grid>
+                    </Border>
                 </StackPanel>
             </StackPanel>
             <!-- Right Controls -->

+ 0 - 3
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

+ 1 - 1
src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs

@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
         /// <summary>
         /// The current version of the file format
         /// </summary>
-        public const int CurrentVersion = 60;
+        public const int CurrentVersion = 61;
 
         /// <summary>
         /// Version of the configuration file format

+ 16 - 8
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<StandardControllerInputConfig>())
                     {
-                        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<StandardControllerInputConfig>())
+                    {
+                        config.Led = new LedConfigController
+                        {
+                            EnableLed = false,
+                            LedColor = 328189
+                        };
+                    }
+                })
             );
     }
 }