From f26b3c193a4f42175d0b3918933c24e73e15acec Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 18 Jun 2025 19:01:20 +0100 Subject: [PATCH 1/5] Added gRPC sdk client --- .../Enum/WootingLayoutType.cs | 7 +- .../Generic/WootingLedMappings.cs | 4 + .../Generic/WootingRGBDevice.cs | 49 +++--- .../Generic/WootingRGBDeviceInfo.cs | 37 +---- .../Grpc/WootingGrpcDeviceProvider.cs | 139 ++++++++++++++++++ .../Grpc/WootingGrpcUpdateQueue.cs | 97 ++++++++++++ .../Keyboard/WootingKeyboardRGBDevice.cs | 32 +--- .../Keyboard/WootingKeyboardRGBDeviceInfo.cs | 17 +-- .../Keypad/WootingKeypadRGBDevice.cs | 27 +--- .../Keypad/WootingKeypadRGBDeviceInfo.cs | 8 +- .../{ => Native}/WootingDeviceProvider.cs | 38 +++-- .../WootingNativeUpdateQueue.cs} | 20 ++- .../RGB.NET.Devices.Wooting.csproj | 13 ++ RGB.NET.Devices.Wooting/WootingRgb.proto | 68 +++++++++ 14 files changed, 426 insertions(+), 130 deletions(-) create mode 100644 RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs create mode 100644 RGB.NET.Devices.Wooting/Grpc/WootingGrpcUpdateQueue.cs rename RGB.NET.Devices.Wooting/{ => Native}/WootingDeviceProvider.cs (68%) rename RGB.NET.Devices.Wooting/{Generic/WootingUpdateQueue.cs => Native/WootingNativeUpdateQueue.cs} (77%) create mode 100644 RGB.NET.Devices.Wooting/WootingRgb.proto diff --git a/RGB.NET.Devices.Wooting/Enum/WootingLayoutType.cs b/RGB.NET.Devices.Wooting/Enum/WootingLayoutType.cs index 70c1520..c3085ef 100644 --- a/RGB.NET.Devices.Wooting/Enum/WootingLayoutType.cs +++ b/RGB.NET.Devices.Wooting/Enum/WootingLayoutType.cs @@ -15,5 +15,8 @@ public enum WootingLayoutType { Unknown = -1, ANSI = 0, - ISO = 1 -} \ No newline at end of file + ISO = 1, + JIS = 2, + ANSI_SPLIT_SPACEBAR = 3, + ISO_SPLIT_SPACEBAR = 4, +} diff --git a/RGB.NET.Devices.Wooting/Generic/WootingLedMappings.cs b/RGB.NET.Devices.Wooting/Generic/WootingLedMappings.cs index 8ec7b97..9e07926 100644 --- a/RGB.NET.Devices.Wooting/Generic/WootingLedMappings.cs +++ b/RGB.NET.Devices.Wooting/Generic/WootingLedMappings.cs @@ -11,6 +11,10 @@ namespace RGB.NET.Devices.Wooting.Generic; /// internal static class WootingLedMappings { + + public const int ROWS = 6; + public const int COLUMNS = 21; + #region Properties & Fields private static readonly Dictionary TKL = new() diff --git a/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs b/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs index 7bc089e..9204708 100644 --- a/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs +++ b/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs @@ -1,40 +1,47 @@ -using RGB.NET.Core; -using RGB.NET.Devices.Wooting.Native; +using System.Collections.Generic; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Enum; namespace RGB.NET.Devices.Wooting.Generic; -/// -/// -/// -/// Represents a Wooting-device -/// public abstract class WootingRGBDevice : AbstractRGBDevice, IWootingRGBDevice where TDeviceInfo : WootingRGBDeviceInfo { - #region Constructors + #region Properties & Fields - /// - /// Initializes a new instance of the class. - /// - /// The generic information provided by Wooting for the device. - /// The update queue used to update this device. - protected WootingRGBDevice(TDeviceInfo info, IUpdateQueue updateQueue) - : base(info, updateQueue) - { - } + private readonly Dictionary _mapping; #endregion + #region Constructors + + internal WootingRGBDevice(WootingDeviceType deviceType, TDeviceInfo info, IUpdateQueue updateQueue) + : base(info, updateQueue) + { + _mapping = WootingLedMappings.Mapping[deviceType]; + InitializeLayout(); + } + + #endregion #region Methods + private void InitializeLayout() + { + foreach (KeyValuePair led in _mapping) + AddLed(led.Key, new Point(led.Value.column * 19, led.Value.row * 19), new Size(19, 19)); + } + + /// + protected override object GetLedCustomData(LedId ledId) => _mapping[ledId]; + + /// public override void Dispose() { - _WootingSDK.SelectDevice(DeviceInfo.WootingDeviceIndex); - _WootingSDK.Reset(); + UpdateQueue.Dispose(); base.Dispose(); } - + #endregion -} \ No newline at end of file +} diff --git a/RGB.NET.Devices.Wooting/Generic/WootingRGBDeviceInfo.cs b/RGB.NET.Devices.Wooting/Generic/WootingRGBDeviceInfo.cs index ec4500d..d77f190 100644 --- a/RGB.NET.Devices.Wooting/Generic/WootingRGBDeviceInfo.cs +++ b/RGB.NET.Devices.Wooting/Generic/WootingRGBDeviceInfo.cs @@ -1,14 +1,8 @@ using RGB.NET.Core; -using RGB.NET.Devices.Wooting.Enum; -using RGB.NET.Devices.Wooting.Native; namespace RGB.NET.Devices.Wooting.Generic; -/// -/// -/// Represents a generic information for a Wooting-. -/// -public class WootingRGBDeviceInfo : IRGBDeviceInfo +public abstract class WootingRGBDeviceInfo : IRGBDeviceInfo { #region Properties & Fields @@ -27,37 +21,16 @@ public class WootingRGBDeviceInfo : IRGBDeviceInfo /// public object? LayoutMetadata { get; set; } - /// - /// Gets the of the . - /// - public WootingDeviceType WootingDeviceType { get; } - - /// - /// Gets the of the . - /// - public WootingLayoutType WootingLayoutType { get; } - - public byte WootingDeviceIndex { get; } - #endregion #region Constructors - /// - /// Internal constructor of managed . - /// - /// The type of the . - /// The of the . - internal WootingRGBDeviceInfo(RGBDeviceType deviceType, _WootingDeviceInfo deviceInfo, byte deviceIndex) + protected WootingRGBDeviceInfo(RGBDeviceType deviceType, string model, string name) { this.DeviceType = deviceType; - this.WootingDeviceType = deviceInfo.DeviceType; - this.WootingLayoutType = deviceInfo.LayoutType; - this.WootingDeviceIndex = deviceIndex; - - Model = deviceInfo.Model; - DeviceName = DeviceHelper.CreateDeviceName(Manufacturer, Model); + this.Model = model; + this.DeviceName = name; } #endregion -} \ No newline at end of file +} diff --git a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs new file mode 100644 index 0000000..d13433c --- /dev/null +++ b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Grpc.Net.Client; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Enum; +using RGB.NET.Devices.Wooting.Keyboard; +using RGB.NET.Devices.Wooting.Keypad; +using WootingRgbSdk; + +namespace RGB.NET.Devices.Wooting.Grpc; + +/// +/// +/// Represents a device provider responsible for Wooting devices. +/// +public sealed class WootingGrpcDeviceProvider : AbstractRGBDeviceProvider +{ + #region Properties & Fields + + // ReSharper disable once InconsistentNaming + private static readonly Lock _lock = new(); + + private GrpcChannel? _channel; + private RgbSdkService.RgbSdkServiceClient? _client; + + private static WootingGrpcDeviceProvider? _instance; + /// + /// Gets the singleton instance. + /// + public static WootingGrpcDeviceProvider Instance + { + get + { + lock (_lock) + return _instance ?? new WootingGrpcDeviceProvider(); + } + } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// Thrown if this constructor is called even if there is already an instance of this class. + public WootingGrpcDeviceProvider() + { + lock (_lock) + { + if (_instance != null) + throw new InvalidOperationException($"There can be only one instance of type {nameof(WootingGrpcDeviceProvider)}"); + _instance = this; + } + } + + #endregion + + #region Methods + + /// + protected override void InitializeSDK() + { + _channel = GrpcChannel.ForAddress("http://localhost:50051"); + _client = new RgbSdkService.RgbSdkServiceClient(_channel); + } + + /// + protected override IEnumerable LoadDevices() + { + ArgumentNullException.ThrowIfNull(_client, nameof(_client)); + + int i = 0; + foreach (RgbGetConnectedDevicesResponse.Types.RgbDevice? device in _client.GetConnectedDevices(new()).Devices) + { + if (device.DeviceType == RgbDeviceType.None) + continue; // Skip devices that are not supported + + _client.Initialize(new RgbInitializeRequest { Id = device.Id }); + + WootingGrpcUpdateQueue updateQueue = new(GetUpdateTrigger(i++), device, _client); + + WootingDeviceType deviceType = device.DeviceType switch + { + RgbDeviceType.Tkl => WootingDeviceType.KeyboardTKL, + RgbDeviceType.FullSize => WootingDeviceType.Keyboard, + RgbDeviceType.SixtyPercent => WootingDeviceType.KeyboardSixtyPercent, + RgbDeviceType.ThreeKey => WootingDeviceType.Keypad3Keys, + RgbDeviceType.EighyPercent => WootingDeviceType.KeyboardEightyPercent, + _ or RgbDeviceType.None => throw new ArgumentOutOfRangeException() + }; + KeyboardLayoutType layoutType = device.LayoutType switch + { + RgbDeviceLayout.Ansi => KeyboardLayoutType.ANSI, + RgbDeviceLayout.Iso => KeyboardLayoutType.ISO, + RgbDeviceLayout.Jis => KeyboardLayoutType.JIS, + RgbDeviceLayout.AnsiSplitSpacebar => KeyboardLayoutType.ANSI, + RgbDeviceLayout.IsoSplitSpacebar => KeyboardLayoutType.ISO, + RgbDeviceLayout.Unknown => KeyboardLayoutType.Unknown, + _ => throw new ArgumentOutOfRangeException() + }; + + //NOTE: this model name ends up kind of ugly, since `ModelName` is like `Wooting 60HE`. We cannot remove the `Wooting` prefix, + //since that makes loadouts fail to load. The deviceName part, however, is fine to strip. + string model = device.ModelName; + string name = + DeviceHelper.CreateDeviceName("Wooting", $"{device.ModelName.Replace("Wooting", "").Trim()} ({device.SerialNumber})"); + + yield return deviceType switch + { + WootingDeviceType.Keypad3Keys => new WootingKeypadRGBDevice(deviceType, new(model, name), updateQueue), + _ => new WootingKeyboardRGBDevice(deviceType, new(layoutType, model, name), updateQueue) + }; + } + } + + /// + protected override void Dispose(bool disposing) + { + lock (_lock) + { + base.Dispose(disposing); + + try + { + _client = null; + _channel?.Dispose(); + } + catch + { /* at least we tried */ + } + + _instance = null; + } + } + + #endregion +} diff --git a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcUpdateQueue.cs b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcUpdateQueue.cs new file mode 100644 index 0000000..cdc2cfd --- /dev/null +++ b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcUpdateQueue.cs @@ -0,0 +1,97 @@ +using System; +using System.Runtime.InteropServices; +using Google.Protobuf; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Generic; +using WootingRgbSdk; + +namespace RGB.NET.Devices.Wooting.Grpc; + +/// +/// +/// Represents the update-queue performing updates for cooler master devices. +/// +public sealed class WootingGrpcUpdateQueue : UpdateQueue +{ + #region Properties & Fields + + private readonly RgbSdkService.RgbSdkServiceClient _client; + private readonly RgbGetConnectedDevicesResponse.Types.RgbDevice _wootDevice; + private readonly WootingColor[] _colors; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The update trigger used by this queue. + public WootingGrpcUpdateQueue(IDeviceUpdateTrigger updateTrigger, RgbGetConnectedDevicesResponse.Types.RgbDevice wootDevice, + RgbSdkService.RgbSdkServiceClient client) + : base(updateTrigger) + { + this._client = client; + this._wootDevice = wootDevice; + this._colors = new WootingColor[WootingLedMappings.COLUMNS * WootingLedMappings.ROWS]; + } + + #endregion + + #region Methods + + /// + protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet) + { + try + { + foreach ((object key, Color color) in dataSet) + { + (int row, int column) = ((int, int))key; + long index = (WootingLedMappings.COLUMNS * row) + column; + + _colors[index] = new WootingColor(color.GetR(), color.GetG(), color.GetB()); + } + + _client.SetColors(new RgbSetColorsRequest + { + Id = _wootDevice.Id, + Colors = ByteString.CopyFrom(MemoryMarshal.AsBytes(_colors.AsSpan())) + }); + return true; + } + catch (Exception ex) + { + WootingGrpcDeviceProvider.Instance.Throw(ex); + } + + return false; + } + + /// + public override void Dispose() + { + _client.Close(new RgbCloseRequest { Id = _wootDevice.Id }); + base.Dispose(); + } + + #endregion +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +internal struct WootingColor +{ + public byte r; + public byte g; + public byte b; + public byte a; + + public WootingColor(byte r, byte g, byte b) + { + this.r = r; + this.g = g; + this.b = b; + this.a = 0; // Alpha is not used in Wooting devices + } +} + diff --git a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs index 0ba3600..d8d4410 100644 --- a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs +++ b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using RGB.NET.Core; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Enum; using RGB.NET.Devices.Wooting.Generic; namespace RGB.NET.Devices.Wooting.Keyboard; @@ -22,28 +22,12 @@ public sealed class WootingKeyboardRGBDevice : WootingRGBDevice /// Initializes a new instance of the class. /// + /// The type of the Wooting device. /// The specific information provided by Wooting for the keyboard - /// The update trigger used to update this device. - internal WootingKeyboardRGBDevice(WootingKeyboardRGBDeviceInfo info, IUpdateQueue updateQueue) - : base(info, updateQueue) - { - InitializeLayout(); - } + /// The update queue used to update this device. + internal WootingKeyboardRGBDevice(WootingDeviceType deviceType, WootingKeyboardRGBDeviceInfo info, IUpdateQueue updateQueue) + : base(deviceType, info, updateQueue) + { } #endregion - - #region Methods - - private void InitializeLayout() - { - Dictionary mapping = WootingLedMappings.Mapping[DeviceInfo.WootingDeviceType]; - - foreach (KeyValuePair led in mapping) - AddLed(led.Key, new Point(led.Value.column * 19, led.Value.row * 19), new Size(19, 19)); - } - - /// - protected override object GetLedCustomData(LedId ledId) => WootingLedMappings.Mapping[DeviceInfo.WootingDeviceType][ledId]; - - #endregion -} \ No newline at end of file +} diff --git a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDeviceInfo.cs b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDeviceInfo.cs index e3f8bbf..1b8695a 100644 --- a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDeviceInfo.cs +++ b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDeviceInfo.cs @@ -23,17 +23,14 @@ public sealed class WootingKeyboardRGBDeviceInfo : WootingRGBDeviceInfo, IKeyboa /// /// Internal constructor of managed . /// - /// The native . - internal WootingKeyboardRGBDeviceInfo(_WootingDeviceInfo deviceInfo, byte deviceIndex) - : base(RGBDeviceType.Keyboard, deviceInfo, deviceIndex) + /// The layout of the keyboard. + /// The model of the keyboard. + /// The name of the keyboard. + internal WootingKeyboardRGBDeviceInfo(KeyboardLayoutType layout, string model, string name) + : base(RGBDeviceType.Keyboard, model, name) { - Layout = WootingLayoutType switch - { - WootingLayoutType.ANSI => KeyboardLayoutType.ANSI, - WootingLayoutType.ISO => KeyboardLayoutType.ISO, - _ => KeyboardLayoutType.Unknown - }; + Layout = layout; } #endregion -} \ No newline at end of file +} diff --git a/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDevice.cs b/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDevice.cs index 984072b..20af0ee 100644 --- a/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDevice.cs +++ b/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDevice.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Enum; using RGB.NET.Devices.Wooting.Generic; namespace RGB.NET.Devices.Wooting.Keypad; @@ -16,28 +17,12 @@ public sealed class WootingKeypadRGBDevice : WootingRGBDevice /// Initializes a new instance of the class. /// + /// The type of the Wooting device. /// The specific information provided by Wooting for the keyboard /// The update queue used to update this device. - internal WootingKeypadRGBDevice(WootingKeypadRGBDeviceInfo info, IUpdateQueue updateQueue) - : base(info, updateQueue) - { - InitializeLayout(); - } + internal WootingKeypadRGBDevice(WootingDeviceType deviceType, WootingKeypadRGBDeviceInfo info, IUpdateQueue updateQueue) + : base(deviceType, info, updateQueue) + { } #endregion - - #region Methods - - private void InitializeLayout() - { - Dictionary mapping = WootingLedMappings.Mapping[DeviceInfo.WootingDeviceType]; - - foreach (KeyValuePair led in mapping) - AddLed(led.Key, new Point(led.Value.column * 19, led.Value.row * 19), new Size(19, 19)); - } - - /// - protected override object GetLedCustomData(LedId ledId) => WootingLedMappings.Mapping[DeviceInfo.WootingDeviceType][ledId]; - - #endregion -} \ No newline at end of file +} diff --git a/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDeviceInfo.cs b/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDeviceInfo.cs index 55088e1..fb90592 100644 --- a/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDeviceInfo.cs +++ b/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDeviceInfo.cs @@ -9,9 +9,7 @@ namespace RGB.NET.Devices.Wooting.Keypad; /// public sealed class WootingKeypadRGBDeviceInfo : WootingRGBDeviceInfo { - internal WootingKeypadRGBDeviceInfo(_WootingDeviceInfo deviceInfo, byte deviceIndex) - : base(RGBDeviceType.Keypad, deviceInfo, deviceIndex) - { - - } + internal WootingKeypadRGBDeviceInfo(string model, string name) + : base(RGBDeviceType.Keypad, model, name) + { } } diff --git a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs b/RGB.NET.Devices.Wooting/Native/WootingDeviceProvider.cs similarity index 68% rename from RGB.NET.Devices.Wooting/WootingDeviceProvider.cs rename to RGB.NET.Devices.Wooting/Native/WootingDeviceProvider.cs index cb58d18..6bc749a 100644 --- a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs +++ b/RGB.NET.Devices.Wooting/Native/WootingDeviceProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; @@ -72,7 +72,8 @@ public sealed class WootingDeviceProvider : AbstractRGBDeviceProvider { lock (_lock) { - if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(WootingDeviceProvider)}"); + if (_instance != null) + throw new InvalidOperationException($"There can be only one instance of type {nameof(WootingDeviceProvider)}"); _instance = this; } } @@ -99,18 +100,35 @@ public sealed class WootingDeviceProvider : AbstractRGBDeviceProvider { for (byte i = 0; i < _WootingSDK.GetDeviceCount(); i++) { - WootingUpdateQueue updateQueue = new(GetUpdateTrigger(), i); + WootingNativeUpdateQueue updateQueue = new(GetUpdateTrigger(), i); _WootingSDK.SelectDevice(i); - _WootingDeviceInfo nativeDeviceInfo = (_WootingDeviceInfo)Marshal.PtrToStructure(_WootingSDK.GetDeviceInfo(), typeof(_WootingDeviceInfo))!; - + _WootingDeviceInfo nativeDeviceInfo = + (_WootingDeviceInfo)Marshal.PtrToStructure(_WootingSDK.GetDeviceInfo(), typeof(_WootingDeviceInfo))!; + //Uwu non-rgb returns zero here. if (nativeDeviceInfo.MaxLedIndex == 0) continue; + KeyboardLayoutType layoutType = nativeDeviceInfo.LayoutType switch + { + WootingLayoutType.Unknown => KeyboardLayoutType.Unknown, + WootingLayoutType.ANSI => KeyboardLayoutType.ANSI, + WootingLayoutType.ISO => KeyboardLayoutType.ISO, + WootingLayoutType.JIS => KeyboardLayoutType.JIS, + WootingLayoutType.ANSI_SPLIT_SPACEBAR => KeyboardLayoutType.ANSI, + WootingLayoutType.ISO_SPLIT_SPACEBAR => KeyboardLayoutType.ISO, + _ => throw new ArgumentOutOfRangeException() + }; + + //Note: we cannot change *any* of these here or the local database Artemis has will no longer match up and everything breaks. + string model = nativeDeviceInfo.Model; + string name = DeviceHelper.CreateDeviceName("Wooting", model); + yield return nativeDeviceInfo.DeviceType switch { - WootingDeviceType.Keypad3Keys => new WootingKeypadRGBDevice(new WootingKeypadRGBDeviceInfo(nativeDeviceInfo, i), updateQueue), - _ => new WootingKeyboardRGBDevice(new WootingKeyboardRGBDeviceInfo(nativeDeviceInfo, i), updateQueue), + WootingDeviceType.Keypad3Keys => new WootingKeypadRGBDevice(nativeDeviceInfo.DeviceType, new(model, name), + updateQueue), + _ => new WootingKeyboardRGBDevice(nativeDeviceInfo.DeviceType, new(layoutType, model, name), updateQueue) }; } } @@ -127,7 +145,9 @@ public sealed class WootingDeviceProvider : AbstractRGBDeviceProvider lock (_WootingSDK.SdkLock) { try { _WootingSDK.UnloadWootingSDK(); } - catch { /* at least we tried */ } + catch + { /* at least we tried */ + } } _instance = null; @@ -135,4 +155,4 @@ public sealed class WootingDeviceProvider : AbstractRGBDeviceProvider } #endregion -} \ No newline at end of file +} diff --git a/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs b/RGB.NET.Devices.Wooting/Native/WootingNativeUpdateQueue.cs similarity index 77% rename from RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs rename to RGB.NET.Devices.Wooting/Native/WootingNativeUpdateQueue.cs index be942cf..daba1a8 100644 --- a/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs +++ b/RGB.NET.Devices.Wooting/Native/WootingNativeUpdateQueue.cs @@ -1,14 +1,13 @@ -using System; +using System; using RGB.NET.Core; -using RGB.NET.Devices.Wooting.Native; -namespace RGB.NET.Devices.Wooting.Generic; +namespace RGB.NET.Devices.Wooting.Native; /// /// /// Represents the update-queue performing updates for cooler master devices. /// -public sealed class WootingUpdateQueue : UpdateQueue +public sealed class WootingNativeUpdateQueue : UpdateQueue { #region Properties & Fields @@ -22,7 +21,7 @@ public sealed class WootingUpdateQueue : UpdateQueue /// Initializes a new instance of the class. /// /// The update trigger used by this queue. - public WootingUpdateQueue(IDeviceUpdateTrigger updateTrigger, byte deviceId) + public WootingNativeUpdateQueue(IDeviceUpdateTrigger updateTrigger, byte deviceId) : base(updateTrigger) { this._deviceid = deviceId; @@ -60,5 +59,14 @@ public sealed class WootingUpdateQueue : UpdateQueue return false; } + /// + public override void Dispose() + { + _WootingSDK.SelectDevice(_deviceid); + _WootingSDK.Reset(); + + base.Dispose(); + } + #endregion -} \ No newline at end of file +} diff --git a/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj b/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj index 778d0b9..966cad2 100644 --- a/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj +++ b/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj @@ -64,4 +64,17 @@ + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + \ No newline at end of file diff --git a/RGB.NET.Devices.Wooting/WootingRgb.proto b/RGB.NET.Devices.Wooting/WootingRgb.proto new file mode 100644 index 0000000..4ba7548 --- /dev/null +++ b/RGB.NET.Devices.Wooting/WootingRgb.proto @@ -0,0 +1,68 @@ +syntax = "proto3"; + +package wooting_rgb_sdk; + +//from C rgb_sdk +enum RgbDeviceType { + None = 0; + Tkl = 1; + FullSize = 2; + SixtyPercent = 3; + ThreeKey = 4; + EighyPercent = 5; +} + +//from C rgb_sdk +enum RgbDeviceLayout { + ANSI = 0; + ISO = 1; + JIS = 2; + ANSI_SPLIT_SPACEBAR = 3; + ISO_SPLIT_SPACEBAR = 4; + Unknown = -1; +} + +message RgbGetConnectedDevicesRequest {} + +message RgbGetConnectedDevicesResponse { + message RgbDevice { + uint64 id = 1; + uint32 rows = 2; + uint32 columns = 3; + string model_name = 4; + string serial_number = 5; + RgbDeviceType device_type = 6; + RgbDeviceLayout layout_type = 7; + } + + repeated RgbDevice devices = 1; +} + +message RgbInitializeRequest { + uint64 id = 1; +} + +message RgbInitializeResponse { +} + +message RgbSetColorsRequest { + uint64 id = 1; + bytes colors = 2; +} + +message RgbSetColorsResponse { +} + +message RgbCloseRequest { + uint64 id = 1; +} + +message RgbCloseResponse { +} + +service RgbSdkService { + rpc GetConnectedDevices(RgbGetConnectedDevicesRequest) returns (RgbGetConnectedDevicesResponse); + rpc Initialize(RgbInitializeRequest) returns (RgbInitializeResponse); + rpc SetColors(RgbSetColorsRequest) returns (RgbSetColorsResponse); + rpc Close(RgbCloseRequest) returns (RgbCloseResponse); +} \ No newline at end of file From a96b994e61d3953f58f67b646fdf9f7c8adff548 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 18 Jun 2025 19:05:33 +0100 Subject: [PATCH 2/5] Fix warning --- RGB.NET.Devices.Wooting/Native/WootingNativeUpdateQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RGB.NET.Devices.Wooting/Native/WootingNativeUpdateQueue.cs b/RGB.NET.Devices.Wooting/Native/WootingNativeUpdateQueue.cs index daba1a8..ec895f0 100644 --- a/RGB.NET.Devices.Wooting/Native/WootingNativeUpdateQueue.cs +++ b/RGB.NET.Devices.Wooting/Native/WootingNativeUpdateQueue.cs @@ -18,7 +18,7 @@ public sealed class WootingNativeUpdateQueue : UpdateQueue #region Constructors /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The update trigger used by this queue. public WootingNativeUpdateQueue(IDeviceUpdateTrigger updateTrigger, byte deviceId) From 34b04523dee0afefeabe29ceb5ba48124082648d Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 18 Jun 2025 19:31:00 +0100 Subject: [PATCH 3/5] make wootingcolor readonly, use int for array index --- .../Grpc/WootingGrpcDeviceProvider.cs | 2 +- .../Grpc/WootingGrpcUpdateQueue.cs | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs index d13433c..2ad96b1 100644 --- a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs +++ b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs @@ -66,7 +66,7 @@ public sealed class WootingGrpcDeviceProvider : AbstractRGBDeviceProvider _client = new RgbSdkService.RgbSdkServiceClient(_channel); } - /// + /// protected override IEnumerable LoadDevices() { ArgumentNullException.ThrowIfNull(_client, nameof(_client)); diff --git a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcUpdateQueue.cs b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcUpdateQueue.cs index cdc2cfd..83ff7b9 100644 --- a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcUpdateQueue.cs +++ b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcUpdateQueue.cs @@ -48,7 +48,7 @@ public sealed class WootingGrpcUpdateQueue : UpdateQueue foreach ((object key, Color color) in dataSet) { (int row, int column) = ((int, int))key; - long index = (WootingLedMappings.COLUMNS * row) + column; + int index = (WootingLedMappings.COLUMNS * row) + column; _colors[index] = new WootingColor(color.GetR(), color.GetG(), color.GetB()); } @@ -79,12 +79,12 @@ public sealed class WootingGrpcUpdateQueue : UpdateQueue } [StructLayout(LayoutKind.Sequential, Pack = 1)] -internal struct WootingColor +internal readonly struct WootingColor { - public byte r; - public byte g; - public byte b; - public byte a; + public readonly byte r; + public readonly byte g; + public readonly byte b; + public readonly byte a; public WootingColor(byte r, byte g, byte b) { @@ -94,4 +94,3 @@ internal struct WootingColor this.a = 0; // Alpha is not used in Wooting devices } } - From dc6715b2364d38b789c5d7bede2aa94de1482201 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 18 Jun 2025 19:44:29 +0100 Subject: [PATCH 4/5] use serial number hash as update trigger id --- RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs index 2ad96b1..712d8c0 100644 --- a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs +++ b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs @@ -71,7 +71,6 @@ public sealed class WootingGrpcDeviceProvider : AbstractRGBDeviceProvider { ArgumentNullException.ThrowIfNull(_client, nameof(_client)); - int i = 0; foreach (RgbGetConnectedDevicesResponse.Types.RgbDevice? device in _client.GetConnectedDevices(new()).Devices) { if (device.DeviceType == RgbDeviceType.None) @@ -79,7 +78,7 @@ public sealed class WootingGrpcDeviceProvider : AbstractRGBDeviceProvider _client.Initialize(new RgbInitializeRequest { Id = device.Id }); - WootingGrpcUpdateQueue updateQueue = new(GetUpdateTrigger(i++), device, _client); + WootingGrpcUpdateQueue updateQueue = new(GetUpdateTrigger(device.SerialNumber.GetHashCode()), device, _client); WootingDeviceType deviceType = device.DeviceType switch { From 35a40335213a6753559f90dd6ae59f0c7dfbeb14 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 18 Jun 2025 22:23:23 +0100 Subject: [PATCH 5/5] connect on ipv4 only speeds up first connection significantly --- RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs index 712d8c0..a7070d3 100644 --- a/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs +++ b/RGB.NET.Devices.Wooting/Grpc/WootingGrpcDeviceProvider.cs @@ -62,7 +62,7 @@ public sealed class WootingGrpcDeviceProvider : AbstractRGBDeviceProvider /// protected override void InitializeSDK() { - _channel = GrpcChannel.ForAddress("http://localhost:50051"); + _channel = GrpcChannel.ForAddress("http://127.0.0.1:50051"); _client = new RgbSdkService.RgbSdkServiceClient(_channel); }