diff --git a/RGB.NET.Devices.Logitech/Enum/LogitechDeviceType.cs b/RGB.NET.Devices.Logitech/Enum/LogitechDeviceType.cs
new file mode 100644
index 0000000..6697b2d
--- /dev/null
+++ b/RGB.NET.Devices.Logitech/Enum/LogitechDeviceType.cs
@@ -0,0 +1,11 @@
+namespace RGB.NET.Devices.Logitech
+{
+ public enum LogitechDeviceType
+ {
+ Keyboard = 0x0,
+ Mouse = 0x3,
+ Mousemat = 0x4,
+ Headset = 0x8,
+ Speaker = 0xE
+ }
+}
diff --git a/RGB.NET.Devices.Logitech/Generic/LogitechRGBDevice.cs b/RGB.NET.Devices.Logitech/Generic/LogitechRGBDevice.cs
index edcbd29..b8f6eab 100644
--- a/RGB.NET.Devices.Logitech/Generic/LogitechRGBDevice.cs
+++ b/RGB.NET.Devices.Logitech/Generic/LogitechRGBDevice.cs
@@ -18,7 +18,7 @@ namespace RGB.NET.Devices.Logitech
/// Gets information about the .
///
public override TDeviceInfo DeviceInfo { get; }
-
+
///
/// Gets or sets the update queue performing updates for this device.
///
@@ -64,6 +64,7 @@ namespace RGB.NET.Devices.Logitech
protected virtual void InitializeLayout()
{
if (!(DeviceInfo is LogitechRGBDeviceInfo info)) return;
+
string layout = info.ImageLayout;
string layoutPath = info.LayoutPath;
ApplyLayoutFromFile(PathHelper.GetAbsolutePath($@"Layouts\Logitech\{layoutPath}.xml"), layout, true);
diff --git a/RGB.NET.Devices.Logitech/Generic/LogitechRGBDeviceInfo.cs b/RGB.NET.Devices.Logitech/Generic/LogitechRGBDeviceInfo.cs
index ae13908..a476c7f 100644
--- a/RGB.NET.Devices.Logitech/Generic/LogitechRGBDeviceInfo.cs
+++ b/RGB.NET.Devices.Logitech/Generic/LogitechRGBDeviceInfo.cs
@@ -49,6 +49,11 @@ namespace RGB.NET.Devices.Logitech
///
public LogitechDeviceCaps DeviceCaps { get; }
+ ///
+ /// Gets the amount of zones the is able to control (0 for single-color and per-key devices)
+ ///
+ public int Zones { get; }
+
///
/// Gets the layout used to decide which images to load.
///
@@ -69,14 +74,16 @@ namespace RGB.NET.Devices.Logitech
/// The type of the .
/// The represented device model.
/// The lighting-capabilities of the device.
+ /// The amount of zones the device is able to control.
/// The layout used to decide which images to load.
/// The path/name of the layout-file.
internal LogitechRGBDeviceInfo(RGBDeviceType deviceType, string model, LogitechDeviceCaps deviceCaps,
- string imageLayout, string layoutPath)
+ int zones, string imageLayout, string layoutPath)
{
this.DeviceType = deviceType;
this.Model = model;
this.DeviceCaps = deviceCaps;
+ this.Zones = zones;
this.ImageLayout = imageLayout;
this.LayoutPath = layoutPath;
diff --git a/RGB.NET.Devices.Logitech/HID/DeviceChecker.cs b/RGB.NET.Devices.Logitech/HID/DeviceChecker.cs
index dcd8043..68f7677 100644
--- a/RGB.NET.Devices.Logitech/HID/DeviceChecker.cs
+++ b/RGB.NET.Devices.Logitech/HID/DeviceChecker.cs
@@ -13,24 +13,29 @@ namespace RGB.NET.Devices.Logitech.HID
private const int VENDOR_ID = 0x046D;
//TODO DarthAffe 14.11.2017: Add devices
- private static readonly List<(string model, RGBDeviceType deviceType, int id, string imageLayout, string layoutPath)> PER_KEY_DEVICES
- = new List<(string model, RGBDeviceType deviceType, int id, string imageLayout, string layoutPath)>
- {
- ("G910", RGBDeviceType.Keyboard, 0xC32B, "DE", @"Keyboards\G910\UK"), //TODO DarthAffe 15.11.2017: Somehow detect the current layout
- ("G810", RGBDeviceType.Keyboard, 0xC337, "DE", @"Keyboards\G810\UK"),
- ("G610", RGBDeviceType.Keyboard, 0xC333, "DE", @"Keyboards\G610\UK"),
- ("Pro", RGBDeviceType.Keyboard, 0xC339, "DE", @"Keyboards\Pro\UK"),
- };
-
- private static readonly List<(string model, RGBDeviceType deviceType, int id, string imageLayout, string layoutPath)> PER_DEVICE_DEVICES
- = new List<(string model, RGBDeviceType deviceType, int id, string imageLayout, string layoutPath)>
+ private static readonly List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)> PER_KEY_DEVICES
+ = new List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)>
{
- ("G19", RGBDeviceType.Keyboard, 0xC228, "DE", @"Keyboards\G19\UK"),
- ("G903", RGBDeviceType.Mouse, 0xC086, "default", @"Mice\G903"),
- ("G403", RGBDeviceType.Mouse, 0xC083, "default", @"Mice\G403"),
- ("G502", RGBDeviceType.Mouse, 0xC332, "default", @"Mice\G502"),
- ("G600", RGBDeviceType.Mouse, 0xC24A, "default", @"Mice\G600"),
- ("G Pro", RGBDeviceType.Mouse, 0xC085, "default", @"Mice\GPro"),
+ ("G910", RGBDeviceType.Keyboard, 0xC32B, 0, "DE", @"Keyboards\G910\UK"), //TODO DarthAffe 15.11.2017: Somehow detect the current layout
+ ("G810", RGBDeviceType.Keyboard, 0xC337, 0, "DE", @"Keyboards\G810\UK"),
+ ("G610", RGBDeviceType.Keyboard, 0xC333, 0, "DE", @"Keyboards\G610\UK"),
+ ("Pro", RGBDeviceType.Keyboard, 0xC339, 0, "DE", @"Keyboards\Pro\UK"),
+ };
+
+ private static readonly List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)> PER_DEVICE_DEVICES
+ = new List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)>
+ {
+ ("G19", RGBDeviceType.Keyboard, 0xC228, 0, "DE", @"Keyboards\G19\UK"),
+ ("G502", RGBDeviceType.Mouse, 0xC332, 0, "default", @"Mice\G502"),
+ ("G600", RGBDeviceType.Mouse, 0xC24A, 0, "default", @"Mice\G600"),
+ };
+
+ private static readonly List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)> ZONE_DEVICES
+ = new List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)>
+ {
+ ("G903", RGBDeviceType.Mouse, 0xC086, 2, "default", @"Mice\G903"),
+ ("G403", RGBDeviceType.Mouse, 0xC083, 2, "default", @"Mice\G403"),
+ ("G Pro", RGBDeviceType.Mouse, 0xC085, 1, "default", @"Mice\GPro"),
};
#endregion
@@ -38,10 +43,13 @@ namespace RGB.NET.Devices.Logitech.HID
#region Properties & Fields
public static bool IsPerKeyDeviceConnected { get; private set; }
- public static (string model, RGBDeviceType deviceType, int id, string imageLayout, string layoutPath) PerKeyDeviceData { get; private set; }
+ public static (string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath) PerKeyDeviceData { get; private set; }
public static bool IsPerDeviceDeviceConnected { get; private set; }
- public static (string model, RGBDeviceType deviceType, int id, string imageLayout, string layoutPath) PerDeviceDeviceData { get; private set; }
+ public static (string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath) PerDeviceDeviceData { get; private set; }
+
+ public static bool IsZoneDeviceConnected { get; private set; }
+ public static IEnumerable<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)> ZoneDeviceData { get; private set; }
#endregion
@@ -51,7 +59,7 @@ namespace RGB.NET.Devices.Logitech.HID
{
List ids = DeviceList.Local.GetHidDevices(VENDOR_ID).Select(x => x.ProductID).Distinct().ToList();
- foreach ((string model, RGBDeviceType deviceType, int id, string imageLayout, string layoutPath) deviceData in PER_KEY_DEVICES)
+ foreach ((string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath) deviceData in PER_KEY_DEVICES)
if (ids.Contains(deviceData.id))
{
IsPerKeyDeviceConnected = true;
@@ -59,13 +67,35 @@ namespace RGB.NET.Devices.Logitech.HID
break;
}
- foreach ((string model, RGBDeviceType deviceType, int id, string imageLayout, string layoutPath) deviceData in PER_DEVICE_DEVICES)
+ foreach ((string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath) deviceData in PER_DEVICE_DEVICES)
if (ids.Contains(deviceData.id))
{
IsPerDeviceDeviceConnected = true;
PerDeviceDeviceData = deviceData;
break;
}
+
+ Dictionary> connectedZoneDevices
+ = new Dictionary>();
+ foreach ((string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath) deviceData in ZONE_DEVICES)
+ {
+ if (ids.Contains(deviceData.id))
+ {
+ IsZoneDeviceConnected = true;
+ if (!connectedZoneDevices.TryGetValue(deviceData.deviceType, out List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)> deviceList))
+ connectedZoneDevices.Add(deviceData.deviceType, deviceList = new List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)>());
+ deviceList.Add(deviceData);
+ }
+ }
+ List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)> zoneDeviceData
+ = new List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)>();
+ foreach (KeyValuePair> connectedZoneDevice in connectedZoneDevices)
+ {
+ int maxZones = connectedZoneDevice.Value.Max(x => x.zones);
+ zoneDeviceData.Add(connectedZoneDevice.Value.First(x => x.zones == maxZones));
+ }
+
+ ZoneDeviceData = zoneDeviceData;
}
#endregion
diff --git a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs
index 817665f..4f7d789 100644
--- a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs
+++ b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs
@@ -60,6 +60,9 @@ namespace RGB.NET.Devices.Logitech
/// The used to trigger the updates for logitech devices.
///
public DeviceUpdateTrigger UpdateTrigger { get; private set; }
+
+ // ReSharper disable once CollectionNeverQueried.Local - for now this is just to make sure they're never collected
+ private readonly Dictionary _zoneUpdateQueues = new Dictionary();
private LogitechPerDeviceUpdateQueue _perDeviceUpdateQueue;
private LogitechPerKeyUpdateQueue _perKeyUpdateQueue;
@@ -111,12 +114,12 @@ namespace RGB.NET.Devices.Logitech
try
{
- if (DeviceChecker.IsPerKeyDeviceConnected)
+ if (DeviceChecker.IsZoneDeviceConnected)
{
- (string model, RGBDeviceType deviceType, int _, string imageLayout, string layoutPath) = DeviceChecker.PerKeyDeviceData;
+ (string model, RGBDeviceType deviceType, int _, int _, string imageLayout, string layoutPath) = DeviceChecker.PerKeyDeviceData;
if (loadFilter.HasFlag(deviceType)) //TODO DarthAffe 07.12.2017: Check if it's worth to try another device if the one returned doesn't match the filter
{
- ILogitechRGBDevice device = new LogitechPerKeyRGBDevice(new LogitechRGBDeviceInfo(deviceType, model, LogitechDeviceCaps.PerKeyRGB, imageLayout, layoutPath));
+ ILogitechRGBDevice device = new LogitechPerKeyRGBDevice(new LogitechRGBDeviceInfo(deviceType, model, LogitechDeviceCaps.PerKeyRGB, 0, imageLayout, layoutPath));
device.Initialize(_perKeyUpdateQueue);
devices.Add(device);
}
@@ -128,10 +131,10 @@ namespace RGB.NET.Devices.Logitech
{
if (DeviceChecker.IsPerDeviceDeviceConnected)
{
- (string model, RGBDeviceType deviceType, int _, string imageLayout, string layoutPath) = DeviceChecker.PerDeviceDeviceData;
+ (string model, RGBDeviceType deviceType, int _, int _, string imageLayout, string layoutPath) = DeviceChecker.PerDeviceDeviceData;
if (loadFilter.HasFlag(deviceType)) //TODO DarthAffe 07.12.2017: Check if it's worth to try another device if the one returned doesn't match the filter
{
- ILogitechRGBDevice device = new LogitechPerDeviceRGBDevice(new LogitechRGBDeviceInfo(deviceType, model, LogitechDeviceCaps.DeviceRGB, imageLayout, layoutPath));
+ ILogitechRGBDevice device = new LogitechPerDeviceRGBDevice(new LogitechRGBDeviceInfo(deviceType, model, LogitechDeviceCaps.DeviceRGB, 0, imageLayout, layoutPath));
device.Initialize(_perDeviceUpdateQueue);
devices.Add(device);
}
@@ -139,6 +142,27 @@ namespace RGB.NET.Devices.Logitech
}
catch { if (throwExceptions) throw; }
+ try
+ {
+ if (DeviceChecker.IsZoneDeviceConnected)
+ {
+ foreach ((string model, RGBDeviceType deviceType, int _, int zones, string imageLayout, string layoutPath) in DeviceChecker.ZoneDeviceData)
+ try
+ {
+ if (loadFilter.HasFlag(deviceType))
+ {
+ LogitechZoneUpdateQueue updateQueue = new LogitechZoneUpdateQueue(UpdateTrigger, deviceType);
+ ILogitechRGBDevice device = new LogitechZoneRGBDevice(new LogitechRGBDeviceInfo(deviceType, model, LogitechDeviceCaps.DeviceRGB, zones, imageLayout, layoutPath));
+ device.Initialize(updateQueue);
+ devices.Add(device);
+ _zoneUpdateQueues.Add(deviceType, updateQueue);
+ }
+ }
+ catch { if (throwExceptions) throw; }
+ }
+ }
+ catch { if (throwExceptions) throw; }
+
UpdateTrigger?.Start();
Devices = new ReadOnlyCollection(devices);
diff --git a/RGB.NET.Devices.Logitech/Native/_LogitechGSDK.cs b/RGB.NET.Devices.Logitech/Native/_LogitechGSDK.cs
index c924515..39d0968 100644
--- a/RGB.NET.Devices.Logitech/Native/_LogitechGSDK.cs
+++ b/RGB.NET.Devices.Logitech/Native/_LogitechGSDK.cs
@@ -52,6 +52,7 @@ namespace RGB.NET.Devices.Logitech.Native
_logiLedSetLightingPointer = (LogiLedSetLightingPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetLighting"), typeof(LogiLedSetLightingPointer));
_logiLedSetLightingForKeyWithKeyNamePointer = (LogiLedSetLightingForKeyWithKeyNamePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetLightingForKeyWithKeyName"), typeof(LogiLedSetLightingForKeyWithKeyNamePointer));
_logiLedSetLightingFromBitmapPointer = (LogiLedSetLightingFromBitmapPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetLightingFromBitmap"), typeof(LogiLedSetLightingFromBitmapPointer));
+ _logiLedSetLightingForTargetZonePointer = (LogiLedSetLightingForTargetZonePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetLightingForTargetZone"), typeof(LogiLedSetLightingForTargetZonePointer));
}
private static void UnloadLogitechGSDK()
@@ -89,6 +90,7 @@ namespace RGB.NET.Devices.Logitech.Native
private static LogiLedSetLightingPointer _logiLedSetLightingPointer;
private static LogiLedSetLightingForKeyWithKeyNamePointer _logiLedSetLightingForKeyWithKeyNamePointer;
private static LogiLedSetLightingFromBitmapPointer _logiLedSetLightingFromBitmapPointer;
+ private static LogiLedSetLightingForTargetZonePointer _logiLedSetLightingForTargetZonePointer;
#endregion
@@ -121,6 +123,9 @@ namespace RGB.NET.Devices.Logitech.Native
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool LogiLedSetLightingFromBitmapPointer(byte[] bitmap);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate bool LogiLedSetLightingForTargetZonePointer(LogitechDeviceType deviceType, int zone, int redPercentage, int greenPercentage, int bluePercentage);
+
#endregion
// ReSharper disable EventExceptionNotDocumented
@@ -149,11 +154,14 @@ namespace RGB.NET.Devices.Logitech.Native
internal static bool LogiLedSetLighting(int redPercentage, int greenPercentage, int bluePercentage) => _logiLedSetLightingPointer(redPercentage, greenPercentage, bluePercentage);
- internal static bool LogiLedSetLightingForKeyWithKeyName(int keyCode,
- int redPercentage, int greenPercentage, int bluePercentage) => _logiLedSetLightingForKeyWithKeyNamePointer(keyCode, redPercentage, greenPercentage, bluePercentage);
+ internal static bool LogiLedSetLightingForKeyWithKeyName(int keyCode, int redPercentage, int greenPercentage, int bluePercentage)
+ => _logiLedSetLightingForKeyWithKeyNamePointer(keyCode, redPercentage, greenPercentage, bluePercentage);
internal static bool LogiLedSetLightingFromBitmap(byte[] bitmap) => _logiLedSetLightingFromBitmapPointer(bitmap);
+ internal static bool LogiLedSetLightingForTargetZone(LogitechDeviceType deviceType, int zone, int redPercentage, int greenPercentage, int bluePercentage)
+ => _logiLedSetLightingForTargetZonePointer(deviceType, zone, redPercentage, greenPercentage, bluePercentage);
+
// ReSharper restore EventExceptionNotDocumented
#endregion
diff --git a/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj.DotSettings b/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj.DotSettings
index 742b199..e94069e 100644
--- a/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj.DotSettings
+++ b/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj.DotSettings
@@ -5,4 +5,5 @@
True
True
True
- True
\ No newline at end of file
+ True
+ True
\ No newline at end of file
diff --git a/RGB.NET.Devices.Logitech/Zone/LogitechZoneRGBDevice.cs b/RGB.NET.Devices.Logitech/Zone/LogitechZoneRGBDevice.cs
new file mode 100644
index 0000000..c7263ae
--- /dev/null
+++ b/RGB.NET.Devices.Logitech/Zone/LogitechZoneRGBDevice.cs
@@ -0,0 +1,66 @@
+using System.Collections.Generic;
+using System.Linq;
+using RGB.NET.Core;
+
+namespace RGB.NET.Devices.Logitech
+{
+ ///
+ ///
+ /// Represents a logitech zone-lightable device.
+ ///
+ public class LogitechZoneRGBDevice : LogitechRGBDevice
+ {
+ #region Constants
+
+ private static readonly Dictionary BASE_LED_MAPPING = new Dictionary
+ {
+ {RGBDeviceType.Keyboard, LedId.Keyboard_Programmable1},
+ {RGBDeviceType.Mouse, LedId.Mouse1},
+ {RGBDeviceType.Headset, LedId.Headset1},
+ {RGBDeviceType.Mousepad, LedId.Mousepad1},
+ {RGBDeviceType.Speaker, LedId.Speaker1}
+ };
+
+ #endregion
+
+ #region Properties & Fields
+
+ private LedId _baseLedId;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The specific information provided by logitech for the zone-lightable device
+ internal LogitechZoneRGBDevice(LogitechRGBDeviceInfo info)
+ : base(info)
+ {
+ _baseLedId = BASE_LED_MAPPING.TryGetValue(info.DeviceType, out LedId id) ? id : LedId.Custom1;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ protected override void InitializeLayout()
+ {
+ for (int i = 0; i < DeviceInfo.Zones; i++)
+ InitializeLed(_baseLedId + i, new Rectangle(i * 10, 0, 10, 10));
+
+ base.InitializeLayout();
+ }
+
+ ///
+ protected override object CreateLedCustomData(LedId ledId) => (int)(ledId - _baseLedId);
+
+ ///
+ protected override void UpdateLeds(IEnumerable ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0));
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Logitech/Zone/LogitechZoneUpdateQueue.cs b/RGB.NET.Devices.Logitech/Zone/LogitechZoneUpdateQueue.cs
new file mode 100644
index 0000000..ab0062c
--- /dev/null
+++ b/RGB.NET.Devices.Logitech/Zone/LogitechZoneUpdateQueue.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using RGB.NET.Core;
+using RGB.NET.Devices.Logitech.Native;
+
+namespace RGB.NET.Devices.Logitech
+{
+ ///
+ /// Represents the update-queue performing updates for logitech zone devices.
+ ///
+ public class LogitechZoneUpdateQueue : UpdateQueue
+ {
+ #region Constants
+
+ private static readonly Dictionary DEVICE_TYPE_MAPPING = new Dictionary
+ {
+ {RGBDeviceType.Keyboard, LogitechDeviceType.Keyboard},
+ {RGBDeviceType.Mouse, LogitechDeviceType.Mouse},
+ {RGBDeviceType.Headset, LogitechDeviceType.Headset},
+ {RGBDeviceType.Mousepad, LogitechDeviceType.Mousemat},
+ {RGBDeviceType.Speaker, LogitechDeviceType.Speaker}
+ };
+
+ #endregion
+
+ #region Properties & Fields
+
+ private readonly LogitechDeviceType _deviceType;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The update trigger used by this queue.
+ /// The tpye of the device this queue is updating.
+ public LogitechZoneUpdateQueue(IDeviceUpdateTrigger updateTrigger, RGBDeviceType deviceType)
+ : base(updateTrigger)
+ {
+ if (!DEVICE_TYPE_MAPPING.TryGetValue(deviceType, out _deviceType))
+ throw new ArgumentException($"Invalid type '{deviceType.ToString()}'", nameof(deviceType));
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ protected override void Update(Dictionary