diff --git a/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs b/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs index d09813a..72defb3 100644 --- a/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs +++ b/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs @@ -16,9 +16,9 @@ public abstract class WootingRGBDevice : AbstractRGBDevice class. /// /// The generic information provided by Wooting for the device. - /// The update trigger used to update this device. - protected WootingRGBDevice(TDeviceInfo info, IDeviceUpdateTrigger updateTrigger) - : base(info, new WootingUpdateQueue(updateTrigger)) + /// The update queue used to update this device. + protected WootingRGBDevice(TDeviceInfo info, IUpdateQueue updateQueue) + : base(info, updateQueue) { } #endregion diff --git a/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs b/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs index ec15db0..4679cb9 100644 --- a/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs +++ b/RGB.NET.Devices.Wooting/Generic/WootingUpdateQueue.cs @@ -10,15 +10,20 @@ namespace RGB.NET.Devices.Wooting.Generic; /// public class WootingUpdateQueue : UpdateQueue { + #region Properties & Fields + private readonly byte _deviceid; + #endregion + #region Constructors /// /// Initializes a new instance of the class. /// /// The update trigger used by this queue. - public WootingUpdateQueue(IDeviceUpdateTrigger updateTrigger) + public WootingUpdateQueue(IDeviceUpdateTrigger updateTrigger, byte deviceId) : base(updateTrigger) { + _deviceid = deviceId; } #endregion @@ -30,6 +35,8 @@ public class WootingUpdateQueue : UpdateQueue { lock (_WootingSDK.SdkLock) { + _WootingSDK.SelectDevice(_deviceid); + foreach ((object key, Color color) in dataSet) { (int row, int column) = ((int, int))key; diff --git a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs index da3d2d2..6e082a4 100644 --- a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs +++ b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs @@ -24,8 +24,8 @@ public class WootingKeyboardRGBDevice : WootingRGBDevice /// The specific information provided by Wooting for the keyboard /// The update trigger used to update this device. - internal WootingKeyboardRGBDevice(WootingKeyboardRGBDeviceInfo info, IDeviceUpdateTrigger updateTrigger) - : base(info, updateTrigger) + internal WootingKeyboardRGBDevice(WootingKeyboardRGBDeviceInfo info, IUpdateQueue updateQueue) + : base(info, updateQueue) { InitializeLayout(); } diff --git a/RGB.NET.Devices.Wooting/Native/_WootingSDK.cs b/RGB.NET.Devices.Wooting/Native/_WootingSDK.cs index 5e18491..885a255 100644 --- a/RGB.NET.Devices.Wooting/Native/_WootingSDK.cs +++ b/RGB.NET.Devices.Wooting/Native/_WootingSDK.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Runtime.InteropServices; using RGB.NET.Core; @@ -15,7 +16,7 @@ internal static class _WootingSDK { #region Library management - private static IntPtr _dllHandle = IntPtr.Zero; + private static IntPtr _handle = IntPtr.Zero; internal static object SdkLock = new(); /// @@ -29,7 +30,7 @@ internal static class _WootingSDK private static void LoadWootingSDK() { - if (_dllHandle != IntPtr.Zero) return; + if (_handle != 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) @@ -38,22 +39,24 @@ internal static class _WootingSDK 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); - if (_dllHandle == IntPtr.Zero) throw new RGBDeviceException($"Wooting LoadLibrary failed with error code {Marshal.GetLastWin32Error()}"); - - _getDeviceInfoPointer = (GetDeviceInfoPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_device_info"), typeof(GetDeviceInfoPointer)); - _keyboardConnectedPointer = (KeyboardConnectedPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_kbd_connected"), typeof(KeyboardConnectedPointer)); - _resetPointer = (ResetPointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_reset_rgb"), typeof(ResetPointer)); - _closePointer = (ClosePointer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "wooting_rgb_close"), typeof(ClosePointer)); - _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)); + + _handle = NativeLibrary.Load(dllPath); + if (_handle == IntPtr.Zero) throw new RGBDeviceException($"Wooting LoadLibrary failed with error code {Marshal.GetLastWin32Error()}"); + + _getDeviceInfoPointer = (GetDeviceInfoPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_device_info"), typeof(GetDeviceInfoPointer)); + _keyboardConnectedPointer = (KeyboardConnectedPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_kbd_connected"), typeof(KeyboardConnectedPointer)); + _resetPointer = (ResetPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_reset_rgb"), typeof(ResetPointer)); + _closePointer = (ClosePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_close"), typeof(ClosePointer)); + _arrayUpdateKeyboardPointer = (ArrayUpdateKeyboardPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_array_update_keyboard"), typeof(ArrayUpdateKeyboardPointer)); + _arraySetSinglePointer = (ArraySetSinglePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_rgb_array_set_single"), typeof(ArraySetSinglePointer)); + _getDeviceCountPointer = (GetDeviceCountPointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_usb_keyboard_count"), typeof(GetDeviceCountPointer)); + _selectDevicePointer = (SelectDevicePointer)Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_handle, "wooting_usb_select_device"), typeof(SelectDevicePointer)); } + internal static void UnloadWootingSDK() { - if (_dllHandle == IntPtr.Zero) return; + if (_handle == IntPtr.Zero) return; Reset(); Close(); @@ -66,22 +69,10 @@ internal static class _WootingSDK _closePointer = null; // 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; + NativeLibrary.Free(_handle); + _handle = 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 @@ -94,6 +85,8 @@ internal static class _WootingSDK private static ClosePointer? _closePointer; private static ArrayUpdateKeyboardPointer? _arrayUpdateKeyboardPointer; private static ArraySetSinglePointer? _arraySetSinglePointer; + private static GetDeviceCountPointer? _getDeviceCountPointer; + private static SelectDevicePointer? _selectDevicePointer; #endregion @@ -117,6 +110,12 @@ internal static class _WootingSDK [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate bool ArraySetSinglePointer(byte row, byte column, byte red, byte green, byte blue); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate byte GetDeviceCountPointer(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void SelectDevicePointer(byte index); + #endregion internal static IntPtr GetDeviceInfo() => (_getDeviceInfoPointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); @@ -125,6 +124,7 @@ internal static class _WootingSDK internal static bool Close() => (_closePointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); internal static bool ArrayUpdateKeyboard() => (_arrayUpdateKeyboardPointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); internal static bool ArraySetSingle(byte row, byte column, byte red, byte green, byte blue) => (_arraySetSinglePointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(row, column, red, green, blue); - + internal static byte GetDeviceCount() => (_getDeviceCountPointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(); + internal static void SelectDevice(byte index) => (_selectDevicePointer ?? throw new RGBDeviceException("The Wooting-SDK is not initialized.")).Invoke(index); #endregion } \ No newline at end of file diff --git a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs index 8f6a6f6..c588401 100644 --- a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs +++ b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using RGB.NET.Core; +using RGB.NET.Devices.Wooting.Generic; using RGB.NET.Devices.Wooting.Keyboard; using RGB.NET.Devices.Wooting.Native; @@ -67,9 +68,14 @@ public class WootingDeviceProvider : AbstractRGBDeviceProvider { if (_WootingSDK.KeyboardConnected()) { - _WootingDeviceInfo nativeDeviceInfo = (_WootingDeviceInfo)Marshal.PtrToStructure(_WootingSDK.GetDeviceInfo(), typeof(_WootingDeviceInfo))!; + for (byte i = 0; i < _WootingSDK.GetDeviceCount(); i++) + { + var updateQueue = new WootingUpdateQueue(GetUpdateTrigger(), i); + _WootingSDK.SelectDevice(i); + _WootingDeviceInfo nativeDeviceInfo = (_WootingDeviceInfo)Marshal.PtrToStructure(_WootingSDK.GetDeviceInfo(), typeof(_WootingDeviceInfo))!; - yield return new WootingKeyboardRGBDevice(new WootingKeyboardRGBDeviceInfo(nativeDeviceInfo), GetUpdateTrigger()); + yield return new WootingKeyboardRGBDevice(new WootingKeyboardRGBDeviceInfo(nativeDeviceInfo), updateQueue); + } } } }