#pragma warning disable IDE1006 // Naming Styles // ReSharper disable UnusedMethodReturnValue.Global // ReSharper disable UnusedMember.Global // ReSharper disable MemberCanBePrivate.Global using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using RGB.NET.Core; namespace RGB.NET.Devices.Logitech.Native; // ReSharper disable once InconsistentNaming internal static class _LogitechGSDK { #region Libary Management private static nint _handle = 0; /// /// Reloads the SDK. /// internal static void Reload() { UnloadLogitechGSDK(); LoadLogitechGSDK(); } private static void LoadLogitechGSDK() { if (_handle != 0) return; List possiblePathList = GetPossibleLibraryPaths().ToList(); string? dllPath = possiblePathList.FirstOrDefault(File.Exists); if (dllPath == null) throw new RGBDeviceException($"Can't find the Logitech-SDK at one of the expected locations:\r\n '{string.Join("\r\n", possiblePathList.Select(Path.GetFullPath))}'"); if (!NativeLibrary.TryLoad(dllPath, out _handle)) #if NET6_0 throw new RGBDeviceException($"Logitech LoadLibrary failed with error code {Marshal.GetLastPInvokeError()}"); #else throw new RGBDeviceException($"Logitech LoadLibrary failed with error code {Marshal.GetLastWin32Error()}"); #endif if (!NativeLibrary.TryGetExport(_handle, "LogiLedInit", out _logiLedInitPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedInit'"); if (!NativeLibrary.TryGetExport(_handle, "LogiLedShutdown", out _logiLedShutdownPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedShutdown'"); if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetTargetDevice", out _logiLedSetTargetDevicePointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetTargetDevice'"); if (!NativeLibrary.TryGetExport(_handle, "LogiLedGetSdkVersion", out _logiLedGetSdkVersionPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedGetSdkVersion'"); if (!NativeLibrary.TryGetExport(_handle, "LogiLedSaveCurrentLighting", out _lgiLedSaveCurrentLightingPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSaveCurrentLighting'"); if (!NativeLibrary.TryGetExport(_handle, "LogiLedRestoreLighting", out _logiLedRestoreLightingPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedRestoreLighting'"); if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetLighting", out _logiLedSetLightingPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetLighting'"); if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetLightingForKeyWithKeyName", out _logiLedSetLightingForKeyWithKeyNamePointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetLightingForKeyWithKeyName'"); if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetLightingFromBitmap", out _logiLedSetLightingFromBitmapPointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetLightingFromBitmap'"); if (!NativeLibrary.TryGetExport(_handle, "LogiLedSetLightingForTargetZone", out _logiLedSetLightingForTargetZonePointer)) throw new RGBDeviceException("Failed to load Logitech function 'LogiLedSetLightingForTargetZone'"); } private static IEnumerable GetPossibleLibraryPaths() { IEnumerable possibleLibraryPaths; if (OperatingSystem.IsWindows()) possibleLibraryPaths = Environment.Is64BitProcess ? LogitechDeviceProvider.PossibleX64NativePaths : LogitechDeviceProvider.PossibleX86NativePaths; else possibleLibraryPaths = []; return possibleLibraryPaths.Select(Environment.ExpandEnvironmentVariables); } internal static void UnloadLogitechGSDK() { if (_handle == 0) return; _logiLedInitPointer = 0; _logiLedShutdownPointer = 0; _logiLedSetTargetDevicePointer = 0; _logiLedGetSdkVersionPointer = 0; _lgiLedSaveCurrentLightingPointer = 0; _logiLedRestoreLightingPointer = 0; _logiLedSetLightingPointer = 0; _logiLedSetLightingForKeyWithKeyNamePointer = 0; _logiLedSetLightingFromBitmapPointer = 0; _logiLedSetLightingForTargetZonePointer = 0; NativeLibrary.Free(_handle); _handle = 0; } #endregion #region SDK-METHODS #region Pointers private static nint _logiLedInitPointer; private static nint _logiLedShutdownPointer; private static nint _logiLedSetTargetDevicePointer; private static nint _logiLedGetSdkVersionPointer; private static nint _lgiLedSaveCurrentLightingPointer; private static nint _logiLedRestoreLightingPointer; private static nint _logiLedSetLightingPointer; private static nint _logiLedSetLightingForKeyWithKeyNamePointer; private static nint _logiLedSetLightingFromBitmapPointer; private static nint _logiLedSetLightingForTargetZonePointer; #endregion internal static unsafe bool LogiLedInit() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_logiLedInitPointer))(); internal static unsafe void LogiLedShutdown() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_logiLedShutdownPointer))(); internal static unsafe bool LogiLedSetTargetDevice(LogitechDeviceCaps targetDevice) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_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 unsafe bool LogiLedGetSdkVersion(ref int majorNum, ref int minorNum, ref int buildNum) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_logiLedGetSdkVersionPointer))(ref majorNum, ref minorNum, ref buildNum); internal static unsafe bool LogiLedSaveCurrentLighting() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_lgiLedSaveCurrentLightingPointer))(); internal static unsafe bool LogiLedRestoreLighting() => ((delegate* unmanaged[Cdecl])ThrowIfZero(_logiLedRestoreLightingPointer))(); internal static unsafe bool LogiLedSetLighting(int redPercentage, int greenPercentage, int bluePercentage) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_logiLedSetLightingPointer))(redPercentage, greenPercentage, bluePercentage); internal static unsafe bool LogiLedSetLightingForKeyWithKeyName(int keyCode, int redPercentage, int greenPercentage, int bluePercentage) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_logiLedSetLightingForKeyWithKeyNamePointer))(keyCode, redPercentage, greenPercentage, bluePercentage); internal static unsafe bool LogiLedSetLightingFromBitmap(byte[] bitmap) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_logiLedSetLightingFromBitmapPointer))(bitmap); internal static unsafe bool LogiLedSetLightingForTargetZone(LogitechDeviceType deviceType, int zone, int redPercentage, int greenPercentage, int bluePercentage) => ((delegate* unmanaged[Cdecl])ThrowIfZero(_logiLedSetLightingForTargetZonePointer))(deviceType, zone, redPercentage, greenPercentage, bluePercentage); private static nint ThrowIfZero(nint ptr) { if (ptr == 0) throw new RGBDeviceException("The Logitech-SDK is not initialized."); return ptr; } #endregion }