Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to change controller LED color #572

Merged
merged 33 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8904397
Change controller LED color
Otozinclus Jan 22, 2025
e861204
fix formatting & styling
GreemDev Jan 22, 2025
6c0526c
Check if controller has a controllable LED
Otozinclus Jan 22, 2025
861531f
just testing if git is working
Otozinclus Jan 22, 2025
c21aa86
just testing if git works
Otozinclus Jan 22, 2025
eff11f5
Change controller LED color
Otozinclus Jan 22, 2025
f4c3a2e
fix formatting & styling
GreemDev Jan 22, 2025
488b09f
Check if controller has a controllable LED
Otozinclus Jan 22, 2025
bdaaddb
just testing if git is working
Otozinclus Jan 22, 2025
e945565
just testing if git works
Otozinclus Jan 22, 2025
2c4236f
test
Otozinclus Jan 23, 2025
740e358
test
Otozinclus Jan 23, 2025
97dfeae
test2
Otozinclus Jan 23, 2025
9aa834c
maybe this works
Otozinclus Jan 23, 2025
96e9e36
move logic around
Otozinclus Jan 23, 2025
898153a
Update SDL2Gamepad.cs
GreemDev Jan 23, 2025
5276991
Update SDL2Gamepad.cs
GreemDev Jan 23, 2025
8e642f0
Merge branch 'master' into Change-Controller-LED-Color
GreemDev Jan 23, 2025
5712e83
UI: enable LED changing
GreemDev Jan 23, 2025
cfe4256
Add the LED functionality to the base IGamepad interface
GreemDev Jan 24, 2025
72d5af8
Update LED as its changed in the UI
GreemDev Jan 24, 2025
bf869b0
Properly save default
GreemDev Jan 24, 2025
033f305
log line to match other optional gamepad features
GreemDev Jan 24, 2025
b442d32
directly compare result of rumble instead of storing an error int
GreemDev Jan 24, 2025
6619453
Check if controller supports Rumble rather than trying to rumble for …
GreemDev Jan 24, 2025
5f02765
Allow the ability to turn off the LED entirely
GreemDev Jan 24, 2025
a6dfbe9
Clear the LED on all controllers when settings window is closed and w…
GreemDev Jan 24, 2025
344c1a5
Clear LED on game close as well
GreemDev Jan 24, 2025
8a22d9a
tab
GreemDev Jan 24, 2025
e8025e1
Rainbow LED
GreemDev Jan 24, 2025
8b76295
forgot to use the new locale key
GreemDev Jan 24, 2025
5e8ba2c
cleanup testing changes
GreemDev Jan 24, 2025
76b8c79
Merge branch 'master' into Change-Controller-LED-Color
GreemDev Jan 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@
{
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; }

/// <summary>
/// Ignores the color and disables the LED entirely.
/// </summary>
public bool TurnOffLed { get; set; }

/// <summary>
/// Ignores the color and uses the rainbow color functionality for the LED.
/// </summary>
public bool UseRainbow { get; set; }

/// <summary>
/// Packed RGB int of the color
/// </summary>
public uint LedColor { get; set; }
}
}
76 changes: 76 additions & 0 deletions src/Ryujinx.Common/Utilities/Rainbow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Drawing;

namespace Ryujinx.Common.Utilities
{
public class Rainbow
{
public const float Speed = 1;

public static Color Color { get; private set; } = Color.Blue;

public static void Tick()
{
Color = HsbToRgb(
(Color.GetHue() + Speed) / 360,
1,
1
);

RainbowColorUpdated?.Invoke(Color.ToArgb());
}

public static event Action<int> RainbowColorUpdated;

private static Color HsbToRgb(float hue, float saturation, float brightness)
{
int r = 0, g = 0, b = 0;
if (saturation == 0)
{
r = g = b = (int)(brightness * 255.0f + 0.5f);
}
else
{
float h = (hue - (float)Math.Floor(hue)) * 6.0f;
float f = h - (float)Math.Floor(h);
float p = brightness * (1.0f - saturation);
float q = brightness * (1.0f - saturation * f);
float t = brightness * (1.0f - (saturation * (1.0f - f)));
switch ((int)h)
{
case 0:
r = (int)(brightness * 255.0f + 0.5f);
g = (int)(t * 255.0f + 0.5f);
b = (int)(p * 255.0f + 0.5f);
break;
case 1:
r = (int)(q * 255.0f + 0.5f);
g = (int)(brightness * 255.0f + 0.5f);
b = (int)(p * 255.0f + 0.5f);
break;
case 2:
r = (int)(p * 255.0f + 0.5f);
g = (int)(brightness * 255.0f + 0.5f);
b = (int)(t * 255.0f + 0.5f);
break;
case 3:
r = (int)(p * 255.0f + 0.5f);
g = (int)(q * 255.0f + 0.5f);
b = (int)(brightness * 255.0f + 0.5f);
break;
case 4:
r = (int)(t * 255.0f + 0.5f);
g = (int)(p * 255.0f + 0.5f);
b = (int)(brightness * 255.0f + 0.5f);
break;
case 5:
r = (int)(brightness * 255.0f + 0.5f);
g = (int)(p * 255.0f + 0.5f);
b = (int)(q * 255.0f + 0.5f);
break;
}
}
return Color.FromArgb(Convert.ToByte(255), Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b));
}
}
}
31 changes: 27 additions & 4 deletions src/Ryujinx.Input.SDL2/SDL2Gamepad.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.Services.Hid;
using SDL2;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -86,7 +88,7 @@ public SDL2Gamepad(nint gamepadHandle, string driverId)
Id = driverId;
Features = GetFeaturesFlag();
_triggerThreshold = 0.0f;

// Enable motion tracking
if (Features.HasFlag(GamepadFeaturesFlag.Motion))
{
Expand All @@ -102,6 +104,18 @@ public SDL2Gamepad(nint gamepadHandle, string driverId)
}
}

public void SetLed(uint packedRgb)
{
if (!Features.HasFlag(GamepadFeaturesFlag.Led)) return;

byte red = packedRgb > 0 ? (byte)(packedRgb >> 16) : (byte)0;
byte green = packedRgb > 0 ? (byte)(packedRgb >> 8) : (byte)0;
byte blue = packedRgb > 0 ? (byte)(packedRgb % 256) : (byte)0;

if (SDL_GameControllerSetLED(_gamepadHandle, red, green, blue) != 0)
Logger.Error?.Print(LogClass.Hid, "LED is not supported on this game controller.");
}

private GamepadFeaturesFlag GetFeaturesFlag()
{
GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
Expand All @@ -112,9 +126,7 @@ private GamepadFeaturesFlag GetFeaturesFlag()
result |= GamepadFeaturesFlag.Motion;
}

int error = SDL_GameControllerRumble(_gamepadHandle, 0, 0, 100);

if (error == 0)
if (SDL_GameControllerHasRumble(_gamepadHandle) == SDL_bool.SDL_TRUE)
{
result |= GamepadFeaturesFlag.Rumble;
}
Expand Down Expand Up @@ -220,6 +232,17 @@ public void SetConfiguration(InputConfig configuration)
{
_configuration = (StandardControllerInputConfig)configuration;

if (Features.HasFlag(GamepadFeaturesFlag.Led) && _configuration.Led.EnableLed)
{
if (_configuration.Led.TurnOffLed)
(this as IGamepad).ClearLed();
else if (_configuration.Led.UseRainbow)
Rainbow.RainbowColorUpdated += clr => SetLed((uint)clr);
else
SetLed(_configuration.Led.LedColor);

}

_buttonsUserMapping.Clear();

// First update sticks
Expand Down
11 changes: 11 additions & 0 deletions src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,5 +173,16 @@ public IGamepad GetGamepad(string id)

return new SDL2Gamepad(gamepadHandle, id);
}

public IEnumerable<IGamepad> GetGamepads()
{
lock (_gamepadsIds)
{
foreach (string gamepadId in _gamepadsIds)
{
yield return GetGamepad(gamepadId);
}
}
}
}
}
6 changes: 6 additions & 0 deletions src/Ryujinx.Input.SDL2/SDL2Keyboard.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Logging;
using System;
using System.Collections.Generic;
using System.Numerics;
Expand Down Expand Up @@ -385,6 +386,11 @@ public void SetConfiguration(InputConfig configuration)
}
}

public void SetLed(uint packedRgb)
{
Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL2Keyboard");
}

public void SetTriggerThreshold(float triggerThreshold)
{
// No operations
Expand Down
6 changes: 6 additions & 0 deletions src/Ryujinx.Input.SDL2/SDL2Mouse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging;
using System;
using System.Drawing;
using System.Numerics;
Expand Down Expand Up @@ -76,6 +77,11 @@ public void SetConfiguration(InputConfig configuration)
throw new NotImplementedException();
}

public void SetLed(uint packedRgb)
{
Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL2Mouse");
}

public void SetTriggerThreshold(float triggerThreshold)
{
throw new NotImplementedException();
Expand Down
3 changes: 3 additions & 0 deletions src/Ryujinx.Input.SDL2/SDL2MouseDriver.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Numerics;
Expand Down Expand Up @@ -164,6 +165,8 @@ public IGamepad GetGamepad(string id)
return new SDL2Mouse(this);
}

public IEnumerable<IGamepad> GetGamepads() => [GetGamepad("0")];

public void Dispose()
{
if (_isDisposed)
Expand Down
9 changes: 9 additions & 0 deletions src/Ryujinx.Input.SDL2/SDLKeyboardDriver.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Ryujinx.SDL2.Common;
using System;
using System.Collections.Generic;

namespace Ryujinx.Input.SDL2
{
Expand Down Expand Up @@ -51,5 +52,13 @@ public IGamepad GetGamepad(string id)

return new SDL2Keyboard(this, _keyboardIdentifers[0], "All keyboards");
}

public IEnumerable<IGamepad> GetGamepads()
{
foreach (var keyboardId in _keyboardIdentifers)
{
yield return GetGamepad(keyboardId);
}
}
}
}
9 changes: 9 additions & 0 deletions src/Ryujinx.Input/IGamepad.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ public interface IGamepad : IDisposable
/// <param name="configuration">The configuration of the gamepad</param>
void SetConfiguration(InputConfig configuration);

/// <summary>
/// Set the LED on the gamepad to a given color.
/// </summary>
/// <remarks>Does nothing on a controller without LED functionality.</remarks>
/// <param name="packedRgb">The packed RGB integer.</param>
void SetLed(uint packedRgb);

public void ClearLed() => SetLed(0);

/// <summary>
/// Starts a rumble effect on the gamepad.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions src/Ryujinx.Input/IGamepadDriver.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;

namespace Ryujinx.Input
{
Expand Down Expand Up @@ -33,6 +34,11 @@ public interface IGamepadDriver : IDisposable
/// <param name="id">The unique id of the gamepad</param>
/// <returns>An instance of <see cref="IGamepad"/> associated to the gamepad id given or null if not found</returns>
IGamepad GetGamepad(string id);

/// <summary>
/// Returns an <see cref="IEnumerable{T}"/> of the connected gamepads.
/// </summary>
IEnumerable<IGamepad> GetGamepads();

/// <summary>
/// Clear the internal state of the driver.
Expand Down
3 changes: 3 additions & 0 deletions src/Ryujinx.SDL2.Common/SDL2Driver.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
Expand Down Expand Up @@ -167,6 +168,8 @@ private void EventWorker()
HandleSDLEvent(ref evnt);
}
});

Rainbow.Tick();

waitHandle.Wait(WaitTimeMs);
}
Expand Down
5 changes: 5 additions & 0 deletions src/Ryujinx/AppHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,11 @@ private void Exit()
return;
}

foreach (IGamepad gamepad in RyujinxApp.MainWindow.InputManager.GamepadDriver.GetGamepads())
{
gamepad?.ClearLed();
}

_isStopped = true;
Stop();
}
Expand Down
52 changes: 51 additions & 1 deletion src/Ryujinx/Assets/locales.json
Original file line number Diff line number Diff line change
Expand Up @@ -7628,7 +7628,57 @@
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Custom LED",
"en_US": "LED",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "ControllerSettingsLedColorDisable",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Disable",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "ControllerSettingsLedColorRainbow",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Rainbow",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
Expand Down
Loading
Loading