From 2af55146cc5d1fecb943b5dd6f5b11c170c66737 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sat, 4 Feb 2017 17:09:00 +0100 Subject: [PATCH] Added logitech support (unfinished: HID-Ids and layouts are missing) --- NuGet/RGB.NET.Devices.Logitech.nuspec | 31 ++++ .../Enum/LogitechDeviceCaps.cs | 18 ++ .../Enum/LogitechLedIds.cs | 129 ++++++++++++++ .../Enum/LogitechLogicalKeyboardLayout.cs | 32 ++++ .../Enum/LogitechPhysicalKeyboardLayout.cs | 36 ++++ .../Generic/LogitechLedId.cs | 107 +++++++++++ .../Generic/LogitechRGBDevice.cs | 105 +++++++++++ .../Generic/LogitechRGBDeviceInfo.cs | 64 +++++++ RGB.NET.Devices.Logitech/HID/DeviceChecker.cs | 57 ++++++ .../Helper/CultureHelper.cs | 44 +++++ .../Keyboard/LogitechKeyboardRGBDevice.cs | 49 ++++++ .../Keyboard/LogitechKeyboardRGBDeviceInfo.cs | 63 +++++++ .../LogitechDeviceProvider.cs | 117 ++++++++++++ .../Native/_LogitechGSDK.cs | 166 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 ++++ .../RGB.NET.Devices.Logitech.csproj | 88 ++++++++++ ...GB.NET.Devices.Logitech.csproj.DotSettings | 5 + .../libs/x64/LogitechLedEnginesWrapper.dll | Bin 0 -> 20088 bytes .../libs/x86/LogitechLedEnginesWrapper.dll | Bin 0 -> 18040 bytes RGB.NET.Devices.Logitech/packages.config | 5 + .../targets/RGB.NET.Devices.Logitech.targets | 150 ++++++++++++++++ RGB.NET.sln | 8 + 22 files changed, 1310 insertions(+) create mode 100644 NuGet/RGB.NET.Devices.Logitech.nuspec create mode 100644 RGB.NET.Devices.Logitech/Enum/LogitechDeviceCaps.cs create mode 100644 RGB.NET.Devices.Logitech/Enum/LogitechLedIds.cs create mode 100644 RGB.NET.Devices.Logitech/Enum/LogitechLogicalKeyboardLayout.cs create mode 100644 RGB.NET.Devices.Logitech/Enum/LogitechPhysicalKeyboardLayout.cs create mode 100644 RGB.NET.Devices.Logitech/Generic/LogitechLedId.cs create mode 100644 RGB.NET.Devices.Logitech/Generic/LogitechRGBDevice.cs create mode 100644 RGB.NET.Devices.Logitech/Generic/LogitechRGBDeviceInfo.cs create mode 100644 RGB.NET.Devices.Logitech/HID/DeviceChecker.cs create mode 100644 RGB.NET.Devices.Logitech/Helper/CultureHelper.cs create mode 100644 RGB.NET.Devices.Logitech/Keyboard/LogitechKeyboardRGBDevice.cs create mode 100644 RGB.NET.Devices.Logitech/Keyboard/LogitechKeyboardRGBDeviceInfo.cs create mode 100644 RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs create mode 100644 RGB.NET.Devices.Logitech/Native/_LogitechGSDK.cs create mode 100644 RGB.NET.Devices.Logitech/Properties/AssemblyInfo.cs create mode 100644 RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj create mode 100644 RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj.DotSettings create mode 100644 RGB.NET.Devices.Logitech/libs/x64/LogitechLedEnginesWrapper.dll create mode 100644 RGB.NET.Devices.Logitech/libs/x86/LogitechLedEnginesWrapper.dll create mode 100644 RGB.NET.Devices.Logitech/packages.config create mode 100644 RGB.NET.Devices.Logitech/targets/RGB.NET.Devices.Logitech.targets diff --git a/NuGet/RGB.NET.Devices.Logitech.nuspec b/NuGet/RGB.NET.Devices.Logitech.nuspec new file mode 100644 index 0000000..7c3c9eb --- /dev/null +++ b/NuGet/RGB.NET.Devices.Logitech.nuspec @@ -0,0 +1,31 @@ + + + + RGB.NET.Devices.Logitech + CUE.NET.Devices.Logitech + 1.0.0.0 + Darth Affe + Darth Affe + https://github.com/DarthAffe/RGB.NET + https://raw.githubusercontent.com/DarthAffe/RGB.NET/master/LICENSE + true + Logitech-Device-Implementations of RGB.NET + + Logitech-Device-Implementations of RGB.NET, a C# (.NET) library for accessing various RGB-peripherals + Copyright © Wyrez 2017 + en-US + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RGB.NET.Devices.Logitech/Enum/LogitechDeviceCaps.cs b/RGB.NET.Devices.Logitech/Enum/LogitechDeviceCaps.cs new file mode 100644 index 0000000..0d72242 --- /dev/null +++ b/RGB.NET.Devices.Logitech/Enum/LogitechDeviceCaps.cs @@ -0,0 +1,18 @@ +// ReSharper disable InconsistentNaming + +using System; + +#pragma warning disable 1591 // Missing XML comment for publicly visible type or member + +namespace RGB.NET.Devices.Logitech +{ + [Flags] + public enum LogitechDeviceCaps + { + None = 0, + Monochrome = 1 << 0, + DeviceRGB = 1 << 1, + PerKeyRGB = 1 << 2, + All = Monochrome | DeviceRGB | PerKeyRGB + } +} diff --git a/RGB.NET.Devices.Logitech/Enum/LogitechLedIds.cs b/RGB.NET.Devices.Logitech/Enum/LogitechLedIds.cs new file mode 100644 index 0000000..d82f868 --- /dev/null +++ b/RGB.NET.Devices.Logitech/Enum/LogitechLedIds.cs @@ -0,0 +1,129 @@ +// ReSharper disable InconsistentNaming + +#pragma warning disable 1591 // Missing XML comment for publicly visible type or member + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Contains list of all LEDs available for all logitech devices. + /// + public enum LogitechLedIds + { + Invalid = 0, + ESC = 0x01, + F1 = 0x3b, + F2 = 0x3c, + F3 = 0x3d, + F4 = 0x3e, + F5 = 0x3f, + F6 = 0x40, + F7 = 0x41, + F8 = 0x42, + F9 = 0x43, + F10 = 0x44, + F11 = 0x57, + F12 = 0x58, + PRINT_SCREEN = 0x137, + SCROLL_LOCK = 0x46, + PAUSE_BREAK = 0x45, + TILDE = 0x29, + ONE = 0x02, + TWO = 0x03, + THREE = 0x04, + FOUR = 0x05, + FIVE = 0x06, + SIX = 0x07, + SEVEN = 0x08, + EIGHT = 0x09, + NINE = 0x0A, + ZERO = 0x0B, + MINUS = 0x0C, + EQUALS = 0x0D, + BACKSPACE = 0x0E, + INSERT = 0x152, + HOME = 0x147, + PAGE_UP = 0x149, + NUM_LOCK = 0x145, + NUM_SLASH = 0x135, + NUM_ASTERISK = 0x37, + NUM_MINUS = 0x4A, + TAB = 0x0F, + Q = 0x10, + W = 0x11, + E = 0x12, + R = 0x13, + T = 0x14, + Y = 0x15, + U = 0x16, + I = 0x17, + O = 0x18, + P = 0x19, + OPEN_BRACKET = 0x1A, + CLOSE_BRACKET = 0x1B, + BACKSLASH = 0x2B, + KEYBOARD_DELETE = 0x153, + END = 0x14F, + PAGE_DOWN = 0x151, + NUM_SEVEN = 0x47, + NUM_EIGHT = 0x48, + NUM_NINE = 0x49, + NUM_PLUS = 0x4E, + CAPS_LOCK = 0x3A, + A = 0x1E, + S = 0x1F, + D = 0x20, + F = 0x21, + G = 0x22, + H = 0x23, + J = 0x24, + K = 0x25, + L = 0x26, + SEMICOLON = 0x27, + APOSTROPHE = 0x28, + ENTER = 0x1C, + NUM_FOUR = 0x4B, + NUM_FIVE = 0x4C, + NUM_SIX = 0x4D, + LEFT_SHIFT = 0x2A, + Z = 0x2C, + X = 0x2D, + C = 0x2E, + V = 0x2F, + B = 0x30, + N = 0x31, + M = 0x32, + COMMA = 0x33, + PERIOD = 0x34, + FORWARD_SLASH = 0x35, + RIGHT_SHIFT = 0x36, + ARROW_UP = 0x148, + NUM_ONE = 0x4F, + NUM_TWO = 0x50, + NUM_THREE = 0x51, + NUM_ENTER = 0x11C, + LEFT_CONTROL = 0x1D, + LEFT_WINDOWS = 0x15B, + LEFT_ALT = 0x38, + SPACE = 0x39, + RIGHT_ALT = 0x138, + RIGHT_WINDOWS = 0x15C, + APPLICATION_SELECT = 0x15D, + RIGHT_CONTROL = 0x11D, + ARROW_LEFT = 0x14B, + ARROW_DOWN = 0x150, + ARROW_RIGHT = 0x14D, + NUM_ZERO = 0x52, + NUM_PERIOD = 0x53, + G_1 = 0xFFF1, + G_2 = 0xFFF2, + G_3 = 0xFFF3, + G_4 = 0xFFF4, + G_5 = 0xFFF5, + G_6 = 0xFFF6, + G_7 = 0xFFF7, + G_8 = 0xFFF8, + G_9 = 0xFFF9, + G_LOGO = 0xFFFF1, + G_BADGE = 0xFFFF2, + } +} diff --git a/RGB.NET.Devices.Logitech/Enum/LogitechLogicalKeyboardLayout.cs b/RGB.NET.Devices.Logitech/Enum/LogitechLogicalKeyboardLayout.cs new file mode 100644 index 0000000..808c12d --- /dev/null +++ b/RGB.NET.Devices.Logitech/Enum/LogitechLogicalKeyboardLayout.cs @@ -0,0 +1,32 @@ +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global + +#pragma warning disable 1591 // Missing XML comment for publicly visible type or member + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Contains list of available logical layouts for logitech keyboards. + /// + public enum LogitechLogicalKeyboardLayout + { + US_Int = 1, + NA = 2, + EU = 3, + UK = 4, + BE = 5, + BR = 6, + CH = 7, + CN = 8, + DE = 9, + ES = 10, + FR = 11, + IT = 12, + ND = 13, + RU = 14, + JP = 15, + KR = 16, + TW = 17, + MEX = 18 + }; +} diff --git a/RGB.NET.Devices.Logitech/Enum/LogitechPhysicalKeyboardLayout.cs b/RGB.NET.Devices.Logitech/Enum/LogitechPhysicalKeyboardLayout.cs new file mode 100644 index 0000000..95e608e --- /dev/null +++ b/RGB.NET.Devices.Logitech/Enum/LogitechPhysicalKeyboardLayout.cs @@ -0,0 +1,36 @@ +// ReSharper disable UnusedMember.Global +// ReSharper disable InconsistentNaming + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Contains list of available physical layouts for logitech keyboards. + /// + public enum LogitechPhysicalKeyboardLayout + { + /// + /// US-Keyboard + /// + US = 1, + + /// + /// UK-Keyboard + /// + UK = 2, + + /// + /// BR-Keyboard + /// + BR = 3, + + /// + /// JP-Keyboard + /// + JP = 4, + + /// + /// KR-Keyboard + /// + KR = 5 + } +} diff --git a/RGB.NET.Devices.Logitech/Generic/LogitechLedId.cs b/RGB.NET.Devices.Logitech/Generic/LogitechLedId.cs new file mode 100644 index 0000000..58a27ed --- /dev/null +++ b/RGB.NET.Devices.Logitech/Generic/LogitechLedId.cs @@ -0,0 +1,107 @@ +using System.Diagnostics; +using RGB.NET.Core; + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Represents a Id of a on a . + /// + [DebuggerDisplay("{" + nameof(LedId) + "}")] + public class LogitechLedId : ILedId + { + #region Properties & Fields + + internal readonly LogitechLedIds LedId; + + /// + public IRGBDevice Device { get; } + + /// + public bool IsValid => LedId != LogitechLedIds.Invalid; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The the belongs to. + /// The of the represented . + public LogitechLedId(IRGBDevice device, LogitechLedIds ledId) + { + this.Device = device; + this.LedId = ledId; + } + + #endregion + + #region Methods + + /// + /// Converts the Id of this to a human-readable string. + /// + /// A string that contains the Id of this . For example "Enter". + public override string ToString() + { + return LedId.ToString(); + } + + /// + /// Tests whether the specified object is a and is equivalent to this . + /// + /// The object to test. + /// true if is a equivalent to this ; otherwise, false. + public override bool Equals(object obj) + { + LogitechLedId compareLedId = obj as LogitechLedId; + if (ReferenceEquals(compareLedId, null)) + return false; + + if (ReferenceEquals(this, compareLedId)) + return true; + + if (GetType() != compareLedId.GetType()) + return false; + + return compareLedId.LedId == LedId; + } + + /// + /// Returns a hash code for this . + /// + /// An integer value that specifies the hash code for this . + public override int GetHashCode() + { + return LedId.GetHashCode(); + } + + #endregion + + #region Operators + + /// + /// Returns a value that indicates whether two specified are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are equal; otherwise, false. + public static bool operator ==(LogitechLedId ledId1, LogitechLedId ledId2) + { + return ReferenceEquals(ledId1, null) ? ReferenceEquals(ledId2, null) : ledId1.Equals(ledId2); + } + + /// + /// Returns a value that indicates whether two specified are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are not equal; otherwise, false. + public static bool operator !=(LogitechLedId ledId1, LogitechLedId ledId2) + { + return !(ledId1 == ledId2); + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/Generic/LogitechRGBDevice.cs b/RGB.NET.Devices.Logitech/Generic/LogitechRGBDevice.cs new file mode 100644 index 0000000..8336467 --- /dev/null +++ b/RGB.NET.Devices.Logitech/Generic/LogitechRGBDevice.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RGB.NET.Core; +using RGB.NET.Core.Layout; +using RGB.NET.Devices.Logitech.Native; + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Represents a generic Logitech-device. (keyboard, mouse, headset, mousmat). + /// + public abstract class LogitechRGBDevice : AbstractRGBDevice + { + #region Properties & Fields + + /// + /// Gets information about the . + /// + public override IRGBDeviceInfo DeviceInfo { get; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The generic information provided by Logitech for the device. + protected LogitechRGBDevice(IRGBDeviceInfo info) + { + this.DeviceInfo = info; + } + + #endregion + + #region Methods + + /// + /// Initializes the device. + /// + internal void Initialize() + { + InitializeLayout(); + + if (InternalSize == null) + { + Rectangle ledRectangle = new Rectangle(this.Select(x => x.LedRectangle)); + InternalSize = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y); + } + } + + /// + /// Initializes the and of the device. + /// + protected abstract void InitializeLayout(); + + /// + /// Applies the given layout. + /// + /// The file containing the layout. + protected void ApplyLayoutFromFile(string layoutPath) + { + DeviceLayout layout = DeviceLayout.Load(layoutPath); + if (layout != null) + { + InternalSize = new Size(layout.Width, layout.Height); + + if (layout.Leds != null) + foreach (LedLayout layoutLed in layout.Leds) + { + LogitechLedIds ledId; + if (Enum.TryParse(layoutLed.Id, true, out ledId)) + { + LogitechLedId id = new LogitechLedId(this, ledId); + Led led; + if (!LedMapping.TryGetValue(id, out led)) + led = InitializeLed(id, new Rectangle()); + + led.LedRectangle.Location.X = layoutLed.X; + led.LedRectangle.Location.Y = layoutLed.Y; + led.LedRectangle.Size.Width = layoutLed.Width; + led.LedRectangle.Size.Height = layoutLed.Height; + + led.Shape = layoutLed.Shape; + } + } + } + } + + /// + protected override void UpdateLeds(IEnumerable ledsToUpdate) + { + List leds = ledsToUpdate.Where(x => x.Color.A > 0).ToList(); + + foreach (Led led in leds) + _LogitechGSDK.LogiLedSetLightingForKeyWithKeyName((int)((LogitechLedId)led.Id).LedId, + (int)Math.Round(led.Color.RPercent * 100), + (int)Math.Round(led.Color.GPercent * 100), + (int)Math.Round(led.Color.BPercent * 100)); + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/Generic/LogitechRGBDeviceInfo.cs b/RGB.NET.Devices.Logitech/Generic/LogitechRGBDeviceInfo.cs new file mode 100644 index 0000000..9876581 --- /dev/null +++ b/RGB.NET.Devices.Logitech/Generic/LogitechRGBDeviceInfo.cs @@ -0,0 +1,64 @@ +using System; +using RGB.NET.Core; + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Represents a generic information for a Logitech-. + /// + public class LogitechRGBDeviceInfo : IRGBDeviceInfo + { + #region Properties & Fields + + /// + public RGBDeviceType DeviceType { get; } + + /// + public string Manufacturer => "Logitech"; + + /// + public string Model { get; } + + /// + public Uri Image { get; protected set; } + + /// + public RGBDeviceLighting Lighting + { + get + { + if (DeviceCaps.HasFlag(LogitechDeviceCaps.PerKeyRGB)) + return RGBDeviceLighting.Key; + + if (DeviceCaps.HasFlag(LogitechDeviceCaps.DeviceRGB)) + return RGBDeviceLighting.Keyboard; + + return RGBDeviceLighting.None; + } + } + + /// + /// Gets a flag that describes device capabilities. () + /// + public LogitechDeviceCaps DeviceCaps { get; } + + #endregion + + #region Constructors + + /// + /// Internal constructor of managed . + /// + /// The type of the . + /// The represented device model. + /// The lighting-capabilities of the device. + internal LogitechRGBDeviceInfo(RGBDeviceType deviceType, string model, LogitechDeviceCaps deviceCaps) + { + this.DeviceType = deviceType; + this.Model = model; + this.DeviceCaps = deviceCaps; + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/HID/DeviceChecker.cs b/RGB.NET.Devices.Logitech/HID/DeviceChecker.cs new file mode 100644 index 0000000..8a753f1 --- /dev/null +++ b/RGB.NET.Devices.Logitech/HID/DeviceChecker.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using HidSharp; + +namespace RGB.NET.Devices.Logitech.HID +{ + //TODO DarthAffe 04.02.2017: Rewrite this once the SDK supports per-device lighting to get all the devices connected. + internal static class DeviceChecker + { + #region Constants + + //TODO DarthAffe 04.02.2017: Add IDs + private const int VENDOR_ID = 0x0; + private const int G910_ID = 0x0; + private const int G810_ID = 0x0; + + #endregion + + #region Properties & Fields + + public static string ConnectedDeviceModel + { + get + { + if (IsG910Connected) return "G910"; + if (IsG810Connected) return "G810"; + return null; + } + } + + public static bool IsDeviceConnected => IsG910Connected || IsG810Connected; + public static bool IsG910Connected { get; private set; } + public static bool IsG810Connected { get; private set; } + + #endregion + + #region Methods + + internal static void LoadDeviceList() + { + IsG910Connected = false; + IsG810Connected = false; + + HidDeviceLoader loader = new HidDeviceLoader(); + IEnumerable devices = loader.GetDevices(); + foreach (HidDevice hidDevice in devices) + if (hidDevice.VendorID == VENDOR_ID) + { + if (hidDevice.ProductID == G910_ID) + IsG910Connected = true; + else if (hidDevice.ProductID == G810_ID) + IsG810Connected = true; + } + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/Helper/CultureHelper.cs b/RGB.NET.Devices.Logitech/Helper/CultureHelper.cs new file mode 100644 index 0000000..ee5e787 --- /dev/null +++ b/RGB.NET.Devices.Logitech/Helper/CultureHelper.cs @@ -0,0 +1,44 @@ +using System; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Offers some helper-methods for culture related things. + /// + public static class CultureHelper + { + #region DLLImports + + [DllImport("user32.dll")] + static extern IntPtr GetKeyboardLayout(uint thread); + + #endregion + + #region Constructors + + #endregion + + #region Methods + + /// + /// Gets the current keyboard-layout from the OS. + /// + /// The current keyboard-layout + public static CultureInfo GetCurrentCulture() + { + try + { + int keyboardLayout = GetKeyboardLayout(0).ToInt32() & 0xFFFF; + return new CultureInfo(keyboardLayout); + } + catch + { + return new CultureInfo(1033); // en-US on error. + } + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/Keyboard/LogitechKeyboardRGBDevice.cs b/RGB.NET.Devices.Logitech/Keyboard/LogitechKeyboardRGBDevice.cs new file mode 100644 index 0000000..bb9e35e --- /dev/null +++ b/RGB.NET.Devices.Logitech/Keyboard/LogitechKeyboardRGBDevice.cs @@ -0,0 +1,49 @@ +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedMember.Global + +using System; +using System.IO; +using System.Reflection; + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Represents a logitech keyboard. + /// + public class LogitechKeyboardRGBDevice : LogitechRGBDevice + { + #region Properties & Fields + + /// + /// Gets information about the . + /// + public LogitechKeyboardRGBDeviceInfo KeyboardDeviceInfo { get; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The specific information provided by CUE for the keyboard + internal LogitechKeyboardRGBDevice(LogitechKeyboardRGBDeviceInfo info) + : base(info) + { + this.KeyboardDeviceInfo = info; + } + + #endregion + + #region Methods + + /// + protected override void InitializeLayout() + { + ApplyLayoutFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), + $@"Layouts\Logitech\Keyboards\{KeyboardDeviceInfo.Model.Replace(" ", string.Empty).ToUpper()}\{KeyboardDeviceInfo.PhysicalLayout.ToString().ToUpper()}.xml")); + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/Keyboard/LogitechKeyboardRGBDeviceInfo.cs b/RGB.NET.Devices.Logitech/Keyboard/LogitechKeyboardRGBDeviceInfo.cs new file mode 100644 index 0000000..1a9d00b --- /dev/null +++ b/RGB.NET.Devices.Logitech/Keyboard/LogitechKeyboardRGBDeviceInfo.cs @@ -0,0 +1,63 @@ +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedMember.Global + +using System; +using System.Globalization; +using System.IO; +using System.Reflection; +using RGB.NET.Core; + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Represents a generic information for a . + /// + public class LogitechKeyboardRGBDeviceInfo : LogitechRGBDeviceInfo + { + #region Properties & Fields + + /// + /// Gets the physical layout of the keyboard. + /// + public LogitechPhysicalKeyboardLayout PhysicalLayout { get; private set; } + + /// + /// Gets the logical layout of the keyboard. + /// + public LogitechLogicalKeyboardLayout LogicalLayout { get; private set; } + + #endregion + + #region Constructors + + /// + /// Internal constructor of managed . + /// + /// The type of the . + /// The represented device model. + /// The lighting-capabilities of the device. + /// The of the layout this keyboard is using + internal LogitechKeyboardRGBDeviceInfo(RGBDeviceType deviceType, string model, LogitechDeviceCaps deviceCaps, CultureInfo culture) + : base(deviceType, model, deviceCaps) + { + SetLayouts(culture.KeyboardLayoutId); + + Image = new Uri(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), + $@"Images\Logitech\Keyboards\{Model.Replace(" ", string.Empty).ToUpper()}\{LogicalLayout.ToString().ToUpper()}.png"), UriKind.Absolute); + } + + private void SetLayouts(int keyboardLayoutId) + { + switch (keyboardLayoutId) + { + //TODO DarthAffe 04.02.2017: Check all available keyboards and there layout-ids + default: + PhysicalLayout = LogitechPhysicalKeyboardLayout.US; + LogicalLayout = LogitechLogicalKeyboardLayout.NA; + break; + } + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs new file mode 100644 index 0000000..c9c3939 --- /dev/null +++ b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using RGB.NET.Core; +using RGB.NET.Devices.Logitech.HID; +using RGB.NET.Devices.Logitech.Native; + +namespace RGB.NET.Devices.Logitech +{ + /// + /// Represents a device provider responsible for logitech devices. + /// + public class LogitechDeviceProvider : IRGBDeviceProvider + { + #region Properties & Fields + + /// + /// Gets the singleton instance. + /// + public static LogitechDeviceProvider Instance { get; } = new LogitechDeviceProvider(); + + /// + public bool IsInitialized { get; private set; } + + /// + /// Gets the loaded architecture (x64/x86). + /// + public string LoadedArchitecture => _LogitechGSDK.LoadedArchitecture; + + /// + public IEnumerable Devices { get; private set; } + + /// + public bool HasExclusiveAccess => false; // Exclusive access isn't possible for logitech devices. + + /// + /// Gets or sets a function to get the culture for a specific device. + /// + public Func GetCulture { get; set; } = () => CultureHelper.GetCurrentCulture(); + + #endregion + + #region Constructors + + private LogitechDeviceProvider() + { } + + #endregion + + #region Methods + + /// + public bool Initialize(bool exclusiveAccessIfPossible = false, bool throwExceptions = false) + { + try + { + if (IsInitialized) + _LogitechGSDK.LogiLedRestoreLighting(); + } + catch + { /* At least we tried ... */ } + + IsInitialized = false; + + try + { + _LogitechGSDK.Reload(); + if (!_LogitechGSDK.LogiLedInit()) return false; + + _LogitechGSDK.LogiLedSaveCurrentLighting(); + _LogitechGSDK.LogiLedSetTargetDevice(LogitechDeviceCaps.PerKeyRGB); + + IList devices = new List(); + + DeviceChecker.LoadDeviceList(); + if (DeviceChecker.IsDeviceConnected) + { + LogitechRGBDevice device = new LogitechKeyboardRGBDevice(new LogitechKeyboardRGBDeviceInfo( + RGBDeviceType.Keyboard, DeviceChecker.ConnectedDeviceModel, LogitechDeviceCaps.PerKeyRGB, GetCulture())); + devices.Add(device); + + try + { + device.Initialize(); + } + catch + { + if (throwExceptions) + throw; + return false; + } + } + Devices = new ReadOnlyCollection(devices); + } + catch + { + if (throwExceptions) + throw; + else + return false; + } + + IsInitialized = true; + + return true; + } + + /// + public void ResetDevices() + { + _LogitechGSDK.LogiLedRestoreLighting(); + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/Native/_LogitechGSDK.cs b/RGB.NET.Devices.Logitech/Native/_LogitechGSDK.cs new file mode 100644 index 0000000..e93e2cc --- /dev/null +++ b/RGB.NET.Devices.Logitech/Native/_LogitechGSDK.cs @@ -0,0 +1,166 @@ +// ReSharper disable UnusedMethodReturnValue.Global +// ReSharper disable UnusedMember.Global +// ReSharper disable MemberCanBePrivate.Global + +using System; +using System.IO; +using System.Runtime.InteropServices; +using RGB.NET.Core.Exceptions; + +namespace RGB.NET.Devices.Logitech.Native +{ + // ReSharper disable once InconsistentNaming + internal class _LogitechGSDK + { + #region Libary Management + + private static IntPtr _dllHandle = IntPtr.Zero; + + /// + /// Gets the loaded architecture (x64/x86). + /// + internal static string LoadedArchitecture { get; private set; } + + /// + /// Reloads the SDK. + /// + internal static void Reload() + { + UnloadLogitechGSDK(); + LoadLogitechGSDK(); + } + + private static void LoadLogitechGSDK() + { + if (_dllHandle != IntPtr.Zero) return; + + // HACK: Load library at runtime to support both, x86 and x64 with one managed dll + string dllPath = (LoadedArchitecture = Environment.Is64BitProcess ? "x64" : "x86") + "/LogitechLedEnginesWrapper.dll"; + if (!File.Exists(dllPath)) + throw new RGBDeviceException($"Can't find the Logitech-SDK at the expected location '{Path.GetFullPath(dllPath)}'"); + + _dllHandle = LoadLibrary(dllPath); + + _logiLedInitPointer = (LogiLedInitPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedInit"), typeof(LogiLedInitPointer)); + _logiLedShutdownPointer = (LogiLedShutdownPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedShutdown"), typeof(LogiLedShutdownPointer)); + _logiLedSetTargetDevicePointer = (LogiLedSetTargetDevicePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetTargetDevice"), typeof(LogiLedSetTargetDevicePointer)); + _logiLedGetSdkVersionPointer = (LogiLedGetSdkVersionPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedGetSdkVersion"), typeof(LogiLedGetSdkVersionPointer)); + _lgiLedSaveCurrentLightingPointer = (LogiLedSaveCurrentLightingPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSaveCurrentLighting"), typeof(LogiLedSaveCurrentLightingPointer)); + _logiLedRestoreLightingPointer = (LogiLedRestoreLightingPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedRestoreLighting"), typeof(LogiLedRestoreLightingPointer)); + _logiLedSetLightingForKeyWithKeyNamePointer = (LogiLedSetLightingForKeyWithKeyNamePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "LogiLedSetLightingForKeyWithKeyName"), typeof(LogiLedSetLightingForKeyWithKeyNamePointer)); + } + + private static void UnloadLogitechGSDK() + { + if (_dllHandle == IntPtr.Zero) return; + + LogiLedShutdown(); + + // ReSharper disable once EmptyEmbeddedStatement - DarthAffe 20.02.2016: We might need to reduce the internal reference counter more than once to set the library free + while (FreeLibrary(_dllHandle)) ; + _dllHandle = IntPtr.Zero; + } + + [DllImport("kernel32.dll")] + private static extern IntPtr LoadLibrary(string dllToLoad); + + [DllImport("kernel32.dll")] + private static extern bool FreeLibrary(IntPtr dllHandle); + + [DllImport("kernel32.dll")] + private static extern IntPtr GetProcAddress(IntPtr dllHandle, string name); + + #endregion + + #region SDK-METHODS + + #region Pointers + + private static LogiLedInitPointer _logiLedInitPointer; + private static LogiLedShutdownPointer _logiLedShutdownPointer; + private static LogiLedSetTargetDevicePointer _logiLedSetTargetDevicePointer; + private static LogiLedGetSdkVersionPointer _logiLedGetSdkVersionPointer; + private static LogiLedSaveCurrentLightingPointer _lgiLedSaveCurrentLightingPointer; + private static LogiLedRestoreLightingPointer _logiLedRestoreLightingPointer; + private static LogiLedSetLightingForKeyWithKeyNamePointer _logiLedSetLightingForKeyWithKeyNamePointer; + + #endregion + + #region Delegates + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool LogiLedInitPointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void LogiLedShutdownPointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool LogiLedSetTargetDevicePointer(int targetDevice); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool LogiLedGetSdkVersionPointer(ref int majorNum, ref int minorNum, ref int buildNum); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool LogiLedSaveCurrentLightingPointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool LogiLedRestoreLightingPointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool LogiLedSetLightingForKeyWithKeyNamePointer(int keyCode, int redPercentage, int greenPercentage, int bluePercentage); + + #endregion + + // ReSharper disable EventExceptionNotDocumented + + internal static bool LogiLedInit() + { + return _logiLedInitPointer(); + } + + internal static void LogiLedShutdown() + { + _logiLedShutdownPointer(); + } + + internal static bool LogiLedSetTargetDevice(LogitechDeviceCaps targetDevice) + { + return _logiLedSetTargetDevicePointer((int)targetDevice); + } + + internal static string LogiLedGetSdkVersion() + { + int major = 0; + int minor = 0; + int build = 0; + LogiLedGetSdkVersion(ref major, ref minor, ref build); + + return $"{major}.{minor}.{build}"; + } + + internal static bool LogiLedGetSdkVersion(ref int majorNum, ref int minorNum, ref int buildNum) + { + return _logiLedGetSdkVersionPointer(ref majorNum, ref minorNum, ref buildNum); + } + + internal static bool LogiLedSaveCurrentLighting() + { + return _lgiLedSaveCurrentLightingPointer(); + } + + internal static bool LogiLedRestoreLighting() + { + return _logiLedRestoreLightingPointer(); + } + + internal static bool LogiLedSetLightingForKeyWithKeyName(int keyCode, + int redPercentage, int greenPercentage, int bluePercentage) + { + return _logiLedSetLightingForKeyWithKeyNamePointer(keyCode, redPercentage, greenPercentage, bluePercentage); + } + + // ReSharper restore EventExceptionNotDocumented + + #endregion + } +} diff --git a/RGB.NET.Devices.Logitech/Properties/AssemblyInfo.cs b/RGB.NET.Devices.Logitech/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d3238fd --- /dev/null +++ b/RGB.NET.Devices.Logitech/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RGB.NET.Devices.Logitech")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RGB.NET.Devices.Logitech")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("e7b2f174-fcc6-4fc7-9970-3138b5f4c921")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj b/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj new file mode 100644 index 0000000..01fa985 --- /dev/null +++ b/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj @@ -0,0 +1,88 @@ + + + + + Debug + AnyCPU + {E7B2F174-FCC6-4FC7-9970-3138B5F4C921} + Library + Properties + RGB.NET.Devices.Logitech + RGB.NET.Devices.Logitech + v4.5 + 512 + + + true + full + false + ..\bin\ + DEBUG;TRACE + prompt + 4 + ..\bin\RGB.NET.Devices.Logitech.XML + + + pdbonly + true + ..\bin\ + TRACE + prompt + 4 + ..\bin\RGB.NET.Devices.Logitech.XML + + + + ..\packages\HidSharp.1.5\lib\net35\HidSharp.dll + True + + + ..\packages\RGB.NET.Core.1.0.0\lib\net45\RGB.NET.Core.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj.DotSettings b/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj.DotSettings new file mode 100644 index 0000000..8babca3 --- /dev/null +++ b/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj.DotSettings @@ -0,0 +1,5 @@ + + True + True + True + True \ No newline at end of file diff --git a/RGB.NET.Devices.Logitech/libs/x64/LogitechLedEnginesWrapper.dll b/RGB.NET.Devices.Logitech/libs/x64/LogitechLedEnginesWrapper.dll new file mode 100644 index 0000000000000000000000000000000000000000..fb707e78a9fc57566d267ecefbad8dbdeca0b5ec GIT binary patch literal 20088 zcmeHu2~<*D^Cf=6|kZW>fqi zGoRvzDEzp?dZw7tAJ2>e?)ts~cYS{erJwuRGK#yt|2D-Fr5QQ6?$?bZAr_&`G7D5P z|KbFrP8;gaw_(~M)B}+I26U+la0e>A5Qc3?L#-AR)Xvdz0AMoRe?y3grh}@XkdeJA z8<47CgzmvY>>LjL!F4JSYQhaoM<@hy0--{8;0qDr15*e92mZP%au`)bdp4A(>S;$h zqmaCb4`vBNmbFFy3fSD7hRi(!0N2kNBsdYWrddneM@poXd}Auj<4ufV`p z^s0On21TlG(`miIujobkDpkr1fT=lA(0W6=(v#%LL6MKM76RdReSyrbNQ9!y#Q)Pt zQpcGI^FfwYsad4H>7+=HL;kG1p{$ olhmzUyS^TDaer|Ctb~YMo-sJWzu6s8HMrA;$TVq_8w zB>{$#6k!?)l;8zo5n3jMl`gR7V_|f))v)&$QbW@7`he{yt>TvM1_@?q3~+xF{4^Zb z9c6$$Oz}P^`6nwz|6DHV#f{z;D zP!p^lfjhXt07seNCJKJr04JH??LoPuKwaG43-Nx{Abc(DoI zLczTZ@DdDbIa!l8ZXYT3YVf-sw0kVTQpO>+jyFd}sNOPWs<-8GuOq!xpyo5(04le82CVrT2=gEv0KrW28AyY5#odDmAa&qPCR&o( z90yWc=q%Ds=L^Tv9)};GkJB}abPr1#xTV9O2RhCgSbH#=?_i&&KOLjfYdK{ANk|>r z3rABV%t|YV9A2&F22{0?+OfG89gh94^3|XYk zt_iaAykci8G*j03V^D#NFQ^PDWQcV4MY<-Dt}U+Qfu(5pZ_3GWp%Lmw0d;y_B4o#f zTBv`D)7k5JBR~qMqh=};XJ{?-Uqemvshau%0zwW5lm-`M(ePFcM>M=iy+x#JC3UT> ztI3iVdbJg)JE!OQQnl%M4|+ifEyoWR)N%-5+VI|Rk1f@6OB)fOi^G{9x70&ApsM8z zu#!I++|m<}Fin!~hgYYm9=tM46X&>Lmc9ZJ?1`;ml18!+YK;K5B!hmyI*tWa%UK6H zSi3m|Rur7{GEnd_D7XV_4h6WDQvh0EbP#L~Yf@KBF6M{o~*}y7j}}` z(*egT{5aiH-BpNDU;;Fp=3H24k*-z;t8gBN2?VKAg9C@+X)Vw;eo9PxQ9=^a$nI;3vmA;2OX!XQ7VrD1FIOMnNzbK{i+dY>_SX z7j=y|Dk{CkU9=5!M7mSDZ((%J%oln+odt2gQu8d_S3_2bo}meZxh0@jKm#r|mKp~w zeEwXohsIWeslkm|8@2QoOZ93_iJqkiHnq1Bbe}Z3)_I)OeW!&8O5F!aPNhpa7}bp3 zZMA@5;V_011ScUqT)LBVbfu=}ALfn_;;_nK!${qCdR{mWAu7t$a?-! zA>JfhU8HAqbKfTyOPUz1OdQ4IhXFqau$1r&R9D7NMkp)PQq6+4$P97>$vPcSRTPSk z`Wo9~HZUPsq2rvnt8h=~wJ!I7=81L|K{&1DyahVI6qp&D zg>x$m-NVcunD!D(Y69r#d5_>EjRS00-=}(w4Ha2UgZf$*RN}UpageI^WR)ZN3D2)5&Gc;7&lNSqOQ+<)T_K5K@6 zIQ*nWPL{{RTz%giHy7(nYGWPryhf08Ripr?FXNo@c)n4t$9b`Qvbu>6umc$Y>3~?^ z)np}pO7S}=(gTEm_Et!4Of^iqSb!Tzg{Sw)MGz-r5ymi;8Ur?x4rEFAX#6fhW1;8i zpdqtJ#cZFIyJh#noeG~0tks^>vGBHH;uGjeOLF)R%KK(pszbSvhH@c)qnzHWKXgFv z+8J+PzXWY!>Id54wQMRj~s7Ukh`Sr5~+<=uT)O>A zfTKIUrqO%`%?oKx(tIn;t7zUx^WSOylIE6lJ3VRcNpoMChtYZiX>Lt({H_3B%W2sl zAyh--pVIs)&5il5<4rx$LhO@~8_l~=G`?%bp1B-oFGMJNT@8xHJX;XK;i5yS1nA9&+LE9JC7MOuqmUHIpj{=JO?6Hr z&z6cLnQ=0y+9barQAf*VS<>vW3bj-&8>7ijmnf-R2qQtiQ+||Op4Sx~Ezgr1i*=Ph zS~5FMrqHyvo7AygkvLtFM>k8Ahkk-evRIidQO8JTNi!sd{$N}@OA@V7DkUi{ZV;hRZcr5Wl1vBs`mkW=HELJiJKE!L0P{^e>2iX*NYvVMr6wK)eVH`pi)Q`hNoIp#|r#R?xnc zH5*w2X6y6H378&S%)Iz4KxBM5hx!>3$z{RE1;`D zKLb4j>K+E41c73KrUT6ZdLQT$pmRX@MW!>Hfx>|%1I+}&FJD&y;gK>C3$YOgS)gvn z5?LW@WP@yx9kPer=zzMzr%6Zfp*++R^+L|bg|ZD@Zh7C#JcH-K4?~w0m^K?7&AB<) zZo6pobB_d6L- zV{M&a+OE%$GvO3voV@_Ajx;@WW$k+ih2W)5@J2<1`dbL=)j?o$YD;+b(_OH}T z{4IF{@z2TYx@u)Ka*q5spy-8;Ci5-NSkU zu$yLjy&={u1ih}Vf6fDjS^0O*1Dl!fR3|9q8N$p=r9`DdXa`Fq7iWs3=}NJ3_5_4R z$0m-66$SWH#s-x#6D1HAOK?yVTQ~u&#PT?eL^(S}oTrgs2nl0Sgb8uR65SBAFiM&y zp&#%#S(ZFWI!7`AY~QOn6Tkw3Vtb8HUrKCZQry@vR0kAjNy3C!;l#Ajk&_Wb z@*_tE05TCn0K_MyL?;UT2}6IUGSbqb6^e-&3fu=Z#PN?9Y2tiUcABIRhx`c^SxO0n zdU>q0d~qK91S2g&sYW-MX;L^5fO}JX)+!Ym|UO zm@n6;;5b74&SeTK4Z4_%YT0QT8I`hPre(DEdp(o}pCFe}gJZJO=+sqw^9m+_lJ z{6_Yl>%Vmd@Ht==Pz{``@HxPE#=`tvpbEe--vM+G()gTE31@^tNaHhFI8Y&+Ga`X+ z0;&&!GXd})fEpp)1U#ab0gnW(b3y1j;Q05HbwGhowjMas6``kq*L*vcB`EVB72{`5x=`=p; z;q#pWaLj+9)A-!xz&GHS524f0+JE82fO8Ve9ZYA(!QrzO6>uGBP`LN_sM5|#JJ2s`T$ zVwFmgpPo0H4;9E%;ocghEKHS=Bgq%5eDb9kO1Vm&rS{2?=ZA?^`M$FR-h6P5(kyrp zM+ZoT)}Sgre}r18QK@mnMAz2;FKP?uPnCm`DoKV$DOJy=Wk8gYnHp$Cl9`~C&H^u* zEm4^=&9h?*p(uXwDU!^R$t8?&O=eIh`~Oa?<>Ls(gGhS;;1@QRMev9KOu0WYtL zgP9C=#bjb45nzUJ2`?4{Rq!{ugS{R>{f$NG@L56*A1NeA4HSX@h<;{uvYobtNVb0$ za_Q&B-8YlPpEmJ#UjDPFqS$2%QOwy$6tmy1U@;j?rUN@|?jr7y_=Si=vP{B8wd zXX-J-2Ktsqb(J-qZQ;lqpCsTBjus$TJKDxbv!&4zrJ5fn%MiE_y)bO!=ul8l;F}3q z8Ia`*hD0!g7=*J}j{Qv~VpI6h5X|$Fq}ehsS^Q`re_#?R^dCgH_p%cVBLe*i!!;Si z5D)|5$OPA9qUfQ(jc~>Fac!Njsesc7f2=YajMN-4HVXnrqPv9+J)0w#3>MXESHi^{ zWI9?yC@zK2UnUg`x)WSnA;-}&T0jH^hXjWTdK1nVvU2Pm97GWOH=vaQ@oaun-mFZ4 zJz9j6Dk4w;r68sNg50@%&bVhmKH%r%=t{8j?LJ)I^p9;u*9ogYZQ=!7I2Sq>Qlip$Q(Lx_Qei*!(dW75@@hroa1@qkvCI@ym1Ld4NJ1gh;>G}5ZPbc^- zu(?(5I5)vjetp@}0b$22qxCi;!lv98y!%=7`fEi- z^2TSkORW3a&2>HeY1W1E8Jk{KcrjcH_>7fn<2~jck8-QnbbVX;&69Ta&o8`lW4T|> zvJDbvm1wh1ROYAAx5Dqdo1olsYKp7HuKlua?zkuax_?lr{PcNA&vKu^Yg4WcMK{k* zJ(K;5{kp{MmU}+1Iv_`0H8Ixrlj~-#dn-e9XpjZ-kk5*BSB^fv@pSArA=lruC5kO( zfTd2Ptu%}AAu~)rabNB?SML7Yt1ZiX$~a)9(>t1>f8R>?qaGZv($2=U;|o+R@Tjqri*sfV~Ti^f5ww{I&!l)qDjX z-hwOSvP_BcFAd(N%&E`k9cU^Z*3|U-slh+TX@=L!nvyV50%O`nU`?|%HEN1?`k>lCLKu^#V~#f+ctT*g^Ce(`K_)RQyz<=eg= zllJ5G!#C?fhE4`P)6;(hDMhixK3X8EnwKV24YUvS~x zQrn;@bE@YYEv&7x@EzrFy1bb^{n`nY`p+?qFF%cZxc|IjR7uO#$PJUizT;UBazY<-cK0iW!+k)4*gx*%bF;Mk4&=K?Xl$;3Ez7GYUS$D_J0^ zQ4ajfK?SL3>PHW1kg|X>;D--5mf=H64kc9}Nr5yJiuJ{ilK~nEK*XSd)8@5eDF(`9 z0~zbatt22n>YhZ^A%lMfH1q=NCqf;0&`bQoi)@e+pk^i1kNYhIL<#v4ln*2Wl#dFi z-eLmWTYzoy%L_a8QXKEZBCHuIdBrxQ<(_dFcuzwXV!vwN3} z{?%PueP%u}A8&xZ>{*1G2&o9F2rTnAn)FwknDKF?O+s7@HVBj#d!=M2FZTM91;!l% zE-06f{!JGoG?pTmWy6g9{Z}ribC=bfOef`S)_E;(4T#@ApeS{1*?A8>cj4lnmgx2S zF3%V$xF6QbWoEB)pSYfw+%pudyOp=-_T9)c4{p(=HEO#7HTG}0 z9{R1~;i&?PfxMQ+cYhk+v+cO`jy~5?N$;%Fn{?KFetPff?i$}o72+FLALnlrx4dnW zf3Ju0XHUi_N3vE9$^CNNm)7K-y_aQ8zdBimx!zh9erC^%^10U=W5C;-0B^I|=xrVz zyqOkO{LtzB!UNwnzL9D^W&cxW0up{1WNQs2!{63!8oIOh(47w#?F<{%BW&f0V-s%I z)IIjwPL4S8jqLjB{>R467VnAnvpcf(V4Prg%*2Sz8{Xfxc&x{QlX())<>MnZobj0V zRa8sOob=eW^S{qfpZz$)>*=BoKim~NcK7_gryb8~*4Ev;`Sw#A+Yf#{6LB&2(>d;2 zCcYaK`1uguA%cln2mKw^uWL)(@Jn;V*Rvi)PQL!5+c3LE(AreqTjHrqx299}llP-}lk+evk96H6C!8 z`*yu!AX~uO!P20BTK>pybzOtIyx*yS=SNv zTgK-ctb>Y}`8TaYoUs&Ghw#5+9q_KBECk+ku_<`VMGL72wP=~aJQgh`iWU)(6%iF9 z%EF9QzScm#uD-liYj};Je0>eYj2ffMJ`O(i2+)Cce}LWYW+Kcu0dNBFrF;9z0YIh7 z^T|-Ce3TM}TqT8{*v$sjd?^2q6PJQh{-1W@?FY~<&!^@G*nJTvrL3o4yurBq!GPYD z%wIAxhn(zWj4A)+67Z&NQ9$suT|srX>%xv7a`m0F@yB1Iqk4V(#h4B8H}_p@DY~(q z@#yxFD=jarUi7QJH+5k{+c(wGU%o6Da_x_AR|K5TyRzS9_|LxI)V(`)N#r}{ZvM95 zA@|gz6lHVk4B=;eu8g`eFYZiM2(S8!rWJ~U#nir{c zSBib!J=$u|j{f$yms{J?FRz)grMkK;bJardU+2Jo9isi0#fv{!@3VH@Mb@n&y^kMr zHJ>tkT9R};sr>t=B~PM1Jc@9TaW%#_=BFhy$3+AQ1cLULS^glI#Q(^l?XTQbbFt5w zKhAs^_1>0+sz^n{$0^CFpVTx6Etb^(5Uw%+|upsWb zw#NGEp0m?(@9)|>Q_y-LEYfyV{JZybbAl{cJ8T1AI>!~itgRK03+K6So=MaTN zSOuKM$^wm5y*5ZO9f?f!$mQ4 z{%QPn-1v&yb6bep;VFamBwk2t5xlV@C3WrKbIr@=nF_a{zMww4Lfw{H))y*6}P&2Q)33TLhIQr#ZB=U9M6JDm>bU(qIy8Y#|ZXsjsPEB1=$<2;E_f5(DJ1gzV z_eqzIeKx7dgWK@wZZz+~M^W|{R($Jyq~`o;nb-HZjvn2|;iCel>UCrNCckGn$YFq>nC$}}X$CPF45Db^fA)ye#W$h$Z&eiv z!olp@l&t{2zjZM!pcPACYnII>`j|;J)VGuNPhC8C9cWy6E4BdM$UlEN>q*hR4>M<6 zd-GKOiP=t##VyI^+XKFRu#4ea*tEgH=iQGC<7zw>$KA>Dn)d4#<9A=oY>adb|9<=B zXFcTEXChWo&rrsfaa_;cMPUyUqz)uc6N2Pt}1@42XVyve#1DtfYL`K5!;p0sK2dawM_bJejQ z&i$0Avg_^H^XunRM_&Etz>>0GvwLlR>%`3M;=ohdH|LKk)jWIBujrxWQ(FmZ!ObsY z__kvQ1y4A-Zk#;n#mOFg?XLRZMKkXV*mq}Wqzw_fd_yslOB6HVZ4mu!(aJ(l%yGj)z7XzwY!TI|!F!x3=d3ttfalHpGb3m7Jt{K}RX zHm#*$kxyQ8LU8Lq+uYSlo=!`A(Z!Y+z^xG}whv2|KTp%VH|4UvX62X!oA@Oslz&vU zEN&yUd$geeXC-YtH~#)$&2RTF23^>5*W&#>C90e^J!8-9xuz$szxS(6+B)X2eVQrz zF8hfG=6y0{?K^V{#{C>24>|6)E^+DX(veq_w$3|RxK&oUA5GUt?tih$=DGUV*Pr@Y zKWVkyUfCzt?dsaaB}tL#%ig|~_rr!q$v;XTeJLwmHRX%%+rl1QI&k9oQZJV;BI0uk z_X-}gZd!ULQd2zn*FSB}6~^`)I{Z;t{lZb2ZhhuA3%|X%H>Aqti0{INc{^T)&YYCX rYgt=ec=FUdM(^gS=YMyM;EbK+kuyUZoX}Li>%`|brq-UKKBxabW4+R- literal 0 HcmV?d00001 diff --git a/RGB.NET.Devices.Logitech/libs/x86/LogitechLedEnginesWrapper.dll b/RGB.NET.Devices.Logitech/libs/x86/LogitechLedEnginesWrapper.dll new file mode 100644 index 0000000000000000000000000000000000000000..a33fa4057b8e73adce471154fbaba3bea9f6d418 GIT binary patch literal 18040 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 literal 0 HcmV?d00001 diff --git a/RGB.NET.Devices.Logitech/packages.config b/RGB.NET.Devices.Logitech/packages.config new file mode 100644 index 0000000..32c0f53 --- /dev/null +++ b/RGB.NET.Devices.Logitech/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/RGB.NET.Devices.Logitech/targets/RGB.NET.Devices.Logitech.targets b/RGB.NET.Devices.Logitech/targets/RGB.NET.Devices.Logitech.targets new file mode 100644 index 0000000..decacc5 --- /dev/null +++ b/RGB.NET.Devices.Logitech/targets/RGB.NET.Devices.Logitech.targets @@ -0,0 +1,150 @@ + + + + + + + + + + + False + + + False + + + + + + + + %(RecursiveDir)%(FileName)%(Extension) + Always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bin\%(RecursiveDir)%(Filename)%(Extension) + + + + + + + + + + + + + + + + + + + + + + + $(PostBuildEventDependsOn); + CopyLogitechSDKFiles; + + + $(BuildDependsOn); + CopyLogitechSDKFiles; + + + $(CleanDependsOn); + CleanLogitechSDKFiles; + + + + + + + + CollectLogitechSDKFiles; + $(PipelineCollectFilesPhaseDependsOn); + + + diff --git a/RGB.NET.sln b/RGB.NET.sln index 3aca62e..94a8642 100644 --- a/RGB.NET.sln +++ b/RGB.NET.sln @@ -31,6 +31,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{06416566 NuGet\RGB.NET.Brushes.nuspec = NuGet\RGB.NET.Brushes.nuspec NuGet\RGB.NET.Core.nuspec = NuGet\RGB.NET.Core.nuspec NuGet\RGB.NET.Devices.Corsair.nuspec = NuGet\RGB.NET.Devices.Corsair.nuspec + NuGet\RGB.NET.Devices.Logitech.nuspec = NuGet\RGB.NET.Devices.Logitech.nuspec NuGet\RGB.NET.Effects.nuspec = NuGet\RGB.NET.Effects.nuspec NuGet\RGB.NET.Groups.nuspec = NuGet\RGB.NET.Groups.nuspec NuGet\RGB.NET.Input.Corsair.nuspec = NuGet\RGB.NET.Input.Corsair.nuspec @@ -42,6 +43,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{BD7C9994-1747- EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RGB.NET.WPF", "RGB.NET.WPF\RGB.NET.WPF.csproj", "{8D6C4FE6-0046-4E98-876F-4C0B87249989}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RGB.NET.Devices.Logitech", "RGB.NET.Devices.Logitech\RGB.NET.Devices.Logitech.csproj", "{E7B2F174-FCC6-4FC7-9970-3138B5F4C921}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -80,6 +83,10 @@ Global {8D6C4FE6-0046-4E98-876F-4C0B87249989}.Debug|Any CPU.Build.0 = Debug|Any CPU {8D6C4FE6-0046-4E98-876F-4C0B87249989}.Release|Any CPU.ActiveCfg = Release|Any CPU {8D6C4FE6-0046-4E98-876F-4C0B87249989}.Release|Any CPU.Build.0 = Release|Any CPU + {E7B2F174-FCC6-4FC7-9970-3138B5F4C921}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7B2F174-FCC6-4FC7-9970-3138B5F4C921}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7B2F174-FCC6-4FC7-9970-3138B5F4C921}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7B2F174-FCC6-4FC7-9970-3138B5F4C921}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -92,5 +99,6 @@ Global {F905C418-76BB-4BA6-88AB-0793BC2681D3} = {C854766D-9C1D-474B-B5B8-249DF4A9E552} {2A39F859-AAD0-4C16-94F8-78057820B376} = {FFBCAF88-6646-43EC-9F24-2D719D3779C8} {8D6C4FE6-0046-4E98-876F-4C0B87249989} = {BD7C9994-1747-4595-9C21-298E8FDCB657} + {E7B2F174-FCC6-4FC7-9970-3138B5F4C921} = {33D5E279-1C4E-4AB6-9D1E-6D18109A6C25} EndGlobalSection EndGlobal