From 7690a49e43e533194bfd74cb6698a645e5e72574 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Wed, 11 Dec 2019 22:34:19 +0100 Subject: [PATCH] Wooting device provider --- .../Enum/WootingDevicesIndexes.cs | 21 ++ .../Enum/WootingLogicalKeyboardLayout.cs | 16 ++ .../Enum/WootingPhysicalKeyboardLayout.cs | 16 ++ .../Generic/IWootingRGBDevice.cs | 12 + .../Generic/WootingRGBDevice.cs | 71 +++++ .../Generic/WootingRGBDeviceInfo.cs | 62 +++++ .../Helper/EnumExtension.cs | 41 +++ .../Keyboard/WootingKeyboardLedMappings.cs | 262 ++++++++++++++++++ .../Keyboard/WootingKeyboardRGBDevice.cs | 53 ++++ .../Keyboard/WootingKeyboardRGBDeviceInfo.cs | 57 ++++ RGB.NET.Devices.Wooting/Native/_WootingSDK.cs | 123 ++++++++ .../RGB.NET.Devices.Wooting.csproj | 68 +++++ .../WootingDeviceProvider.cs | 120 ++++++++ .../WootingDeviceProviderLoader.cs | 24 ++ RGB.NET.sln | 11 +- 15 files changed, 955 insertions(+), 2 deletions(-) create mode 100644 RGB.NET.Devices.Wooting/Enum/WootingDevicesIndexes.cs create mode 100644 RGB.NET.Devices.Wooting/Enum/WootingLogicalKeyboardLayout.cs create mode 100644 RGB.NET.Devices.Wooting/Enum/WootingPhysicalKeyboardLayout.cs create mode 100644 RGB.NET.Devices.Wooting/Generic/IWootingRGBDevice.cs create mode 100644 RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs create mode 100644 RGB.NET.Devices.Wooting/Generic/WootingRGBDeviceInfo.cs create mode 100644 RGB.NET.Devices.Wooting/Helper/EnumExtension.cs create mode 100644 RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardLedMappings.cs create mode 100644 RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs create mode 100644 RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDeviceInfo.cs create mode 100644 RGB.NET.Devices.Wooting/Native/_WootingSDK.cs create mode 100644 RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj create mode 100644 RGB.NET.Devices.Wooting/WootingDeviceProvider.cs create mode 100644 RGB.NET.Devices.Wooting/WootingDeviceProviderLoader.cs diff --git a/RGB.NET.Devices.Wooting/Enum/WootingDevicesIndexes.cs b/RGB.NET.Devices.Wooting/Enum/WootingDevicesIndexes.cs new file mode 100644 index 0000000..c25afa4 --- /dev/null +++ b/RGB.NET.Devices.Wooting/Enum/WootingDevicesIndexes.cs @@ -0,0 +1,21 @@ +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global + +using System.ComponentModel; + +#pragma warning disable 1591 // Missing XML comment for publicly visible type or member + +namespace RGB.NET.Devices.Wooting.Enum +{ + /// + /// Contains a list of available device-indexes. + /// + public enum WootingDevicesIndexes + { + [Description("Wooting One")] + WootingOne = 0, + + [Description("Wooting Two")] + WootingTwo = 1 + } +} diff --git a/RGB.NET.Devices.Wooting/Enum/WootingLogicalKeyboardLayout.cs b/RGB.NET.Devices.Wooting/Enum/WootingLogicalKeyboardLayout.cs new file mode 100644 index 0000000..f21929d --- /dev/null +++ b/RGB.NET.Devices.Wooting/Enum/WootingLogicalKeyboardLayout.cs @@ -0,0 +1,16 @@ +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global + +#pragma warning disable 1591 // Missing XML comment for publicly visible type or member + +namespace RGB.NET.Devices.Wooting.Enum +{ + /// + /// Contains list of available logical layouts for cooler master keyboards. + /// + public enum WootingLogicalKeyboardLayout + { + US = 0, + EU = 1 + }; +} diff --git a/RGB.NET.Devices.Wooting/Enum/WootingPhysicalKeyboardLayout.cs b/RGB.NET.Devices.Wooting/Enum/WootingPhysicalKeyboardLayout.cs new file mode 100644 index 0000000..2142d50 --- /dev/null +++ b/RGB.NET.Devices.Wooting/Enum/WootingPhysicalKeyboardLayout.cs @@ -0,0 +1,16 @@ +// ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global + +#pragma warning disable 1591 // Missing XML comment for publicly visible type or member + +namespace RGB.NET.Devices.Wooting.Enum +{ + /// + /// Contains list of available physical layouts for Wooting keyboards. + /// + public enum WootingPhysicalKeyboardLayout + { + US = 0, + EU = 1 + } +} diff --git a/RGB.NET.Devices.Wooting/Generic/IWootingRGBDevice.cs b/RGB.NET.Devices.Wooting/Generic/IWootingRGBDevice.cs new file mode 100644 index 0000000..42c6995 --- /dev/null +++ b/RGB.NET.Devices.Wooting/Generic/IWootingRGBDevice.cs @@ -0,0 +1,12 @@ +using RGB.NET.Core; + +namespace RGB.NET.Devices.Wooting.Generic +{ + /// + /// Represents a Wooting RGB-device. + /// + internal interface IWootingRGBDevice : IRGBDevice + { + void Initialize(UpdateQueue updateQueue); + } +} diff --git a/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs b/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs new file mode 100644 index 0000000..6fd6af7 --- /dev/null +++ b/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Native; + +namespace RGB.NET.Devices.Wooting.Generic +{ + /// + /// + /// + /// Represents a Wooting-device + /// + public abstract class WootingRGBDevice : AbstractRGBDevice, IWootingRGBDevice + where TDeviceInfo : WootingRGBDeviceInfo + { + #region Properties & Fields + + /// + /// + /// Gets information about the . + /// + public override TDeviceInfo DeviceInfo { get; } + + /// + /// Gets or sets the update queue performing updates for this device. + /// + // ReSharper disable once MemberCanBePrivate.Global + protected UpdateQueue UpdateQueue { get; set; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The generic information provided by Wooting for the device. + protected WootingRGBDevice(TDeviceInfo info) + { + this.DeviceInfo = info; + } + + #endregion + + #region Methods + + /// + /// Initializes the device. + /// + public void Initialize(UpdateQueue updateQueue) + { + InitializeLayout(); + + if (Size == Size.Invalid) + { + Rectangle ledRectangle = new Rectangle(this.Select(x => x.LedRectangle)); + Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y); + } + + UpdateQueue = updateQueue; + } + + /// + /// Initializes the and of the device. + /// + protected abstract void InitializeLayout(); + + #endregion + } +} diff --git a/RGB.NET.Devices.Wooting/Generic/WootingRGBDeviceInfo.cs b/RGB.NET.Devices.Wooting/Generic/WootingRGBDeviceInfo.cs new file mode 100644 index 0000000..bf91f8d --- /dev/null +++ b/RGB.NET.Devices.Wooting/Generic/WootingRGBDeviceInfo.cs @@ -0,0 +1,62 @@ +using System; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Enum; +using RGB.NET.Devices.Wooting.Helper; + +namespace RGB.NET.Devices.Wooting.Generic +{ + /// + /// + /// Represents a generic information for a Wooting-. + /// + public class WootingRGBDeviceInfo : IRGBDeviceInfo + { + #region Properties & Fields + + /// + public RGBDeviceType DeviceType { get; } + + /// + public string DeviceName { get; } + + /// + public string Manufacturer => "Wooting"; + + /// + public string Model { get; } + + /// + public Uri Image { get; set; } + + /// + public RGBDeviceLighting Lighting => RGBDeviceLighting.Key; + + /// + public bool SupportsSyncBack => false; + + /// + /// Gets the of the . + /// + public WootingDevicesIndexes DeviceIndex { get; } + + #endregion + + #region Constructors + + /// + /// Internal constructor of managed . + /// + /// The type of the . + /// The of the . + internal WootingRGBDeviceInfo(RGBDeviceType deviceType, WootingDevicesIndexes deviceIndex) + { + this.DeviceType = deviceType; + this.DeviceIndex = deviceIndex; + + Model = deviceIndex.GetDescription(); + DeviceName = $"{Manufacturer} {Model}"; + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Wooting/Helper/EnumExtension.cs b/RGB.NET.Devices.Wooting/Helper/EnumExtension.cs new file mode 100644 index 0000000..7c2e8b3 --- /dev/null +++ b/RGB.NET.Devices.Wooting/Helper/EnumExtension.cs @@ -0,0 +1,41 @@ +using System; +using System.ComponentModel; +using System.Reflection; +using RGB.NET.Core; + +namespace RGB.NET.Devices.Wooting.Helper +{ + /// + /// Offers some extensions and helper-methods for enum related things. + /// + internal static class EnumExtension + { + /// + /// Gets the value of the . + /// + /// The enum value to get the description from. + /// The generic enum-type + /// The value of the or the result of the source. + internal static string GetDescription(this T source) + where T : struct + { + return source.GetAttribute()?.Description ?? source.ToString(); + } + + /// + /// Gets the attribute of type T. + /// + /// The enum value to get the attribute from + /// The generic attribute type + /// The generic enum-type + /// The . + private static T GetAttribute(this TEnum source) + where T : Attribute + where TEnum : struct + { + FieldInfo fi = source.GetType().GetField(source.ToString()); + T[] attributes = (T[])fi.GetCustomAttributes(typeof(T), false); + return attributes.Length > 0 ? attributes[0] : null; + } + } +} diff --git a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardLedMappings.cs b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardLedMappings.cs new file mode 100644 index 0000000..ebc62d3 --- /dev/null +++ b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardLedMappings.cs @@ -0,0 +1,262 @@ +// ReSharper disable InconsistentNaming + +using System.Collections.Generic; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Enum; + +namespace RGB.NET.Devices.Wooting.Keyboard +{ + /// + /// Contains all the hardware-id mappings for Wooting devices. + /// + internal static class WootingKeyboardLedMappings + { + #region Properties & Fields + + #region Wooting One + + private static readonly Dictionary WootingOne_US = new Dictionary + { + { LedId.Keyboard_Escape, (0,0) }, + { LedId.Keyboard_F1, (0,2) }, + { LedId.Keyboard_F2, (0,3) }, + { LedId.Keyboard_F3, (0,4) }, + { LedId.Keyboard_F4, (0,5) }, + { LedId.Keyboard_F5, (0,6) }, + { LedId.Keyboard_F6, (0,7) }, + { LedId.Keyboard_F7, (0,8) }, + { LedId.Keyboard_F8, (0,9) }, + { LedId.Keyboard_F9, (0,10) }, + { LedId.Keyboard_F10, (0,11) }, + { LedId.Keyboard_F11, (0,12) }, + { LedId.Keyboard_F12, (0,13) }, + { LedId.Keyboard_PrintScreen, (0,14) }, + { LedId.Keyboard_PauseBreak, (0,15) }, + { LedId.Keyboard_Custom1, (0,20) }, // TODO: Make sure it is not 0,16 + + { LedId.Keyboard_GraveAccentAndTilde, (1,0) }, + { LedId.Keyboard_1, (1,1) }, + { LedId.Keyboard_2, (1,2) }, + { LedId.Keyboard_3, (1,3) }, + { LedId.Keyboard_4, (1,4) }, + { LedId.Keyboard_5, (1,5) }, + { LedId.Keyboard_6, (1,6) }, + { LedId.Keyboard_7, (1,7) }, + { LedId.Keyboard_8, (1,8) }, + { LedId.Keyboard_9, (1,9) }, + { LedId.Keyboard_0, (1,10) }, + { LedId.Keyboard_MinusAndUnderscore, (1,11) }, + { LedId.Keyboard_EqualsAndPlus, (1,12) }, + { LedId.Keyboard_Backspace, (1,13) }, + { LedId.Keyboard_Insert, (1,14) }, + { LedId.Keyboard_Home, (1,15) }, + { LedId.Keyboard_PageUp, (1,16) }, + + { LedId.Keyboard_Tab, (2,0) }, + { LedId.Keyboard_Q, (2,1) }, + { LedId.Keyboard_W, (2,2) }, + { LedId.Keyboard_E, (2,3) }, + { LedId.Keyboard_R, (2,4) }, + { LedId.Keyboard_T, (2,5) }, + { LedId.Keyboard_Y, (2,6) }, + { LedId.Keyboard_U, (2,7) }, + { LedId.Keyboard_I, (2,8) }, + { LedId.Keyboard_O, (2,9) }, + { LedId.Keyboard_P, (2,10) }, + { LedId.Keyboard_BracketLeft, (2,11) }, + { LedId.Keyboard_BracketRight, (2,12) }, + { LedId.Keyboard_Backslash, (2,13) }, + { LedId.Keyboard_Delete, (2,14) }, + { LedId.Keyboard_End, (2,15) }, + { LedId.Keyboard_PageDown, (2,16) }, + + { LedId.Keyboard_CapsLock, (3,0) }, + { LedId.Keyboard_A, (3,1) }, + { LedId.Keyboard_S, (3,2) }, + { LedId.Keyboard_D, (3,3) }, + { LedId.Keyboard_F, (3,4) }, + { LedId.Keyboard_G, (3,5) }, + { LedId.Keyboard_H, (3,6) }, + { LedId.Keyboard_J, (3,7) }, + { LedId.Keyboard_K, (3,8) }, + { LedId.Keyboard_L, (3,9) }, + { LedId.Keyboard_SemicolonAndColon, (3,10) }, + { LedId.Keyboard_ApostropheAndDoubleQuote, (3,11) }, + { LedId.Keyboard_Enter, (3,13) }, + + { LedId.Keyboard_LeftShift, (4,0) }, + { LedId.Keyboard_NonUsBackslash, (4,1) }, + { LedId.Keyboard_Z, (4,2) }, + { LedId.Keyboard_X, (4,3) }, + { LedId.Keyboard_C, (4,4) }, + { LedId.Keyboard_V, (4,5) }, + { LedId.Keyboard_B, (4,6) }, + { LedId.Keyboard_N, (4,7) }, + { LedId.Keyboard_M, (4,8) }, + { LedId.Keyboard_CommaAndLessThan, (4,9) }, + { LedId.Keyboard_PeriodAndBiggerThan, (4,10) }, + { LedId.Keyboard_SlashAndQuestionMark, (4,11) }, + { LedId.Keyboard_RightShift, (4,13) }, + { LedId.Keyboard_ArrowUp, (4,15) }, + + { LedId.Keyboard_LeftCtrl, (5,0) }, + { LedId.Keyboard_LeftGui, (5,1) }, + { LedId.Keyboard_LeftAlt, (5,2) }, + { LedId.Keyboard_Space, (5,6) }, + { LedId.Keyboard_RightAlt, (5,10) }, + { LedId.Keyboard_RightGui, (5,11) }, + { LedId.Keyboard_Application, (5,12) }, + { LedId.Keyboard_RightCtrl, (5,13) }, + { LedId.Keyboard_ArrowLeft, (5,14) }, + { LedId.Keyboard_ArrowDown, (5,15) }, + { LedId.Keyboard_ArrowRight, (5,16) } + }; + + #endregion + + #region Wooting Two + + private static readonly Dictionary WootingTwo_US = new Dictionary + { + { LedId.Keyboard_Escape, (0,0) }, + { LedId.Keyboard_F1, (0,2) }, + { LedId.Keyboard_F2, (0,3) }, + { LedId.Keyboard_F3, (0,4) }, + { LedId.Keyboard_F4, (0,5) }, + { LedId.Keyboard_F5, (0,6) }, + { LedId.Keyboard_F6, (0,7) }, + { LedId.Keyboard_F7, (0,8) }, + { LedId.Keyboard_F8, (0,9) }, + { LedId.Keyboard_F9, (0,10) }, + { LedId.Keyboard_F10, (0,11) }, + { LedId.Keyboard_F11, (0,12) }, + { LedId.Keyboard_F12, (0,13) }, + { LedId.Keyboard_PrintScreen, (0,14) }, + { LedId.Keyboard_PauseBreak, (0,15) }, + { LedId.Keyboard_ScrollLock, (0,16) }, + { LedId.Keyboard_Custom1, (0,17) }, + { LedId.Keyboard_Custom2, (0,18) }, + { LedId.Keyboard_Custom3, (0,19) }, + { LedId.Keyboard_Custom4, (0,20) }, + + { LedId.Keyboard_GraveAccentAndTilde, (1,0) }, + { LedId.Keyboard_1, (1,1) }, + { LedId.Keyboard_2, (1,2) }, + { LedId.Keyboard_3, (1,3) }, + { LedId.Keyboard_4, (1,4) }, + { LedId.Keyboard_5, (1,5) }, + { LedId.Keyboard_6, (1,6) }, + { LedId.Keyboard_7, (1,7) }, + { LedId.Keyboard_8, (1,8) }, + { LedId.Keyboard_9, (1,9) }, + { LedId.Keyboard_0, (1,10) }, + { LedId.Keyboard_MinusAndUnderscore, (1,11) }, + { LedId.Keyboard_EqualsAndPlus, (1,12) }, + { LedId.Keyboard_Backspace, (1,13) }, + { LedId.Keyboard_Insert, (1,14) }, + { LedId.Keyboard_Home, (1,15) }, + { LedId.Keyboard_PageUp, (1,16) }, + { LedId.Keyboard_NumLock, (1,17) }, + { LedId.Keyboard_NumSlash, (1,18) }, + { LedId.Keyboard_NumAsterisk, (1,19) }, + { LedId.Keyboard_NumMinus, (1,20) }, + + { LedId.Keyboard_Tab, (2,0) }, + { LedId.Keyboard_Q, (2,1) }, + { LedId.Keyboard_W, (2,2) }, + { LedId.Keyboard_E, (2,3) }, + { LedId.Keyboard_R, (2,4) }, + { LedId.Keyboard_T, (2,5) }, + { LedId.Keyboard_Y, (2,6) }, + { LedId.Keyboard_U, (2,7) }, + { LedId.Keyboard_I, (2,8) }, + { LedId.Keyboard_O, (2,9) }, + { LedId.Keyboard_P, (2,10) }, + { LedId.Keyboard_BracketLeft, (2,11) }, + { LedId.Keyboard_BracketRight, (2,12) }, + { LedId.Keyboard_Backslash, (2,13) }, + { LedId.Keyboard_Delete, (2,14) }, + { LedId.Keyboard_End, (2,15) }, + { LedId.Keyboard_PageDown, (2,16) }, + { LedId.Keyboard_Num7, (2,17) }, + { LedId.Keyboard_Num8, (2,18) }, + { LedId.Keyboard_Num9, (2,19) }, + { LedId.Keyboard_NumPlus, (2,20) }, + + { LedId.Keyboard_CapsLock, (3,0) }, + { LedId.Keyboard_A, (3,1) }, + { LedId.Keyboard_S, (3,2) }, + { LedId.Keyboard_D, (3,3) }, + { LedId.Keyboard_F, (3,4) }, + { LedId.Keyboard_G, (3,5) }, + { LedId.Keyboard_H, (3,6) }, + { LedId.Keyboard_J, (3,7) }, + { LedId.Keyboard_K, (3,8) }, + { LedId.Keyboard_L, (3,9) }, + { LedId.Keyboard_SemicolonAndColon, (3,10) }, + { LedId.Keyboard_ApostropheAndDoubleQuote, (3,11) }, + { LedId.Keyboard_Enter, (3,13) }, + { LedId.Keyboard_Num4, (3,17) }, + { LedId.Keyboard_Num5, (3,18) }, + { LedId.Keyboard_Num6, (3,19) }, + + { LedId.Keyboard_LeftShift, (4,0) }, + { LedId.Keyboard_NonUsBackslash, (4,1) }, + { LedId.Keyboard_Z, (4,2) }, + { LedId.Keyboard_X, (4,3) }, + { LedId.Keyboard_C, (4,4) }, + { LedId.Keyboard_V, (4,5) }, + { LedId.Keyboard_B, (4,6) }, + { LedId.Keyboard_N, (4,7) }, + { LedId.Keyboard_M, (4,8) }, + { LedId.Keyboard_CommaAndLessThan, (4,9) }, + { LedId.Keyboard_PeriodAndBiggerThan, (4,10) }, + { LedId.Keyboard_SlashAndQuestionMark, (4,11) }, + { LedId.Keyboard_RightShift, (4,13) }, + { LedId.Keyboard_ArrowUp, (4,15) }, + { LedId.Keyboard_Num1, (4,17) }, + { LedId.Keyboard_Num2, (4,18) }, + { LedId.Keyboard_Num3, (4,19) }, + { LedId.Keyboard_NumEnter, (4,20) }, + + { LedId.Keyboard_LeftCtrl, (5,0) }, + { LedId.Keyboard_LeftGui, (5,1) }, + { LedId.Keyboard_LeftAlt, (5,2) }, + { LedId.Keyboard_Space, (5,6) }, + { LedId.Keyboard_RightAlt, (5,10) }, + { LedId.Keyboard_RightGui, (5,11) }, + { LedId.Keyboard_Application, (5,12) }, + { LedId.Keyboard_RightCtrl, (5,13) }, + { LedId.Keyboard_ArrowLeft, (5,14) }, + { LedId.Keyboard_ArrowDown, (5,15) }, + { LedId.Keyboard_ArrowRight, (5,16) }, + { LedId.Keyboard_Num0, (5,18) }, + { LedId.Keyboard_NumPeriodAndDelete, (5,19) } + }; + + #endregion + + /// + /// Contains all the hardware-id mappings for Wooting devices. + /// + public static readonly Dictionary>> Mapping = + new Dictionary>> + { + { WootingDevicesIndexes.WootingOne, new Dictionary> + { + { WootingPhysicalKeyboardLayout.US, WootingOne_US }, + { WootingPhysicalKeyboardLayout.EU, WootingOne_US } + } + }, + + { WootingDevicesIndexes.WootingTwo, new Dictionary> + { + { WootingPhysicalKeyboardLayout.US, WootingTwo_US }, + { WootingPhysicalKeyboardLayout.EU, WootingTwo_US } + } + } + }; + + #endregion + } +} diff --git a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs new file mode 100644 index 0000000..0b3334a --- /dev/null +++ b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.Linq; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Generic; + +namespace RGB.NET.Devices.Wooting.Keyboard +{ + /// + /// + /// Represents a Wooting keyboard. + /// + public class WootingKeyboardRGBDevice : WootingRGBDevice + { + #region Constructors + + /// + /// + /// Initializes a new instance of the class. + /// + /// The specific information provided by Wooting for the keyboard + internal WootingKeyboardRGBDevice(WootingKeyboardRGBDeviceInfo info) + : base(info) + { } + + #endregion + + #region Methods + + /// + protected override void InitializeLayout() + { + + Dictionary mapping = WootingKeyboardLedMappings.Mapping[DeviceInfo.DeviceIndex][DeviceInfo.PhysicalLayout]; + + foreach (KeyValuePair led in mapping) + { + InitializeLed(led.Key, new Point(led.Value.column * 19, led.Value.row * 19), new Size(19,19)); + } + + string model = DeviceInfo.Model.Replace(" ", string.Empty).ToUpper(); + ApplyLayoutFromFile(PathHelper.GetAbsolutePath(this, $@"Layouts\Wooting\Keyboards\{model}", $"{DeviceInfo.PhysicalLayout.ToString().ToUpper()}.xml"), + DeviceInfo.LogicalLayout.ToString()); + } + + /// + protected override void UpdateLeds(IEnumerable ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0)); + + /// + protected override object CreateLedCustomData(LedId ledId) => WootingKeyboardLedMappings.Mapping[DeviceInfo.DeviceIndex][DeviceInfo.PhysicalLayout][ledId]; + + #endregion + } +} diff --git a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDeviceInfo.cs b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDeviceInfo.cs new file mode 100644 index 0000000..f7806f0 --- /dev/null +++ b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDeviceInfo.cs @@ -0,0 +1,57 @@ +using System; +using System.Globalization; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Enum; +using RGB.NET.Devices.Wooting.Generic; + +namespace RGB.NET.Devices.Wooting.Keyboard +{ + /// + /// + /// Represents a generic information for a . + /// + public class WootingKeyboardRGBDeviceInfo : WootingRGBDeviceInfo + { + #region Properties & Fields + + /// + /// Gets the of the . + /// + public WootingPhysicalKeyboardLayout PhysicalLayout { get; } + + /// + /// Gets the of the . + /// + public WootingLogicalKeyboardLayout LogicalLayout { get; private set; } + + #endregion + + #region Constructors + + /// + /// + /// Internal constructor of managed . + /// + /// The index of the . + /// The of the . + /// The of the layout this keyboard is using + internal WootingKeyboardRGBDeviceInfo(WootingDevicesIndexes deviceIndex, WootingPhysicalKeyboardLayout physicalKeyboardLayout, CultureInfo culture) + : base(RGBDeviceType.Keyboard, deviceIndex) + { + this.PhysicalLayout = physicalKeyboardLayout; + + // For now just go for this + switch (physicalKeyboardLayout) + { + case WootingPhysicalKeyboardLayout.US: + this.LogicalLayout = WootingLogicalKeyboardLayout.US; + break; + case WootingPhysicalKeyboardLayout.EU: + this.LogicalLayout = WootingLogicalKeyboardLayout.EU; + break; + } + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Wooting/Native/_WootingSDK.cs b/RGB.NET.Devices.Wooting/Native/_WootingSDK.cs new file mode 100644 index 0000000..402f6f4 --- /dev/null +++ b/RGB.NET.Devices.Wooting/Native/_WootingSDK.cs @@ -0,0 +1,123 @@ +// ReSharper disable UnusedMethodReturnValue.Global +// ReSharper disable UnusedMember.Global + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using RGB.NET.Core; + +namespace RGB.NET.Devices.Wooting.Native +{ + // ReSharper disable once InconsistentNaming + public class _WootingSDK + { + #region Library 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() + { + UnloadWootingSDK(); + LoadWootingSDK(); + } + + private static void LoadWootingSDK() + { + if (_dllHandle != IntPtr.Zero) return; + + // HACK: Load library at runtime to support both, x86 and x64 with one managed dll + List possiblePathList = Environment.Is64BitProcess ? WootingDeviceProvider.PossibleX64NativePaths : WootingDeviceProvider.PossibleX86NativePaths; + string dllPath = possiblePathList.FirstOrDefault(File.Exists); + if (dllPath == null) throw new RGBDeviceException($"Can't find the Wooting-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'"); + + SetDllDirectory(Path.GetDirectoryName(Path.GetFullPath(dllPath))); + + _dllHandle = LoadLibrary(dllPath); + + _isWootingOnePointer = (IsWootingOnePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_kbd_is_wooting_one"), typeof(IsWootingOnePointer)); + _isWootingTwoPointer = (IsWootingTwoPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_kbd_is_wooting_two"), typeof(IsWootingTwoPointer)); + _keyboardConnectedPointer = (KeyboardConnectedPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_kbd_connected"), typeof(KeyboardConnectedPointer)); + _resetPointer = (ResetPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_reset"), typeof(ResetPointer)); + _arrayUpdateKeyboardPointer = (ArrayUpdateKeyboardPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_array_update_keyboard"), typeof(ArrayUpdateKeyboardPointer)); + _arraySetSinglePointer = (ArraySetSinglePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_array_set_single"), typeof(ArraySetSinglePointer)); + } + + private static void UnloadWootingSDK() + { + if (_dllHandle == IntPtr.Zero) return; + + // 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 bool SetDllDirectory(string lpPathName); + + [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 IsWootingOnePointer _isWootingOnePointer; + private static IsWootingTwoPointer _isWootingTwoPointer; + private static KeyboardConnectedPointer _keyboardConnectedPointer; + private static ResetPointer _resetPointer; + private static ArrayUpdateKeyboardPointer _arrayUpdateKeyboardPointer; + private static ArraySetSinglePointer _arraySetSinglePointer; + + #endregion + + #region Delegates + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool IsWootingOnePointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool IsWootingTwoPointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool KeyboardConnectedPointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool ResetPointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool ArrayUpdateKeyboardPointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool ArraySetSinglePointer(byte row, byte column, byte red, byte green, byte blue); + + #endregion + + internal static bool IsWootingOne() => _isWootingOnePointer(); + internal static bool IsWootingTwo() => _isWootingTwoPointer(); + internal static bool KeyboardConnected() => _keyboardConnectedPointer(); + internal static bool Reset() => _resetPointer(); + internal static bool ArrayUpdateKeyboard() => _arrayUpdateKeyboardPointer(); + internal static bool ArraySetSingle(byte row, byte column, byte red, byte green, byte blue) => _arraySetSinglePointer(row, column, red, green, blue); + + #endregion + } +} diff --git a/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj b/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj new file mode 100644 index 0000000..128556f --- /dev/null +++ b/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj @@ -0,0 +1,68 @@ + + + netstandard2.0;net45 + win7-x86;win7-x64 + + Darth Affe + Wyrez + en-US + en-US + RGB.NET.Devices.Wooting + RGB.NET.Devices.Wooting + RGB.NET.Devices.Wooting + RGB.NET.Devices.Wooting + RGB.NET.Devices.Wooting + Wooting-Device-Implementations of RGB.NET + Wooting-Device-Implementations of RGB.NET, a C# (.NET) library for accessing various RGB-peripherals + Copyright © Wyrez 2017 + Copyright © Wyrez 2017 + http://lib.arge.be/icon.png + https://github.com/DarthAffe/RGB.NET + https://raw.githubusercontent.com/DarthAffe/RGB.NET/master/LICENSE + Github + https://github.com/DarthAffe/RGB.NET + False + + + + 0.0.1 + 0.0.1 + 0.0.1 + + ..\bin\ + true + True + True + latest + + + + NETCORE;NETSTANDARD;NETSTANDARD2_0 + + + + NET45;NETFULL + + + + $(DefineConstants);TRACE;DEBUG + true + full + false + + + + pdbonly + true + $(NoWarn);CS1591;CS1572;CS1573 + $(DefineConstants);RELEASE + + + + + + + + + + \ No newline at end of file diff --git a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs new file mode 100644 index 0000000..417b967 --- /dev/null +++ b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Native; + +namespace RGB.NET.Devices.Wooting +{ + /// + /// + /// Represents a device provider responsible for Wooting devices. + /// + public class WootingDeviceProvider : IRGBDeviceProvider + { + #region Properties & Fields + + private static WootingDeviceProvider _instance; + /// + /// Gets the singleton instance. + /// + public static WootingDeviceProvider Instance => _instance ?? new WootingDeviceProvider(); + + /// + /// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications. + /// The first match will be used. + /// + public static List PossibleX86NativePaths { get; } = new List { "x86/wooting-rgb-sdk.dll" }; + + /// + /// Gets a modifiable list of paths used to find the native SDK-dlls for x64 applications. + /// The first match will be used. + /// + public static List PossibleX64NativePaths { get; } = new List { "x64/wooting-rgb-sdk64.dll" }; + + /// + /// + /// Indicates if the SDK is initialized and ready to use. + /// + public bool IsInitialized { get; private set; } + + /// + /// Gets the loaded architecture (x64/x86). + /// + public string LoadedArchitecture => _WootingSDK.LoadedArchitecture; + + /// + /// + /// Gets whether the application has exclusive access to the SDK or not. + /// + public bool HasExclusiveAccess => false; + + /// + public IEnumerable Devices { get; private set; } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// Thrown if this constructor is called even if there is already an instance of this class. + public WootingDeviceProvider() + { + if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(WootingDeviceProvider)}"); + _instance = this; + } + + #endregion + + #region Methods + + /// + /// Thrown if the SDK failed to initialize + public bool Initialize(RGBDeviceType loadFilter = RGBDeviceType.All, bool exclusiveAccessIfPossible = false, bool throwExceptions = false) + { + IsInitialized = false; + + try + { + _WootingSDK.Reload(); + + IList devices = new List(); + if (_WootingSDK.KeyboardConnected()) + { + if (_WootingSDK.IsWootingOne()) + { + + } + else if (_WootingSDK.IsWootingTwo()) + { + + } + } + Devices = new ReadOnlyCollection(devices); + IsInitialized = true; + } + catch + { + if (throwExceptions) throw; + return false; + } + + return true; + } + + /// + public void ResetDevices() + { } + + /// + public void Dispose() + { + try { _WootingSDK.Reset(); } + catch { /* Unlucky.. */} + } + + #endregion + } +} diff --git a/RGB.NET.Devices.Wooting/WootingDeviceProviderLoader.cs b/RGB.NET.Devices.Wooting/WootingDeviceProviderLoader.cs new file mode 100644 index 0000000..5daf314 --- /dev/null +++ b/RGB.NET.Devices.Wooting/WootingDeviceProviderLoader.cs @@ -0,0 +1,24 @@ +using RGB.NET.Core; + +namespace RGB.NET.Devices.Wooting +{ + /// + /// Represents a device provider loaded used to dynamically load Wooting devices into an application. + /// + public class WootingDeviceProviderLoader : IRGBDeviceProviderLoader + { + #region Properties & Fields + + /// + public bool RequiresInitialization => false; + + #endregion + + #region Methods + + /// + public IRGBDeviceProvider GetDeviceProvider() => WootingDeviceProvider.Instance; + + #endregion + } +} diff --git a/RGB.NET.sln b/RGB.NET.sln index e3edb01..2d2701e 100644 --- a/RGB.NET.sln +++ b/RGB.NET.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27703.2035 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29424.173 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Devices", "Devices", "{D13032C6-432E-4F43-8A32-071133C22B16}" EndProject @@ -47,6 +47,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Core.Tests", "Tests EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.Asus", "RGB.NET.Devices.Asus\RGB.NET.Devices.Asus.csproj", "{E0732B34-3F96-4DD9-AFD5-0E34B833AD6D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.Wooting", "RGB.NET.Devices.Wooting\RGB.NET.Devices.Wooting.csproj", "{DD46DB2D-85BE-4962-86AE-E38C9053A548}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -129,6 +131,10 @@ Global {E0732B34-3F96-4DD9-AFD5-0E34B833AD6D}.Debug|Any CPU.Build.0 = Debug|Any CPU {E0732B34-3F96-4DD9-AFD5-0E34B833AD6D}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0732B34-3F96-4DD9-AFD5-0E34B833AD6D}.Release|Any CPU.Build.0 = Release|Any CPU + {DD46DB2D-85BE-4962-86AE-E38C9053A548}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD46DB2D-85BE-4962-86AE-E38C9053A548}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD46DB2D-85BE-4962-86AE-E38C9053A548}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD46DB2D-85BE-4962-86AE-E38C9053A548}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -152,6 +158,7 @@ Global {FFDE4387-60F2-47B6-9704-3A57D02B8C64} = {D13032C6-432E-4F43-8A32-071133C22B16} {A3FD5AD7-040A-47CA-A278-53493A25FF8A} = {92D7C263-D4C9-4D26-93E2-93C1F9C2CD16} {E0732B34-3F96-4DD9-AFD5-0E34B833AD6D} = {D13032C6-432E-4F43-8A32-071133C22B16} + {DD46DB2D-85BE-4962-86AE-E38C9053A548} = {D13032C6-432E-4F43-8A32-071133C22B16} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7F222AD4-1F9E-4AAB-9D69-D62372D4C1BA}