1
0
mirror of https://github.com/DarthAffe/RGB.NET.git synced 2025-12-12 17:48:31 +00:00

Update logitech integration to make use of the new zone-system in the latest logitech SDK

This commit is contained in:
Darth Affe 2018-07-15 17:06:59 +02:00
parent c056aa7444
commit 0412058e6a
9 changed files with 246 additions and 31 deletions

View File

@ -0,0 +1,11 @@
namespace RGB.NET.Devices.Logitech
{
public enum LogitechDeviceType
{
Keyboard = 0x0,
Mouse = 0x3,
Mousemat = 0x4,
Headset = 0x8,
Speaker = 0xE
}
}

View File

@ -18,7 +18,7 @@ namespace RGB.NET.Devices.Logitech
/// Gets information about the <see cref="T:RGB.NET.Devices.Logitech.LogitechRGBDevice" />.
/// </summary>
public override TDeviceInfo DeviceInfo { get; }
/// <summary>
/// Gets or sets the update queue performing updates for this device.
/// </summary>
@ -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);

View File

@ -49,6 +49,11 @@ namespace RGB.NET.Devices.Logitech
/// </summary>
public LogitechDeviceCaps DeviceCaps { get; }
/// <summary>
/// Gets the amount of zones the <see cref="LogitechRGBDevice{TDeviceInfo}"/> is able to control (0 for single-color and per-key devices)
/// </summary>
public int Zones { get; }
/// <summary>
/// Gets the layout used to decide which images to load.
/// </summary>
@ -69,14 +74,16 @@ namespace RGB.NET.Devices.Logitech
/// <param name="deviceType">The type of the <see cref="IRGBDevice"/>.</param>
/// <param name="model">The represented device model.</param>
/// <param name="deviceCaps">The lighting-capabilities of the device.</param>
/// <param name="zones">The amount of zones the device is able to control.</param>
/// <param name="imageLayout">The layout used to decide which images to load.</param>
/// <param name="layoutPath">The path/name of the layout-file.</param>
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;

View File

@ -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<int> 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<RGBDeviceType, List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)>> connectedZoneDevices
= new Dictionary<RGBDeviceType, List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)>>();
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<RGBDeviceType, List<(string model, RGBDeviceType deviceType, int id, int zones, string imageLayout, string layoutPath)>> connectedZoneDevice in connectedZoneDevices)
{
int maxZones = connectedZoneDevice.Value.Max(x => x.zones);
zoneDeviceData.Add(connectedZoneDevice.Value.First(x => x.zones == maxZones));
}
ZoneDeviceData = zoneDeviceData;
}
#endregion

View File

@ -60,6 +60,9 @@ namespace RGB.NET.Devices.Logitech
/// The <see cref="DeviceUpdateTrigger"/> used to trigger the updates for logitech devices.
/// </summary>
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<RGBDeviceType, LogitechZoneUpdateQueue> _zoneUpdateQueues = new Dictionary<RGBDeviceType, LogitechZoneUpdateQueue>();
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<IRGBDevice>(devices);

View File

@ -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

View File

@ -5,4 +5,5 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=keyboard/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=mouse/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=perdevice/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=perkey/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=perkey/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=zone/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,66 @@
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
namespace RGB.NET.Devices.Logitech
{
/// <inheritdoc />
/// <summary>
/// Represents a logitech zone-lightable device.
/// </summary>
public class LogitechZoneRGBDevice : LogitechRGBDevice<LogitechRGBDeviceInfo>
{
#region Constants
private static readonly Dictionary<RGBDeviceType, LedId> BASE_LED_MAPPING = new Dictionary<RGBDeviceType, LedId>
{
{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
/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:RGB.NET.Devices.Logitech.LogitechZoneRGBDevice" /> class.
/// </summary>
/// <param name="info">The specific information provided by logitech for the zone-lightable device</param>
internal LogitechZoneRGBDevice(LogitechRGBDeviceInfo info)
: base(info)
{
_baseLedId = BASE_LED_MAPPING.TryGetValue(info.DeviceType, out LedId id) ? id : LedId.Custom1;
}
#endregion
#region Methods
/// <inheritdoc />
protected override void InitializeLayout()
{
for (int i = 0; i < DeviceInfo.Zones; i++)
InitializeLed(_baseLedId + i, new Rectangle(i * 10, 0, 10, 10));
base.InitializeLayout();
}
/// <inheritdoc />
protected override object CreateLedCustomData(LedId ledId) => (int)(ledId - _baseLedId);
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0));
#endregion
}
}

View File

@ -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
{
/// <summary>
/// Represents the update-queue performing updates for logitech zone devices.
/// </summary>
public class LogitechZoneUpdateQueue : UpdateQueue
{
#region Constants
private static readonly Dictionary<RGBDeviceType, LogitechDeviceType> DEVICE_TYPE_MAPPING = new Dictionary<RGBDeviceType, LogitechDeviceType>
{
{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
/// <summary>
/// Initializes a new instance of the <see cref="LogitechZoneUpdateQueue"/> class.
/// </summary>
/// <param name="updateTrigger">The update trigger used by this queue.</param>
/// <param name="deviceType">The tpye of the device this queue is updating.</param>
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
/// <inheritdoc />
protected override void Update(Dictionary<object, Color> dataSet)
{
_LogitechGSDK.LogiLedSetTargetDevice(LogitechDeviceCaps.All);
foreach (KeyValuePair<object, Color> data in dataSet)
{
int zone = (int)data.Key;
_LogitechGSDK.LogiLedSetLightingForTargetZone(_deviceType, zone,
(int)Math.Round(data.Value.RPercent * 100),
(int)Math.Round(data.Value.GPercent * 100),
(int)Math.Round(data.Value.BPercent * 100));
}
}
#endregion
}
}