From 412dc9785c219e9f5f84a19cf39bdef319caecd2 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 22 Sep 2021 17:06:56 +0100 Subject: [PATCH 1/5] Logitech - Added wireless device detection --- RGB.NET.Devices.Logitech/HID/Extensions.cs | 49 +++++ RGB.NET.Devices.Logitech/HID/FapResponse.cs | 73 +++++++ .../HID/FapShortRequest.cs | 29 +++ .../HID/LightspeedHidLoader.cs | 191 ++++++++++++++++++ .../LogitechDeviceProvider.cs | 116 ++++++++--- 5 files changed, 425 insertions(+), 33 deletions(-) create mode 100644 RGB.NET.Devices.Logitech/HID/Extensions.cs create mode 100644 RGB.NET.Devices.Logitech/HID/FapResponse.cs create mode 100644 RGB.NET.Devices.Logitech/HID/FapShortRequest.cs create mode 100644 RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs diff --git a/RGB.NET.Devices.Logitech/HID/Extensions.cs b/RGB.NET.Devices.Logitech/HID/Extensions.cs new file mode 100644 index 0000000..30cc874 --- /dev/null +++ b/RGB.NET.Devices.Logitech/HID/Extensions.cs @@ -0,0 +1,49 @@ +using HidSharp; +using HidSharp.Reports.Encodings; +using System; +using System.Linq; +using System.Runtime.InteropServices; + +namespace RGB.NET.Devices.Logitech.HID +{ + public static class Extensions + { + public static Span AsSpan(this ref T val) where T : unmanaged + { + Span valSpan = MemoryMarshal.CreateSpan(ref val, 1); + return MemoryMarshal.Cast(valSpan); + } + + public static uint GetUsagePage(this HidDevice device) + { + try + { + var descriptor = device.GetRawReportDescriptor(); + var decodedItems = EncodedItem.DecodeItems(descriptor, 0, descriptor.Length); + var usefulItems = decodedItems.Where(de => de.TagForLocal == LocalItemTag.Usage && de.TagForGlobal == GlobalItemTag.UsagePage); + var usagePage = usefulItems.FirstOrDefault(de => de.ItemType == ItemType.Global); + return usagePage.DataValue; + } + catch + { + return uint.MaxValue; + } + } + + public static uint GetUsage(this HidDevice device) + { + try + { + var descriptor = device.GetRawReportDescriptor(); + var decodedItems = EncodedItem.DecodeItems(descriptor, 0, descriptor.Length); + var usefulItems = decodedItems.Where(de => de.TagForLocal == LocalItemTag.Usage && de.TagForGlobal == GlobalItemTag.UsagePage); + var usage = usefulItems.FirstOrDefault(de => de.ItemType == ItemType.Local); + return usage.DataValue; + } + catch + { + return uint.MaxValue; + } + } + } +} diff --git a/RGB.NET.Devices.Logitech/HID/FapResponse.cs b/RGB.NET.Devices.Logitech/HID/FapResponse.cs new file mode 100644 index 0000000..010c67d --- /dev/null +++ b/RGB.NET.Devices.Logitech/HID/FapResponse.cs @@ -0,0 +1,73 @@ +using System.Runtime.InteropServices; + +namespace RGB.NET.Devices.Logitech.HID +{ + [StructLayout(LayoutKind.Sequential, Pack = 0, Size = 64)] + public struct FapResponse + { + public byte Command; + public byte DeviceIndex; + public byte FeatureIndex; + public byte FeatureCommand; + public byte Data00; + public byte Data01; + public byte Data02; + public byte Data03; + public byte Data04; + public byte Data05; + public byte Data06; + public byte Data07; + public byte Data08; + public byte Data09; + public byte Data10; + public byte Data11; + public byte Data12; + public byte Data13; + public byte Data14; + public byte Data15; + public byte Data16; + public byte Data17; + public byte Data18; + public byte Data19; + public byte Data20; + public byte Data21; + public byte Data22; + public byte Data23; + public byte Data24; + public byte Data25; + public byte Data26; + public byte Data27; + public byte Data28; + public byte Data29; + public byte Data30; + public byte Data31; + public byte Data32; + public byte Data33; + public byte Data34; + public byte Data35; + public byte Data36; + public byte Data37; + public byte Data38; + public byte Data39; + public byte Data40; + public byte Data41; + public byte Data42; + public byte Data43; + public byte Data44; + public byte Data45; + public byte Data46; + public byte Data47; + public byte Data48; + public byte Data49; + public byte Data50; + public byte Data51; + public byte Data52; + public byte Data53; + public byte Data54; + public byte Data55; + public byte Data56; + public byte Data57; + public byte Data58; + public byte Data59; + } +} diff --git a/RGB.NET.Devices.Logitech/HID/FapShortRequest.cs b/RGB.NET.Devices.Logitech/HID/FapShortRequest.cs new file mode 100644 index 0000000..c76f2b7 --- /dev/null +++ b/RGB.NET.Devices.Logitech/HID/FapShortRequest.cs @@ -0,0 +1,29 @@ +using System.Runtime.InteropServices; + +namespace RGB.NET.Devices.Logitech.HID +{ + [StructLayout(LayoutKind.Sequential, Pack = 0, Size = 7)] + public struct FapShortRequest + { + const byte LOGITECH_SHORT_MESSAGE = 0x10; + + public byte ReportId; + public byte DeviceIndex; + public byte FeatureIndex; + public byte FeatureCommand; + public byte Data0; + public byte Data1; + public byte Data2; + + public void Init(byte deviceIndex, byte featureIndex) + { + ReportId = LOGITECH_SHORT_MESSAGE; + DeviceIndex = deviceIndex; + FeatureIndex = featureIndex; + FeatureCommand = 0; + Data0 = 0; + Data1 = 0; + Data2 = 0; + } + } +} diff --git a/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs b/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs new file mode 100644 index 0000000..eb2bcc9 --- /dev/null +++ b/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs @@ -0,0 +1,191 @@ +using HidSharp; +using RGB.NET.Core; +using RGB.NET.HID; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RGB.NET.Devices.Logitech.HID +{ + public class LightspeedHIDLoader : IEnumerable> + where TLed : notnull + { + #region Properties & Fields + + private readonly Dictionary> _deviceDefinitions = new(); + + /// + /// Gets the vendor id used for this loader. + /// + public int VendorId => 0x046d; + + /// + /// Gets or sets the filter used to determine which devices should be loaded. + /// + public RGBDeviceType LoadFilter { get; set; } = RGBDeviceType.All; + + private static List ReceiverPids { get; } = new() + { + 0xC539, + 0xC53A, + 0xC541, + 0xC545 + }; + + #endregion + + #region Methods + + /// + /// Adds a new to this loader. + /// + /// The virtual product id of the HID-device. + /// The type of the device. + /// The name of the device. + /// The mapping of the leds of the device. + /// Some custom data to attach to the device. + public void Add(int virtualPid, RGBDeviceType deviceType, string name, LedMapping ledMapping, TData customData) + => _deviceDefinitions.Add(virtualPid, new HIDDeviceDefinition(virtualPid, deviceType, name, ledMapping, customData)); + + /// + /// Gets a enumerable containing all devices from the definition-list that are connected and match the . + /// + /// The enumerable containing the connected devices. + public IEnumerable> GetConnectedDevices() + { + foreach (var device in Detect()) + { + if (_deviceDefinitions.TryGetValue(device, out HIDDeviceDefinition? definition)) + if (LoadFilter.HasFlag(definition.DeviceType)) + yield return definition; + } + } + + /// + /// Gets a enumerable containing all the first device of each group of devices from the definition-list that are connected and match the . + /// The grouping is done by the specified function. + /// + /// The type of the key used to group the devices. + /// The function grouping the devices. + /// The enumerable containing the selected devices. + public IEnumerable> GetConnectedDevices(Func, TKey> groupBy) + => GetConnectedDevices().GroupBy(x => groupBy(x)) + .Select(group => group.First()); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + /// + public IEnumerator> GetEnumerator() => _deviceDefinitions.Values.GetEnumerator(); + + #endregion + + #region Private Methods + + private IEnumerable Detect() + { + foreach (var receiverPid in ReceiverPids) + { + foreach (var wirelessPid in Detect(receiverPid)) + { + yield return wirelessPid; + } + } + } + + private IEnumerable Detect(int pid) + { + var receiverDevices = DeviceList.Local.GetHidDevices(VendorId, pid); + var interfaceTwo = receiverDevices.Where(d => d.DevicePath.Contains("mi_02")); + //this is terrible but i don't know how else to filter interfaces + + Dictionary deviceUsages = new(); + foreach (var item in interfaceTwo) + { + deviceUsages.Add((byte)item.GetUsage(), item); + } + + foreach ((var wirelessPid, var deviceIndex) in GetWirelessDevices(deviceUsages)) + { + yield return wirelessPid; + } + } + + private Dictionary GetWirelessDevices(Dictionary device_usages) + { + const byte LOGITECH_RECEIVER_ADDRESS = 0xFF; + const byte LOGITECH_SET_REGISTER_REQUEST = 0x80; + const byte LOGITECH_GET_REGISTER_REQUEST = 0x81; + + Dictionary map = new(); + + if (device_usages.TryGetValue(1, out var device)) + { + var stream = device.Open(); + + var response = new FapResponse(); + + var getConnectedDevices = new FapShortRequest(); + getConnectedDevices.Init(LOGITECH_RECEIVER_ADDRESS, LOGITECH_GET_REGISTER_REQUEST); + + stream.Write(getConnectedDevices.AsSpan()); + stream.Read(response.AsSpan()); + + bool wireless_notifications = (response.Data01 & 1) == 1; + if (!wireless_notifications) + { + response = new FapResponse(); + + getConnectedDevices.Init(LOGITECH_RECEIVER_ADDRESS, LOGITECH_SET_REGISTER_REQUEST); + getConnectedDevices.Data1 = 1; + + stream.Write(getConnectedDevices.AsSpan()); + stream.Read(response.AsSpan()); + + if (getConnectedDevices.FeatureIndex == 0x8f) + { + //error?? + } + } + + response = new FapResponse(); + + getConnectedDevices.Init(LOGITECH_RECEIVER_ADDRESS, LOGITECH_GET_REGISTER_REQUEST); + getConnectedDevices.FeatureCommand = 0x02; + + stream.Write(getConnectedDevices.AsSpan()); + stream.Read(response.AsSpan()); + + int deviceCount = response.Data01; + if (deviceCount > 0) + { + //log "Faking a reconnect to get device list" + deviceCount++; + + response = new FapResponse(); + getConnectedDevices.Init(LOGITECH_RECEIVER_ADDRESS, LOGITECH_SET_REGISTER_REQUEST); + getConnectedDevices.FeatureCommand = 0x02; + getConnectedDevices.Data0 = 0x02; + stream.Write(getConnectedDevices.AsSpan()); + + for (int i = 0; i < deviceCount; i++) + { + var devices = new FapResponse(); + stream.Read(devices.AsSpan()); + int wirelessPid = (devices.Data02 << 8) | devices.Data01; + if (devices.DeviceIndex != 0xff) + { + map.Add(wirelessPid, devices.DeviceIndex); + } + } + } + } + + return map; + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs index d45f0ae..6e964c9 100644 --- a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs +++ b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs @@ -7,6 +7,7 @@ using System.Linq; using HidSharp; using RGB.NET.Core; using RGB.NET.Devices.Logitech.Native; +using RGB.NET.Devices.Logitech.HID; using RGB.NET.HID; namespace RGB.NET.Devices.Logitech @@ -43,51 +44,93 @@ namespace RGB.NET.Devices.Logitech private const int VENDOR_ID = 0x046D; /// - /// Gets the HID-definitions for per-key-devices. + /// Gets the HID-definitions for wired per-key-devices. /// public static HIDLoader PerKeyDeviceDefinitions { get; } = new(VENDOR_ID) { { 0xC32B, RGBDeviceType.Keyboard, "G910", LedMappings.PerKey, 0 }, - { 0xC335, RGBDeviceType.Keyboard, "G910v2", LedMappings.PerKey, 0 }, - { 0xC541, RGBDeviceType.Keyboard, "G915", LedMappings.PerKey, 0 }, - { 0xC33F, RGBDeviceType.Keyboard, "G815", LedMappings.PerKey, 0 }, - { 0xC337, RGBDeviceType.Keyboard, "G810", LedMappings.PerKey, 0 }, + { 0xC330, RGBDeviceType.Keyboard, "G410", LedMappings.PerKey, 0 }, { 0xC331, RGBDeviceType.Keyboard, "G810", LedMappings.PerKey, 0 }, + { 0xC335, RGBDeviceType.Keyboard, "G910v2", LedMappings.PerKey, 0 }, + { 0xC337, RGBDeviceType.Keyboard, "G810", LedMappings.PerKey, 0 }, + { 0xC339, RGBDeviceType.Keyboard, "Pro", LedMappings.PerKey, 0 }, + { 0xC33C, RGBDeviceType.Keyboard, "G513", LedMappings.PerKey, 0 }, + { 0xC33E, RGBDeviceType.Keyboard, "G915", LedMappings.PerKey, 0 }, + { 0xC33F, RGBDeviceType.Keyboard, "G815", LedMappings.PerKey, 0 }, + { 0xC342, RGBDeviceType.Keyboard, "G512", LedMappings.PerKey, 0 }, + { 0xC343, RGBDeviceType.Keyboard, "G915 TKL", LedMappings.PerKey, 0 }, + { 0xC541, RGBDeviceType.Keyboard, "G915", LedMappings.PerKey, 0 }, + + //non-rgb { 0xC333, RGBDeviceType.Keyboard, "G610", LedMappings.PerKey, 0 }, { 0xC338, RGBDeviceType.Keyboard, "G610", LedMappings.PerKey, 0 }, - { 0xC342, RGBDeviceType.Keyboard, "G512 SE", LedMappings.PerKey, 0 }, - { 0xC33C, RGBDeviceType.Keyboard, "G513 Carbon", LedMappings.PerKey, 0 }, - { 0xC330, RGBDeviceType.Keyboard, "G410", LedMappings.PerKey, 0 }, - { 0xC339, RGBDeviceType.Keyboard, "Pro", LedMappings.PerKey, 0 }, - { 0xC343, RGBDeviceType.Keyboard, "G915 TKL", LedMappings.PerKey, 0 }, - { 0xC545, RGBDeviceType.Keyboard, "Lightspeed Keyboard Dongle", LedMappings.PerKey, 0 }, }; /// - /// Gets the HID-definitions for per-zone-devices. + /// Gets the HID-definitions for wireless per-key-devices. + /// + public static LightspeedHIDLoader PerKeyWirelessDeviceDefinitions { get; } = new() + { + { 0x407C, RGBDeviceType.Keyboard, "G915", LedMappings.PerKey, 0 }, + { 0x408E, RGBDeviceType.Keyboard, "G915 TKL", LedMappings.PerKey, 0 }, + }; + + /// + /// Gets the HID-definitions for wired per-zone-devices. /// public static HIDLoader PerZoneDeviceDefinitions { get; } = new(VENDOR_ID) { - { 0xC336, RGBDeviceType.Keyboard, "G213", LedMappings.ZoneKeyboard, (LogitechDeviceType.Keyboard, 2) }, - { 0xC086, RGBDeviceType.Mouse, "G903", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, - { 0xC081, RGBDeviceType.Mouse, "G900", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, - { 0xC539, RGBDeviceType.Mouse, "Lightspeed Mouse Dongle", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, - { 0xC087, RGBDeviceType.Mouse, "G703", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, - { 0xC08B, RGBDeviceType.Mouse, "G502 HERO", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, - { 0xC08D, RGBDeviceType.Mouse, "G502 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, - { 0xC332, RGBDeviceType.Mouse, "G502", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, - { 0xC083, RGBDeviceType.Mouse, "G403", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC336, RGBDeviceType.Keyboard, "G213", LedMappings.ZoneKeyboard, (LogitechDeviceType.Keyboard, 5) }, + + { 0xC092, RGBDeviceType.Mouse, "G203 LIGHTSYNC", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 1) }, { 0xC080, RGBDeviceType.Mouse, "G303", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC081, RGBDeviceType.Mouse, "G900", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC082, RGBDeviceType.Mouse, "G403", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC083, RGBDeviceType.Mouse, "G403", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, { 0xC084, RGBDeviceType.Mouse, "G203", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 1) }, { 0xC085, RGBDeviceType.Mouse, "G Pro", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 1) }, + { 0xC086, RGBDeviceType.Mouse, "G903", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC087, RGBDeviceType.Mouse, "G703", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, { 0xC088, RGBDeviceType.Mouse, "G Pro Wireless", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC08B, RGBDeviceType.Mouse, "G502 HERO", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, { 0xC08C, RGBDeviceType.Mouse, "G Pro Hero", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 1) }, + { 0xC08D, RGBDeviceType.Mouse, "G502 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC08F, RGBDeviceType.Mouse, "G403 HERO", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC090, RGBDeviceType.Mouse, "G703 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC091, RGBDeviceType.Mouse, "G903 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0xC24A, RGBDeviceType.Mouse, "G600", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 1) }, + { 0xC332, RGBDeviceType.Mouse, "G502", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + + { 0xC53A, RGBDeviceType.Mousepad, "POWERPLAY", LedMappings.Device, (LogitechDeviceType.Mousemat, 1) }, + + //G633 and G635 are wired headsets. { 0x0A5C, RGBDeviceType.Headset, "G633", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) }, + { 0x0A89, RGBDeviceType.Headset, "G635", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) }, + + //The other 3 are wireless. These PIDs correpond to the dongles. They cannot be used wired. { 0x0A5B, RGBDeviceType.Headset, "G933", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) }, { 0x0A87, RGBDeviceType.Headset, "G935", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) }, + { 0x0AB5, RGBDeviceType.Headset, "G733", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) },//fix + { 0x0A78, RGBDeviceType.Speaker, "G560", LedMappings.ZoneSpeaker, (LogitechDeviceType.Speaker, 4) }, }; + /// + /// Gets the HID-definitions for wireless per-zone-devices. + /// + public static LightspeedHIDLoader PerZoneWirelessDeviceDefinitions { get; } = new() + { + { 0x4053, RGBDeviceType.Mouse, "G900", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0x405D, RGBDeviceType.Mouse, "G403", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0x4067, RGBDeviceType.Mouse, "G903", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0x4070, RGBDeviceType.Mouse, "G703", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0x4079, RGBDeviceType.Mouse, "G Pro Wireless", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0x407F, RGBDeviceType.Mouse, "G502 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0x4086, RGBDeviceType.Mouse, "G703 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0x4087, RGBDeviceType.Mouse, "G903 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, + { 0x405F, RGBDeviceType.Mousepad, "POWERPLAY", LedMappings.ZoneMousepad,(LogitechDeviceType.Mousemat, 1) }, + }; + /// /// Gets the HID-definitions for per-device-devices. /// @@ -105,9 +148,14 @@ namespace RGB.NET.Devices.Logitech { 0xC248, RGBDeviceType.Keyboard, "G105", LedMappings.Device, 0 }, { 0xC222, RGBDeviceType.Keyboard, "G15", LedMappings.Device, 0 }, { 0xC225, RGBDeviceType.Keyboard, "G11", LedMappings.Device, 0 }, - { 0x0AB5, RGBDeviceType.Headset, "G733", LedMappings.Device, 0 }, }; + public static LightspeedHIDLoader PerDeviceWirelessDeviceDefinitions { get; } = new() + { + + }; + + #endregion #region Constructors @@ -147,29 +195,31 @@ namespace RGB.NET.Devices.Logitech return base.GetLoadedDevices(loadFilter); } - + /// protected override IEnumerable LoadDevices() { - (HIDDeviceDefinition definition, HidDevice device) perKeyDevice = PerKeyDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); - if ((_perKeyUpdateQueue != null) && (perKeyDevice != default)) + HIDDeviceDefinition? perKeyDeviceDefinition = PerKeyDeviceDefinitions.GetConnectedDevices().FirstOrDefault().definition ?? + PerKeyWirelessDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); + if ((_perKeyUpdateQueue != null) && (perKeyDeviceDefinition != default)) { - (HIDDeviceDefinition definition, _) = perKeyDevice; - yield return new LogitechPerKeyRGBDevice(new LogitechRGBDeviceInfo(definition.DeviceType, definition.Name, LogitechDeviceCaps.PerKeyRGB, 0), _perKeyUpdateQueue, definition.LedMapping); + yield return new LogitechPerKeyRGBDevice(new LogitechRGBDeviceInfo(perKeyDeviceDefinition.DeviceType, perKeyDeviceDefinition.Name, LogitechDeviceCaps.PerKeyRGB, 0), _perKeyUpdateQueue, perKeyDeviceDefinition.LedMapping); } - IEnumerable<(HIDDeviceDefinition definition, HidDevice device)> perZoneDevices = PerZoneDeviceDefinitions.GetConnectedDevices(x => x.CustomData.deviceType); - foreach ((HIDDeviceDefinition definition, _) in perZoneDevices) + IEnumerable> wiredPerZoneDevices = PerZoneDeviceDefinitions.GetConnectedDevices().Select(x => x.definition); + IEnumerable> wirelessPerZoneDevices = PerZoneWirelessDeviceDefinitions.GetConnectedDevices(); + var wiredAndWirelessPerZoneDevices = wiredPerZoneDevices.Concat(wirelessPerZoneDevices); + foreach (HIDDeviceDefinition definition in wiredAndWirelessPerZoneDevices.GroupBy(x => x.CustomData.deviceType).Select(group => group.First())) { LogitechZoneUpdateQueue updateQueue = new(GetUpdateTrigger(), definition.CustomData.deviceType); yield return new LogitechZoneRGBDevice(new LogitechRGBDeviceInfo(definition.DeviceType, definition.Name, LogitechDeviceCaps.DeviceRGB, definition.CustomData.zones), updateQueue, definition.LedMapping); } - (HIDDeviceDefinition definition, HidDevice device) perDeviceDevice = PerDeviceDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); - if ((_perDeviceUpdateQueue != null) && (perDeviceDevice != default)) + HIDDeviceDefinition? perDeviceDeviceDefinition = PerDeviceDeviceDefinitions.GetConnectedDevices().FirstOrDefault().definition ?? + PerDeviceWirelessDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); + if ((_perDeviceUpdateQueue != null) && (perDeviceDeviceDefinition != default)) { - (HIDDeviceDefinition definition, _) = perDeviceDevice; - yield return new LogitechPerDeviceRGBDevice(new LogitechRGBDeviceInfo(definition.DeviceType, definition.Name, LogitechDeviceCaps.DeviceRGB, 0), _perDeviceUpdateQueue, definition.LedMapping); + yield return new LogitechPerDeviceRGBDevice(new LogitechRGBDeviceInfo(perDeviceDeviceDefinition.DeviceType, perDeviceDeviceDefinition.Name, LogitechDeviceCaps.DeviceRGB, 0), _perDeviceUpdateQueue, perDeviceDeviceDefinition.LedMapping); } } From e06857e2364be842459468edc841ce30898ddaa9 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Wed, 22 Sep 2021 17:56:53 +0100 Subject: [PATCH 2/5] Removed wireless POWERPLAY definition --- RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs index 6e964c9..a83b732 100644 --- a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs +++ b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs @@ -101,7 +101,7 @@ namespace RGB.NET.Devices.Logitech { 0xC24A, RGBDeviceType.Mouse, "G600", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 1) }, { 0xC332, RGBDeviceType.Mouse, "G502", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, - { 0xC53A, RGBDeviceType.Mousepad, "POWERPLAY", LedMappings.Device, (LogitechDeviceType.Mousemat, 1) }, + { 0xC53A, RGBDeviceType.Mousepad, "POWERPLAY", LedMappings.ZoneMousepad, (LogitechDeviceType.Mousemat, 1) }, //G633 and G635 are wired headsets. { 0x0A5C, RGBDeviceType.Headset, "G633", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) }, @@ -128,7 +128,6 @@ namespace RGB.NET.Devices.Logitech { 0x407F, RGBDeviceType.Mouse, "G502 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, { 0x4086, RGBDeviceType.Mouse, "G703 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, { 0x4087, RGBDeviceType.Mouse, "G903 Lightspeed", LedMappings.ZoneMouse, (LogitechDeviceType.Mouse, 2) }, - { 0x405F, RGBDeviceType.Mousepad, "POWERPLAY", LedMappings.ZoneMousepad,(LogitechDeviceType.Mousemat, 1) }, }; /// From a04018fef1e0e023a972b16ea7a72da6238ae82e Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Thu, 23 Sep 2021 22:04:54 +0100 Subject: [PATCH 3/5] Use explicit types instad of var --- RGB.NET.Devices.Logitech/HID/Extensions.cs | 17 ++++++------- .../HID/LightspeedHidLoader.cs | 24 +++++++++---------- .../LogitechDeviceProvider.cs | 2 +- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/RGB.NET.Devices.Logitech/HID/Extensions.cs b/RGB.NET.Devices.Logitech/HID/Extensions.cs index 30cc874..4a0bf68 100644 --- a/RGB.NET.Devices.Logitech/HID/Extensions.cs +++ b/RGB.NET.Devices.Logitech/HID/Extensions.cs @@ -3,6 +3,7 @@ using HidSharp.Reports.Encodings; using System; using System.Linq; using System.Runtime.InteropServices; +using System.Collections.Generic; namespace RGB.NET.Devices.Logitech.HID { @@ -18,10 +19,10 @@ namespace RGB.NET.Devices.Logitech.HID { try { - var descriptor = device.GetRawReportDescriptor(); - var decodedItems = EncodedItem.DecodeItems(descriptor, 0, descriptor.Length); - var usefulItems = decodedItems.Where(de => de.TagForLocal == LocalItemTag.Usage && de.TagForGlobal == GlobalItemTag.UsagePage); - var usagePage = usefulItems.FirstOrDefault(de => de.ItemType == ItemType.Global); + byte[]? descriptor = device.GetRawReportDescriptor(); + IEnumerable? decodedItems = EncodedItem.DecodeItems(descriptor, 0, descriptor.Length); + IEnumerable? usefulItems = decodedItems.Where(de => de.TagForLocal == LocalItemTag.Usage && de.TagForGlobal == GlobalItemTag.UsagePage); + EncodedItem? usagePage = usefulItems.FirstOrDefault(de => de.ItemType == ItemType.Global); return usagePage.DataValue; } catch @@ -34,10 +35,10 @@ namespace RGB.NET.Devices.Logitech.HID { try { - var descriptor = device.GetRawReportDescriptor(); - var decodedItems = EncodedItem.DecodeItems(descriptor, 0, descriptor.Length); - var usefulItems = decodedItems.Where(de => de.TagForLocal == LocalItemTag.Usage && de.TagForGlobal == GlobalItemTag.UsagePage); - var usage = usefulItems.FirstOrDefault(de => de.ItemType == ItemType.Local); + byte[]? descriptor = device.GetRawReportDescriptor(); + IEnumerable? decodedItems = EncodedItem.DecodeItems(descriptor, 0, descriptor.Length); + IEnumerable? usefulItems = decodedItems.Where(de => de.TagForLocal == LocalItemTag.Usage && de.TagForGlobal == GlobalItemTag.UsagePage); + EncodedItem? usage = usefulItems.FirstOrDefault(de => de.ItemType == ItemType.Local); return usage.DataValue; } catch diff --git a/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs b/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs index eb2bcc9..2edff17 100644 --- a/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs +++ b/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs @@ -56,7 +56,7 @@ namespace RGB.NET.Devices.Logitech.HID /// The enumerable containing the connected devices. public IEnumerable> GetConnectedDevices() { - foreach (var device in Detect()) + foreach (int device in Detect()) { if (_deviceDefinitions.TryGetValue(device, out HIDDeviceDefinition? definition)) if (LoadFilter.HasFlag(definition.DeviceType)) @@ -86,9 +86,9 @@ namespace RGB.NET.Devices.Logitech.HID private IEnumerable Detect() { - foreach (var receiverPid in ReceiverPids) + foreach (int receiverPid in ReceiverPids) { - foreach (var wirelessPid in Detect(receiverPid)) + foreach (int wirelessPid in Detect(receiverPid)) { yield return wirelessPid; } @@ -97,17 +97,17 @@ namespace RGB.NET.Devices.Logitech.HID private IEnumerable Detect(int pid) { - var receiverDevices = DeviceList.Local.GetHidDevices(VendorId, pid); - var interfaceTwo = receiverDevices.Where(d => d.DevicePath.Contains("mi_02")); + IEnumerable? receiverDevices = DeviceList.Local.GetHidDevices(VendorId, pid); + IEnumerable? interfaceTwo = receiverDevices.Where(d => d.DevicePath.Contains("mi_02")); //this is terrible but i don't know how else to filter interfaces Dictionary deviceUsages = new(); - foreach (var item in interfaceTwo) + foreach (HidDevice? item in interfaceTwo) { deviceUsages.Add((byte)item.GetUsage(), item); } - foreach ((var wirelessPid, var deviceIndex) in GetWirelessDevices(deviceUsages)) + foreach ((int wirelessPid, byte deviceIndex) in GetWirelessDevices(deviceUsages)) { yield return wirelessPid; } @@ -121,13 +121,13 @@ namespace RGB.NET.Devices.Logitech.HID Dictionary map = new(); - if (device_usages.TryGetValue(1, out var device)) + if (device_usages.TryGetValue(1, out HidDevice? device)) { - var stream = device.Open(); + HidStream? stream = device.Open(); - var response = new FapResponse(); + FapResponse response = new FapResponse(); - var getConnectedDevices = new FapShortRequest(); + FapShortRequest getConnectedDevices = new FapShortRequest(); getConnectedDevices.Init(LOGITECH_RECEIVER_ADDRESS, LOGITECH_GET_REGISTER_REQUEST); stream.Write(getConnectedDevices.AsSpan()); @@ -172,7 +172,7 @@ namespace RGB.NET.Devices.Logitech.HID for (int i = 0; i < deviceCount; i++) { - var devices = new FapResponse(); + FapResponse devices = new FapResponse(); stream.Read(devices.AsSpan()); int wirelessPid = (devices.Data02 << 8) | devices.Data01; if (devices.DeviceIndex != 0xff) diff --git a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs index a83b732..1dc0cc4 100644 --- a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs +++ b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs @@ -207,7 +207,7 @@ namespace RGB.NET.Devices.Logitech IEnumerable> wiredPerZoneDevices = PerZoneDeviceDefinitions.GetConnectedDevices().Select(x => x.definition); IEnumerable> wirelessPerZoneDevices = PerZoneWirelessDeviceDefinitions.GetConnectedDevices(); - var wiredAndWirelessPerZoneDevices = wiredPerZoneDevices.Concat(wirelessPerZoneDevices); + IEnumerable>? wiredAndWirelessPerZoneDevices = wiredPerZoneDevices.Concat(wirelessPerZoneDevices); foreach (HIDDeviceDefinition definition in wiredAndWirelessPerZoneDevices.GroupBy(x => x.CustomData.deviceType).Select(group => group.First())) { LogitechZoneUpdateQueue updateQueue = new(GetUpdateTrigger(), definition.CustomData.deviceType); From afb68f1277dfda1584057eadfbe654fe76e53f27 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sun, 26 Sep 2021 20:30:31 +0200 Subject: [PATCH 4/5] Refactorings to better fit general code-style; Fix for device-loading --- RGB.NET.Devices.Logitech/HID/Extensions.cs | 30 +++---- RGB.NET.Devices.Logitech/HID/FapResponse.cs | 2 +- .../HID/FapShortRequest.cs | 21 ++++- .../HID/LightspeedHidLoader.cs | 81 +++++++++---------- .../LogitechDeviceProvider.cs | 63 +++++++++++---- 5 files changed, 116 insertions(+), 81 deletions(-) diff --git a/RGB.NET.Devices.Logitech/HID/Extensions.cs b/RGB.NET.Devices.Logitech/HID/Extensions.cs index 4a0bf68..0f04602 100644 --- a/RGB.NET.Devices.Logitech/HID/Extensions.cs +++ b/RGB.NET.Devices.Logitech/HID/Extensions.cs @@ -3,27 +3,23 @@ using HidSharp.Reports.Encodings; using System; using System.Linq; using System.Runtime.InteropServices; -using System.Collections.Generic; namespace RGB.NET.Devices.Logitech.HID { - public static class Extensions + internal static class Extensions { - public static Span AsSpan(this ref T val) where T : unmanaged + internal static Span AsSpan(this ref T val) + where T : unmanaged { Span valSpan = MemoryMarshal.CreateSpan(ref val, 1); return MemoryMarshal.Cast(valSpan); } - public static uint GetUsagePage(this HidDevice device) + internal static uint GetUsagePage(this HidDevice device) { try { - byte[]? descriptor = device.GetRawReportDescriptor(); - IEnumerable? decodedItems = EncodedItem.DecodeItems(descriptor, 0, descriptor.Length); - IEnumerable? usefulItems = decodedItems.Where(de => de.TagForLocal == LocalItemTag.Usage && de.TagForGlobal == GlobalItemTag.UsagePage); - EncodedItem? usagePage = usefulItems.FirstOrDefault(de => de.ItemType == ItemType.Global); - return usagePage.DataValue; + return device.GetItemByType(ItemType.Global)?.DataValue ?? uint.MaxValue; } catch { @@ -31,20 +27,24 @@ namespace RGB.NET.Devices.Logitech.HID } } - public static uint GetUsage(this HidDevice device) + internal static uint GetUsage(this HidDevice device) { try { - byte[]? descriptor = device.GetRawReportDescriptor(); - IEnumerable? decodedItems = EncodedItem.DecodeItems(descriptor, 0, descriptor.Length); - IEnumerable? usefulItems = decodedItems.Where(de => de.TagForLocal == LocalItemTag.Usage && de.TagForGlobal == GlobalItemTag.UsagePage); - EncodedItem? usage = usefulItems.FirstOrDefault(de => de.ItemType == ItemType.Local); - return usage.DataValue; + return device.GetItemByType(ItemType.Local)?.DataValue ?? uint.MaxValue; } catch { return uint.MaxValue; } } + + private static EncodedItem? GetItemByType(this HidDevice device, ItemType itemType) + { + byte[] descriptor = device.GetRawReportDescriptor(); + return EncodedItem.DecodeItems(descriptor, 0, descriptor.Length) + .Where(de => (de.TagForLocal == LocalItemTag.Usage) && (de.TagForGlobal == GlobalItemTag.UsagePage)) + .FirstOrDefault(de => de.ItemType == itemType); + } } } diff --git a/RGB.NET.Devices.Logitech/HID/FapResponse.cs b/RGB.NET.Devices.Logitech/HID/FapResponse.cs index 010c67d..f0379a3 100644 --- a/RGB.NET.Devices.Logitech/HID/FapResponse.cs +++ b/RGB.NET.Devices.Logitech/HID/FapResponse.cs @@ -3,7 +3,7 @@ namespace RGB.NET.Devices.Logitech.HID { [StructLayout(LayoutKind.Sequential, Pack = 0, Size = 64)] - public struct FapResponse + internal struct FapResponse { public byte Command; public byte DeviceIndex; diff --git a/RGB.NET.Devices.Logitech/HID/FapShortRequest.cs b/RGB.NET.Devices.Logitech/HID/FapShortRequest.cs index c76f2b7..f7a687f 100644 --- a/RGB.NET.Devices.Logitech/HID/FapShortRequest.cs +++ b/RGB.NET.Devices.Logitech/HID/FapShortRequest.cs @@ -3,9 +3,15 @@ namespace RGB.NET.Devices.Logitech.HID { [StructLayout(LayoutKind.Sequential, Pack = 0, Size = 7)] - public struct FapShortRequest + internal struct FapShortRequest { - const byte LOGITECH_SHORT_MESSAGE = 0x10; + #region Constants + + private const byte LOGITECH_SHORT_MESSAGE = 0x10; + + #endregion + + #region Properties & Fields public byte ReportId; public byte DeviceIndex; @@ -15,15 +21,22 @@ namespace RGB.NET.Devices.Logitech.HID public byte Data1; public byte Data2; + #endregion + + #region Constructors + public void Init(byte deviceIndex, byte featureIndex) { + this.DeviceIndex = deviceIndex; + this.FeatureIndex = featureIndex; + ReportId = LOGITECH_SHORT_MESSAGE; - DeviceIndex = deviceIndex; - FeatureIndex = featureIndex; FeatureCommand = 0; Data0 = 0; Data1 = 0; Data2 = 0; } + + #endregion } } diff --git a/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs b/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs index 2edff17..d90b5ac 100644 --- a/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs +++ b/RGB.NET.Devices.Logitech/HID/LightspeedHidLoader.cs @@ -5,14 +5,32 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace RGB.NET.Devices.Logitech.HID { + /// + /// Represents a loaded for logitech HID-devices. + /// + /// The type of the identifier leds are mapped to. + /// The type of the custom data added to the HID-device. public class LightspeedHIDLoader : IEnumerable> where TLed : notnull { + #region Constants + + private const int VENDOR_ID = 0x046D; + + // ReSharper disable once StaticMemberInGenericType - This is used like a const + private static readonly List RECEIVER_PIDS = new() + { + 0xC539, + 0xC53A, + 0xC541, + 0xC545 + }; + + #endregion + #region Properties & Fields private readonly Dictionary> _deviceDefinitions = new(); @@ -20,21 +38,13 @@ namespace RGB.NET.Devices.Logitech.HID /// /// Gets the vendor id used for this loader. /// - public int VendorId => 0x046d; + public int VendorId => VENDOR_ID; /// /// Gets or sets the filter used to determine which devices should be loaded. /// public RGBDeviceType LoadFilter { get; set; } = RGBDeviceType.All; - private static List ReceiverPids { get; } = new() - { - 0xC539, - 0xC53A, - 0xC541, - 0xC545 - }; - #endregion #region Methods @@ -72,7 +82,7 @@ namespace RGB.NET.Devices.Logitech.HID /// The function grouping the devices. /// The enumerable containing the selected devices. public IEnumerable> GetConnectedDevices(Func, TKey> groupBy) - => GetConnectedDevices().GroupBy(x => groupBy(x)) + => GetConnectedDevices().GroupBy(groupBy) .Select(group => group.First()); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -84,36 +94,20 @@ namespace RGB.NET.Devices.Logitech.HID #region Private Methods - private IEnumerable Detect() - { - foreach (int receiverPid in ReceiverPids) - { - foreach (int wirelessPid in Detect(receiverPid)) - { - yield return wirelessPid; - } - } - } + private IEnumerable Detect() => RECEIVER_PIDS.SelectMany(Detect); private IEnumerable Detect(int pid) { - IEnumerable? receiverDevices = DeviceList.Local.GetHidDevices(VendorId, pid); - IEnumerable? interfaceTwo = receiverDevices.Where(d => d.DevicePath.Contains("mi_02")); - //this is terrible but i don't know how else to filter interfaces + Dictionary deviceUsages = DeviceList.Local + .GetHidDevices(VendorId, pid) + .Where(d => d.DevicePath.Contains("mi_02")) + .ToDictionary(x => (byte)x.GetUsage(), x => x); - Dictionary deviceUsages = new(); - foreach (HidDevice? item in interfaceTwo) - { - deviceUsages.Add((byte)item.GetUsage(), item); - } - - foreach ((int wirelessPid, byte deviceIndex) in GetWirelessDevices(deviceUsages)) - { + foreach ((int wirelessPid, byte _) in GetWirelessDevices(deviceUsages)) yield return wirelessPid; - } } - private Dictionary GetWirelessDevices(Dictionary device_usages) + private Dictionary GetWirelessDevices(IReadOnlyDictionary deviceUsages) { const byte LOGITECH_RECEIVER_ADDRESS = 0xFF; const byte LOGITECH_SET_REGISTER_REQUEST = 0x80; @@ -121,20 +115,20 @@ namespace RGB.NET.Devices.Logitech.HID Dictionary map = new(); - if (device_usages.TryGetValue(1, out HidDevice? device)) + if (deviceUsages.TryGetValue(1, out HidDevice? device)) { HidStream? stream = device.Open(); - FapResponse response = new FapResponse(); + FapResponse response = new(); - FapShortRequest getConnectedDevices = new FapShortRequest(); + FapShortRequest getConnectedDevices = new(); getConnectedDevices.Init(LOGITECH_RECEIVER_ADDRESS, LOGITECH_GET_REGISTER_REQUEST); stream.Write(getConnectedDevices.AsSpan()); stream.Read(response.AsSpan()); - bool wireless_notifications = (response.Data01 & 1) == 1; - if (!wireless_notifications) + bool wirelessNotifications = (response.Data01 & 1) == 1; + if (!wirelessNotifications) { response = new FapResponse(); @@ -163,8 +157,7 @@ namespace RGB.NET.Devices.Logitech.HID { //log "Faking a reconnect to get device list" deviceCount++; - - response = new FapResponse(); + getConnectedDevices.Init(LOGITECH_RECEIVER_ADDRESS, LOGITECH_SET_REGISTER_REQUEST); getConnectedDevices.FeatureCommand = 0x02; getConnectedDevices.Data0 = 0x02; @@ -172,13 +165,11 @@ namespace RGB.NET.Devices.Logitech.HID for (int i = 0; i < deviceCount; i++) { - FapResponse devices = new FapResponse(); + FapResponse devices = new(); stream.Read(devices.AsSpan()); int wirelessPid = (devices.Data02 << 8) | devices.Data01; if (devices.DeviceIndex != 0xff) - { map.Add(wirelessPid, devices.DeviceIndex); - } } } } diff --git a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs index 1dc0cc4..590911b 100644 --- a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs +++ b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs @@ -131,7 +131,7 @@ namespace RGB.NET.Devices.Logitech }; /// - /// Gets the HID-definitions for per-device-devices. + /// Gets the HID-definitions for wired per-device-devices. /// public static HIDLoader PerDeviceDeviceDefinitions { get; } = new(VENDOR_ID) { @@ -149,12 +149,12 @@ namespace RGB.NET.Devices.Logitech { 0xC225, RGBDeviceType.Keyboard, "G11", LedMappings.Device, 0 }, }; + /// + /// Gets the HID-definitions for wireless per-device-devices. + /// public static LightspeedHIDLoader PerDeviceWirelessDeviceDefinitions { get; } = new() - { - - }; - - + { }; + #endregion #region Constructors @@ -198,28 +198,59 @@ namespace RGB.NET.Devices.Logitech /// protected override IEnumerable LoadDevices() { - HIDDeviceDefinition? perKeyDeviceDefinition = PerKeyDeviceDefinitions.GetConnectedDevices().FirstOrDefault().definition ?? - PerKeyWirelessDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); - if ((_perKeyUpdateQueue != null) && (perKeyDeviceDefinition != default)) + #region PerKey + + if (_perKeyUpdateQueue != null) { - yield return new LogitechPerKeyRGBDevice(new LogitechRGBDeviceInfo(perKeyDeviceDefinition.DeviceType, perKeyDeviceDefinition.Name, LogitechDeviceCaps.PerKeyRGB, 0), _perKeyUpdateQueue, perKeyDeviceDefinition.LedMapping); + (HIDDeviceDefinition definition, HidDevice device) perKeyDevice = PerKeyDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); + if (perKeyDevice != default) + { + (HIDDeviceDefinition definition, _) = perKeyDevice; + yield return new LogitechPerKeyRGBDevice(new LogitechRGBDeviceInfo(definition.DeviceType, definition.Name, LogitechDeviceCaps.PerKeyRGB, 0), _perKeyUpdateQueue, definition.LedMapping); + } + else + { + HIDDeviceDefinition? perKeyWirelessDevice = PerKeyWirelessDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); + if (perKeyWirelessDevice != null) + yield return new LogitechPerKeyRGBDevice(new LogitechRGBDeviceInfo(perKeyWirelessDevice.DeviceType, perKeyWirelessDevice.Name, LogitechDeviceCaps.PerKeyRGB, 0), _perKeyUpdateQueue, perKeyWirelessDevice.LedMapping); + } } + #endregion + + #region PerZone + IEnumerable> wiredPerZoneDevices = PerZoneDeviceDefinitions.GetConnectedDevices().Select(x => x.definition); IEnumerable> wirelessPerZoneDevices = PerZoneWirelessDeviceDefinitions.GetConnectedDevices(); - IEnumerable>? wiredAndWirelessPerZoneDevices = wiredPerZoneDevices.Concat(wirelessPerZoneDevices); - foreach (HIDDeviceDefinition definition in wiredAndWirelessPerZoneDevices.GroupBy(x => x.CustomData.deviceType).Select(group => group.First())) + foreach (HIDDeviceDefinition definition in wiredPerZoneDevices.Concat(wirelessPerZoneDevices) + .GroupBy(x => x.CustomData.deviceType) + .Select(group => group.First())) { LogitechZoneUpdateQueue updateQueue = new(GetUpdateTrigger(), definition.CustomData.deviceType); yield return new LogitechZoneRGBDevice(new LogitechRGBDeviceInfo(definition.DeviceType, definition.Name, LogitechDeviceCaps.DeviceRGB, definition.CustomData.zones), updateQueue, definition.LedMapping); } - HIDDeviceDefinition? perDeviceDeviceDefinition = PerDeviceDeviceDefinitions.GetConnectedDevices().FirstOrDefault().definition ?? - PerDeviceWirelessDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); - if ((_perDeviceUpdateQueue != null) && (perDeviceDeviceDefinition != default)) + #endregion + + #region PerDevice + + if (_perDeviceUpdateQueue != null) { - yield return new LogitechPerDeviceRGBDevice(new LogitechRGBDeviceInfo(perDeviceDeviceDefinition.DeviceType, perDeviceDeviceDefinition.Name, LogitechDeviceCaps.DeviceRGB, 0), _perDeviceUpdateQueue, perDeviceDeviceDefinition.LedMapping); + (HIDDeviceDefinition definition, HidDevice device) perDeviceDevice = PerDeviceDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); + if (perDeviceDevice != default) + { + (HIDDeviceDefinition definition, _) = perDeviceDevice; + yield return new LogitechPerDeviceRGBDevice(new LogitechRGBDeviceInfo(definition.DeviceType, definition.Name, LogitechDeviceCaps.DeviceRGB, 0), _perDeviceUpdateQueue, definition.LedMapping); + } + else + { + HIDDeviceDefinition? perDeviceWirelessDevice = PerDeviceWirelessDeviceDefinitions.GetConnectedDevices().FirstOrDefault(); + if (perDeviceWirelessDevice != null) + yield return new LogitechPerDeviceRGBDevice(new LogitechRGBDeviceInfo(perDeviceWirelessDevice.DeviceType, perDeviceWirelessDevice.Name, LogitechDeviceCaps.DeviceRGB, 0), _perDeviceUpdateQueue, perDeviceWirelessDevice.LedMapping); + } } + + #endregion } /// From 4b6c341185241dd05d25baf4033ea5ed57001d06 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Sun, 26 Sep 2021 21:24:58 +0100 Subject: [PATCH 5/5] Moved G733 definition to PerDevice --- RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs index 590911b..54ef43a 100644 --- a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs +++ b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs @@ -107,10 +107,9 @@ namespace RGB.NET.Devices.Logitech { 0x0A5C, RGBDeviceType.Headset, "G633", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) }, { 0x0A89, RGBDeviceType.Headset, "G635", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) }, - //The other 3 are wireless. These PIDs correpond to the dongles. They cannot be used wired. + //The other ones are wireless only. These PIDs correpond to the dongles. { 0x0A5B, RGBDeviceType.Headset, "G933", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) }, { 0x0A87, RGBDeviceType.Headset, "G935", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) }, - { 0x0AB5, RGBDeviceType.Headset, "G733", LedMappings.ZoneHeadset, (LogitechDeviceType.Headset, 2) },//fix { 0x0A78, RGBDeviceType.Speaker, "G560", LedMappings.ZoneSpeaker, (LogitechDeviceType.Speaker, 4) }, }; @@ -147,6 +146,7 @@ namespace RGB.NET.Devices.Logitech { 0xC248, RGBDeviceType.Keyboard, "G105", LedMappings.Device, 0 }, { 0xC222, RGBDeviceType.Keyboard, "G15", LedMappings.Device, 0 }, { 0xC225, RGBDeviceType.Keyboard, "G11", LedMappings.Device, 0 }, + { 0x0AB5, RGBDeviceType.Headset, "G733", LedMappings.Device, 0 }, }; ///