From 395e9c856267704c4554db10c558a33e1088a567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayta=C3=A7=20Kayadelen?= Date: Sun, 18 Jun 2023 18:40:17 +0200 Subject: [PATCH 1/4] implement DevicesChanged event for Openrgb and make name creations consistent --- .../Abstract/AbstractOpenRGBDevice.cs | 19 +++ .../Abstract/OpenRGBDeviceInfo.cs | 7 +- .../Generic/OpenRGBUpdateQueue.cs | 4 +- RGB.NET.Devices.OpenRGB/Helper.cs | 21 ++- .../OpenRGBClientWrapper.cs | 22 +++ .../OpenRGBDeviceProvider.cs | 146 +++++++++++------- 6 files changed, 161 insertions(+), 58 deletions(-) create mode 100644 RGB.NET.Devices.OpenRGB/OpenRGBClientWrapper.cs diff --git a/RGB.NET.Devices.OpenRGB/Abstract/AbstractOpenRGBDevice.cs b/RGB.NET.Devices.OpenRGB/Abstract/AbstractOpenRGBDevice.cs index 78f3f1fb..36ab64d1 100644 --- a/RGB.NET.Devices.OpenRGB/Abstract/AbstractOpenRGBDevice.cs +++ b/RGB.NET.Devices.OpenRGB/Abstract/AbstractOpenRGBDevice.cs @@ -21,4 +21,23 @@ protected AbstractOpenRGBDevice(TDeviceInfo info, IUpdateQueue updateQueue) { } #endregion + + #region Methods + + private bool Equals(AbstractOpenRGBDevice other) + { + return DeviceInfo.DeviceName == other.DeviceInfo.DeviceName; + } + + public override bool Equals(object? obj) + { + return ReferenceEquals(this, obj) || (obj is AbstractOpenRGBDevice other && Equals(other)); + } + + public override int GetHashCode() + { + return DeviceInfo.DeviceName.GetHashCode(); + } + + #endregion } diff --git a/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs b/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs index 5d3cc1bb..7b927683 100644 --- a/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs +++ b/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs @@ -38,14 +38,17 @@ public class OpenRGBDeviceInfo : IRGBDeviceInfo /// Initializes a new instance of . /// /// The OpenRGB device to extract information from. - internal OpenRGBDeviceInfo(OpenRGBDevice openRGBDevice) + /// If this is a zone or segment, specify the name + internal OpenRGBDeviceInfo(OpenRGBDevice openRGBDevice, string? splitId = null) { this.OpenRGBDevice = openRGBDevice; DeviceType = Helper.GetRgbNetDeviceType(openRGBDevice.Type); Manufacturer = Helper.GetVendorName(openRGBDevice); Model = Helper.GetModelName(openRGBDevice); - DeviceName = DeviceHelper.CreateDeviceName(Manufacturer, Model); + string model = Manufacturer + " " + Model; + string id = string.IsNullOrWhiteSpace(openRGBDevice.Serial) ? openRGBDevice.Location : openRGBDevice.Serial; + DeviceName = model + " #" + Helper.HashAndShorten(id) + (splitId != null ? $" {splitId}" : null); } #endregion diff --git a/RGB.NET.Devices.OpenRGB/Generic/OpenRGBUpdateQueue.cs b/RGB.NET.Devices.OpenRGB/Generic/OpenRGBUpdateQueue.cs index 0537d11b..9cb6876e 100644 --- a/RGB.NET.Devices.OpenRGB/Generic/OpenRGBUpdateQueue.cs +++ b/RGB.NET.Devices.OpenRGB/Generic/OpenRGBUpdateQueue.cs @@ -18,7 +18,7 @@ public sealed class OpenRGBUpdateQueue : UpdateQueue private readonly int _deviceId; - private readonly OpenRgbClient _openRGB; + private readonly IOpenRgbClient _openRGB; private readonly OpenRGBColor[] _colors; #endregion @@ -32,7 +32,7 @@ public sealed class OpenRGBUpdateQueue : UpdateQueue /// The index used to identify the device. /// The OpenRGB client used to send updates to the OpenRGB server. /// The OpenRGB Device containing device-specific information. - public OpenRGBUpdateQueue(IDeviceUpdateTrigger updateTrigger, int deviceId, OpenRgbClient client, OpenRGBDevice device) + public OpenRGBUpdateQueue(IDeviceUpdateTrigger updateTrigger, int deviceId, IOpenRgbClient client, OpenRGBDevice device) : base(updateTrigger) { this._deviceId = deviceId; diff --git a/RGB.NET.Devices.OpenRGB/Helper.cs b/RGB.NET.Devices.OpenRGB/Helper.cs index a79afffb..01757b7e 100644 --- a/RGB.NET.Devices.OpenRGB/Helper.cs +++ b/RGB.NET.Devices.OpenRGB/Helper.cs @@ -1,4 +1,7 @@ -using OpenRGB.NET; +using System; +using System.Security.Cryptography; +using System.Text; +using OpenRGB.NET; using RGB.NET.Core; using OpenRGBDevice = OpenRGB.NET.Device; @@ -53,4 +56,20 @@ public static string GetVendorName(OpenRGBDevice openRGBDevice) => string.IsNull public static string GetModelName(OpenRGBDevice openRGBDevice) => string.IsNullOrWhiteSpace(openRGBDevice.Vendor) ? openRGBDevice.Name : openRGBDevice.Name.Replace(openRGBDevice.Vendor, "").Trim(); + + internal static string HashAndShorten(string input) + { + using SHA256 sha256Hash = SHA256.Create(); + byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(input)); + // Take the first 4 bytes of the hash + byte[] shortenedBytes = new byte[4]; + Array.Copy(bytes, shortenedBytes, 4); + // Convert the bytes to a string + StringBuilder shortenedHash = new(); + foreach (byte b in shortenedBytes) + { + shortenedHash.Append(b.ToString("X2")); + } + return shortenedHash.ToString(); + } } diff --git a/RGB.NET.Devices.OpenRGB/OpenRGBClientWrapper.cs b/RGB.NET.Devices.OpenRGB/OpenRGBClientWrapper.cs new file mode 100644 index 00000000..f36c716d --- /dev/null +++ b/RGB.NET.Devices.OpenRGB/OpenRGBClientWrapper.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using OpenRGB.NET; +using RGB.NET.Core; + +namespace RGB.NET.Devices.OpenRGB; + +public class OpenRGBClientWrapper +{ + public OpenRgbClient OpenRgbClient { get; } + + public List Devices { get; } = new(); + + public OpenRGBClientWrapper(OpenRgbClient openRgbClient) + { + OpenRgbClient = openRgbClient; + } + + public void Dispose() + { + OpenRgbClient.Dispose(); + } +} diff --git a/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs index 4d194843..dbaed3f5 100644 --- a/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs +++ b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs @@ -1,8 +1,9 @@ -using OpenRGB.NET; using RGB.NET.Core; using System; using System.Collections.Generic; using System.Linq; +using OpenRGB.NET; +using OpenRgbDevice = OpenRGB.NET.Device; namespace RGB.NET.Devices.OpenRGB; @@ -14,7 +15,7 @@ public sealed class OpenRGBDeviceProvider : AbstractRGBDeviceProvider { #region Properties & Fields - private readonly List _clients = new(); + private readonly List _clients = new(); private static OpenRGBDeviceProvider? _instance; @@ -71,7 +72,9 @@ protected override void InitializeSDK() try { OpenRgbClient openRgb = new(ip: deviceDefinition.Ip, port: deviceDefinition.Port, name: deviceDefinition.ClientName, autoConnect: true); - _clients.Add(openRgb); + OpenRGBClientWrapper wrapper = new(openRgb); + openRgb.DeviceListUpdated += (_, _) => RefreshClient(wrapper); + _clients.Add(wrapper); deviceDefinition.Connected = true; } catch (Exception e) @@ -82,67 +85,104 @@ protected override void InitializeSDK() } } } + + private void RefreshClient(OpenRGBClientWrapper openRgbClient) + { + List currentDevices = new(openRgbClient.Devices); + List newDevices = GetOrgbClientDevices(openRgbClient.OpenRgbClient) + .SelectMany((device, i) => SplitDevice(device, i, openRgbClient.OpenRgbClient)).ToList(); + + foreach (IRGBDevice rgbDevice in currentDevices.Except(newDevices)) + { + RemoveDevice(rgbDevice); + openRgbClient.Devices.Remove(rgbDevice); + } + foreach (IRGBDevice rgbDevice in newDevices) + { + openRgbClient.Devices.Add(rgbDevice); + AddDevice(rgbDevice); + } + } /// protected override IEnumerable LoadDevices() { - foreach (OpenRgbClient? openRgb in _clients) + return _clients.SelectMany(LoadClientDevices); + } + + private IEnumerable LoadClientDevices(OpenRGBClientWrapper client) + { + List devices = GetOrgbClientDevices(client.OpenRgbClient) + .SelectMany((device, i) => SplitDevice(device, i, client.OpenRgbClient)) + .ToList(); + client.Devices.AddRange(devices); + return devices; + } + + private IEnumerable GetOrgbClientDevices(IOpenRgbClient openRgb) + { + int deviceCount = openRgb.GetControllerCount(); + + for (int i = 0; i < deviceCount; i++) { - int deviceCount = openRgb.GetControllerCount(); + OpenRgbDevice device = openRgb.GetControllerData(i); - for (int i = 0; i < deviceCount; i++) + int directModeIndex = Array.FindIndex(device.Modes, d => d.Name == "Direct"); + if (directModeIndex != -1) + { + //set the device to direct mode if it has it + openRgb.UpdateMode(i, directModeIndex); + } + else if (!ForceAddAllDevices) { - Device device = openRgb.GetControllerData(i); + //if direct mode does not exist + //and if we're not forcing, continue to the next device. + continue; + } - int directModeIndex = Array.FindIndex(device.Modes, d => d.Name == "Direct"); - if (directModeIndex != -1) - { - //set the device to direct mode if it has it - openRgb.UpdateMode(i, directModeIndex); - } - else if (!ForceAddAllDevices) - { - //if direct mode does not exist - //and if we're not forcing, continue to the next device. - continue; - } + if (device.Zones.Length == 0) + continue; + if (device.Zones.All(z => z.LedCount == 0)) + continue; - if (device.Zones.Length == 0) - continue; - if (device.Zones.All(z => z.LedCount == 0)) - continue; + yield return device; + } + } - OpenRGBUpdateQueue updateQueue = new(GetUpdateTrigger(), i, openRgb, device); - - bool anyZoneHasSegments = device.Zones.Any(z => z.Segments.Length > 0); - bool splitDeviceByZones = anyZoneHasSegments || PerZoneDeviceFlag.HasFlag(Helper.GetRgbNetDeviceType(device.Type)); + private IEnumerable SplitDevice(OpenRgbDevice device, int i, IOpenRgbClient openRgb) + { + IDeviceUpdateTrigger clientUpdateTrigger = GetUpdateTrigger(); + OpenRGBUpdateQueue updateQueue = new(clientUpdateTrigger, i, openRgb, device); - if (!splitDeviceByZones) - { - yield return new OpenRGBGenericDevice(new OpenRGBDeviceInfo(device), updateQueue); - continue; - } - - int totalLedCount = 0; + bool anyZoneHasSegments = device.Zones.Any(z => z.Segments.Length > 0); + bool splitDeviceByZones = anyZoneHasSegments || PerZoneDeviceFlag.HasFlag(Helper.GetRgbNetDeviceType(device.Type)); - foreach (Zone zone in device.Zones) + if (!splitDeviceByZones) + { + yield return new OpenRGBGenericDevice(new OpenRGBDeviceInfo(device), updateQueue); + yield break; + } + + int totalLedCount = 0; + + foreach (Zone zone in device.Zones) + { + if (zone.LedCount <= 0) + continue; + + if (zone.Segments.Length <= 0) + { + string zoneId = zone.Name; + yield return new OpenRGBZoneDevice(new OpenRGBDeviceInfo(device, zoneId), totalLedCount, zone, updateQueue); + totalLedCount += (int)zone.LedCount; + } + else + { + foreach (Segment segment in zone.Segments) { - if (zone.LedCount <= 0) - continue; - - if (zone.Segments.Length <= 0) - { - yield return new OpenRGBZoneDevice(new OpenRGBDeviceInfo(device), totalLedCount, zone, updateQueue); - totalLedCount += (int)zone.LedCount; - } - else - { - foreach (Segment segment in zone.Segments) - { - yield return new OpenRGBSegmentDevice(new OpenRGBDeviceInfo(device), totalLedCount, segment, updateQueue); - totalLedCount += (int)segment.LedCount; - } - } + string zoneId = segment.Name; + yield return new OpenRGBSegmentDevice(new OpenRGBDeviceInfo(device, zoneId), totalLedCount, segment, updateQueue); + totalLedCount += (int)segment.LedCount; } } } @@ -153,9 +193,9 @@ public override void Dispose() { base.Dispose(); - foreach (OpenRgbClient client in _clients) + foreach (OpenRGBClientWrapper wrapper in _clients) { - try { client.Dispose(); } + try { wrapper.Dispose(); } catch { /* at least we tried */ } } From 72bf866caa3f7f1508b425affa639db263234055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayta=C3=A7=20Kayadelen?= Date: Sun, 9 Jul 2023 14:34:01 +0200 Subject: [PATCH 2/4] change id generation based on object typed key --- RGB.NET.Core/Ids/IdGenerator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RGB.NET.Core/Ids/IdGenerator.cs b/RGB.NET.Core/Ids/IdGenerator.cs index c6270e7c..2d8e200e 100644 --- a/RGB.NET.Core/Ids/IdGenerator.cs +++ b/RGB.NET.Core/Ids/IdGenerator.cs @@ -13,8 +13,8 @@ public static class IdGenerator // ReSharper disable InconsistentNaming private static readonly HashSet _registeredIds = new(); - private static readonly Dictionary> _idMappings = new(); - private static readonly Dictionary> _counter = new(); + private static readonly Dictionary> _idMappings = new(); + private static readonly Dictionary> _counter = new(); // ReSharper restore InconsistentNaming #endregion @@ -29,7 +29,7 @@ public static class IdGenerator [MethodImpl(MethodImplOptions.NoInlining)] public static string MakeUnique(string id) => MakeUnique(Assembly.GetCallingAssembly(), id); - internal static string MakeUnique(Assembly callingAssembly, string id) + public static string MakeUnique(object callingAssembly, string id) { if (!_idMappings.TryGetValue(callingAssembly, out Dictionary? idMapping)) { @@ -63,7 +63,7 @@ internal static string MakeUnique(Assembly callingAssembly, string id) [MethodImpl(MethodImplOptions.NoInlining)] public static void ResetCounter() => ResetCounter(Assembly.GetCallingAssembly()); - internal static void ResetCounter(Assembly callingAssembly) + public static void ResetCounter(object callingAssembly) { if (_counter.TryGetValue(callingAssembly, out Dictionary? counter)) counter.Clear(); From 3e8a9e2dd12d6ee320d937987a403c4d61c0698c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayta=C3=A7=20Kayadelen?= Date: Sun, 9 Jul 2023 14:40:32 +0200 Subject: [PATCH 3/4] Handle name generations for unpluggable devices, for openrgb --- RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs | 9 ++++++++- RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs b/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs index 7b927683..1d48b27e 100644 --- a/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs +++ b/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs @@ -48,7 +48,14 @@ internal OpenRGBDeviceInfo(OpenRGBDevice openRGBDevice, string? splitId = null) Model = Helper.GetModelName(openRGBDevice); string model = Manufacturer + " " + Model; string id = string.IsNullOrWhiteSpace(openRGBDevice.Serial) ? openRGBDevice.Location : openRGBDevice.Serial; - DeviceName = model + " #" + Helper.HashAndShorten(id) + (splitId != null ? $" {splitId}" : null); + if (string.IsNullOrWhiteSpace(id)) // this device is 99% unpluggable + { + DeviceName = IdGenerator.MakeUnique(typeof(OpenRGBDeviceProvider), Manufacturer + " " + Model); + } + else + { + DeviceName = model + " #" + Helper.HashAndShorten(id) + (splitId != null ? $" {splitId}" : null); + } } #endregion diff --git a/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs index dbaed3f5..a8b5a8ed 100644 --- a/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs +++ b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs @@ -201,6 +201,8 @@ public override void Dispose() _clients.Clear(); DeviceDefinitions.Clear(); + + IdGenerator.ResetCounter(typeof(OpenRGBDeviceProvider)); } #endregion From e47a4014c9a96ae766897b64b3e92f3dcf267215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayta=C3=A7=20Kayadelen?= Date: Wed, 6 Dec 2023 22:32:48 +0100 Subject: [PATCH 4/4] add doc for HashAndShorten method --- RGB.NET.Devices.OpenRGB/Helper.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RGB.NET.Devices.OpenRGB/Helper.cs b/RGB.NET.Devices.OpenRGB/Helper.cs index 01757b7e..6fdeed0a 100644 --- a/RGB.NET.Devices.OpenRGB/Helper.cs +++ b/RGB.NET.Devices.OpenRGB/Helper.cs @@ -56,7 +56,9 @@ public static string GetVendorName(OpenRGBDevice openRGBDevice) => string.IsNull public static string GetModelName(OpenRGBDevice openRGBDevice) => string.IsNullOrWhiteSpace(openRGBDevice.Vendor) ? openRGBDevice.Name : openRGBDevice.Name.Replace(openRGBDevice.Vendor, "").Trim(); - + /** + * Shortens given input into 8 character string + */ internal static string HashAndShorten(string input) { using SHA256 sha256Hash = SHA256.Create();