diff --git a/README.md b/README.md index 4496999..b1d9edd 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ open `settings.json` within the configuration folder (see - For version 8.58.177 and lower, G110 users have to enable [a workaround](https://github.com/Archomeda/lightfx-extender/wiki/Logitech-G110-Workaround) for a bug that will be fixed in an upcoming version +- Corsair keyboards and mice for both RGB and Monochrome - Lightpack devices through a recent version of Prismatik (or similar hardware and software that support the same API, tested on version 5.11.1 only) - Alienware devices that originally support LightFX diff --git a/include/CUESDK.h b/include/CUESDK.h new file mode 100644 index 0000000..d3ab5c2 --- /dev/null +++ b/include/CUESDK.h @@ -0,0 +1,151 @@ +#pragma once + +#include "CUESDKGlobal.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "CorsairLedIdEnum.h" + + enum CorsairDeviceType // contains list of available device types + { + CDT_Unknown = 0, + CDT_Mouse = 1, + CDT_Keyboard = 2, + CDT_Headset = 3 + }; + + enum CorsairPhysicalLayout // contains list of available physical layouts for keyboards + { + CPL_Invalid = 0, // dummy value + + CPL_US = 1, + CPL_UK = 2, + CPL_BR = 3, + CPL_JP = 4, + CPL_KR = 5, // valid values for keyboard + + CPL_Zones1 = 6, + CPL_Zones2 = 7, + CPL_Zones3 = 8, + CPL_Zones4 = 9, // valid values for mouse + }; + + enum CorsairLogicalLayout // contains list of available logical layouts for keyboards + { + CLL_Invalid = 0, // dummy value + CLL_US_Int = 1, + CLL_NA = 2, + CLL_EU = 3, + CLL_UK = 4, + CLL_BE = 5, + CLL_BR = 6, + CLL_CH = 7, + CLL_CN = 8, + CLL_DE = 9, + CLL_ES = 10, + CLL_FR = 11, + CLL_IT = 12, + CLL_ND = 13, + CLL_RU = 14, + CLL_JP = 15, + CLL_KR = 16, + CLL_TW = 17, + CLL_MEX = 18 + }; + + enum CorsairDeviceCaps // contains list of device capabilities + { + CDC_None = 0, // for devices that do not support any SDK functions + CDC_Lighting = 1 // for devices that has controlled lighting + }; + + enum CorsairAccessMode // contains list of available SDK access modes + { + CAM_ExclusiveLightingControl = 0 + }; + + enum CorsairError // contains shared list of all errors which could happen during calling of Corsair* functions + { + CE_Success, // if previously called function completed successfully + CE_ServerNotFound, // CUE is not running or was shut down or third-party control is disabled in CUE settings(runtime error) + CE_NoControl, // if some other client has or took over exclusive control (runtime error) + CE_ProtocolHandshakeMissing, // if developer did not perform protocol handshake(developer error) + CE_IncompatibleProtocol, // if developer is calling the function that is not supported by the server(either because protocol has broken by server or client or because the function is new and server is too old. Check CorsairProtocolDetails for details) (developer error) + CE_InvalidArguments, // if developer supplied invalid arguments to the function(for specifics look at function descriptions). (developer error) + }; + + struct CorsairDeviceInfo // contains information about device + { + CorsairDeviceType type; // enum describing device type + const char* model; // null - terminated device model(like “K95RGB”) + CorsairPhysicalLayout physicalLayout; // enum describing physical layout of the keyboard or mouse + CorsairLogicalLayout logicalLayout; // enum describing logical layout of the keyboard as set in CUE settings + int capsMask; // mask that describes device capabilities, formed as logical “or” of CorsairDeviceCaps enum values + }; + + struct CorsairLedPosition // contains led id and position of led rectangle.Most of the keys are rectangular.In case if key is not rectangular(like Enter in ISO / UK layout) it returns the smallest rectangle that fully contains the key + { + CorsairLedId ledId; // identifier of led + double top; + double left; + double height; + double width; // values in mm + }; + + struct CorsairLedPositions // contains number of leds and arrays with their positions + { + int numberOfLed; // integer value.Number of elements in following array + CorsairLedPosition* pLedPosition; // array of led positions + }; + + struct CorsairLedColor // contains information about led and its color + { + CorsairLedId ledId; // identifier of LED to set + int r; // red brightness[0..255] + int g; // green brightness[0..255] + int b; // blue brightness[0..255] + }; + + struct CorsairProtocolDetails // contains information about SDK and CUE versions + { + const char* sdkVersion; // null - terminated string containing version of SDK(like “1.0.0.1”). Always contains valid value even if there was no CUE found + const char* serverVersion; // null - terminated string containing version of CUE(like “1.0.0.1”) or NULL if CUE was not found. + int sdkProtocolVersion; // integer number that specifies version of protocol that is implemented by current SDK. Numbering starts from 1. Always contains valid value even if there was no CUE found + int serverProtocolVersion; // integer number that specifies version of protocol that is implemented by CUE. Numbering starts from 1. If CUE was not found then this value will be 0 + bool breakingChanges; // boolean value that specifies if there were breaking changes between version of protocol implemented by server and client + }; + + + + // set specified leds to some colors.The color is retained until changed by successive calls.This function does not take logical layout into account + CORSAIR_LIGHTING_SDK_EXPORT bool CorsairSetLedsColors(int size, CorsairLedColor* ledsColors); + + CORSAIR_LIGHTING_SDK_EXPORT bool CorsairSetLedsColorsAsync(int size, CorsairLedColor* ledsColors, void(*CallbackType)(void*, bool, CorsairError), void *context); + + // returns number of connected Corsair devices that support lighting control. + CORSAIR_LIGHTING_SDK_EXPORT int CorsairGetDeviceCount(); + + // returns information about device at provided index + CORSAIR_LIGHTING_SDK_EXPORT CorsairDeviceInfo *CorsairGetDeviceInfo(int deviceIndex); + + // provides list of keyboard LEDs with their physical positions. + CORSAIR_LIGHTING_SDK_EXPORT CorsairLedPositions *CorsairGetLedPositions(); + + // retrieves led id for key name taking logical layout into account. + CORSAIR_LIGHTING_SDK_EXPORT CorsairLedId CorsairGetLedIdForKeyName(char keyName); + + // requestes control using specified access mode. By default client has shared control over lighting so there is no need to call CorsairRequestControl unless client requires exclusive control + CORSAIR_LIGHTING_SDK_EXPORT bool CorsairRequestControl(CorsairAccessMode accessMode); + + // checks file and protocol version of CUE to understand which of SDK functions can be used with this version of CUE + CORSAIR_LIGHTING_SDK_EXPORT CorsairProtocolDetails CorsairPerformProtocolHandshake(); + + // returns last error that occured while using any of Corsair* functions + CORSAIR_LIGHTING_SDK_EXPORT CorsairError CorsairGetLastError(); + +#ifdef __cplusplus +} //exten "C" +#endif diff --git a/include/CUESDKGlobal.h b/include/CUESDKGlobal.h new file mode 100644 index 0000000..3202555 --- /dev/null +++ b/include/CUESDKGlobal.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef _LIB +#ifdef CORSAIR_LIGHTING_SDK_DLL +#define CORSAIR_LIGHTING_SDK_EXPORT __declspec(dllexport) +#else +#define CORSAIR_LIGHTING_SDK_EXPORT __declspec(dllimport) +#endif +#else +#define CORSAIR_LIGHTING_SDK_EXPORT +#endif diff --git a/include/CorsairLedIdEnum.h b/include/CorsairLedIdEnum.h new file mode 100644 index 0000000..d263e79 --- /dev/null +++ b/include/CorsairLedIdEnum.h @@ -0,0 +1,162 @@ +#pragma once + +enum CorsairLedId +{ + CLI_Invalid = 0, + CLK_Escape = 1, + CLK_F1 = 2, + CLK_F2 = 3, + CLK_F3 = 4, + CLK_F4 = 5, + CLK_F5 = 6, + CLK_F6 = 7, + CLK_F7 = 8, + CLK_F8 = 9, + CLK_F9 = 10, + CLK_F10 = 11, + CLK_F11 = 12, + CLK_GraveAccentAndTilde = 13, + CLK_1 = 14, + CLK_2 = 15, + CLK_3 = 16, + CLK_4 = 17, + CLK_5 = 18, + CLK_6 = 19, + CLK_7 = 20, + CLK_8 = 21, + CLK_9 = 22, + CLK_0 = 23, + CLK_MinusAndUnderscore = 24, + CLK_Tab = 25, + CLK_Q = 26, + CLK_W = 27, + CLK_E = 28, + CLK_R = 29, + CLK_T = 30, + CLK_Y = 31, + CLK_U = 32, + CLK_I = 33, + CLK_O = 34, + CLK_P = 35, + CLK_BracketLeft = 36, + CLK_CapsLock = 37, + CLK_A = 38, + CLK_S = 39, + CLK_D = 40, + CLK_F = 41, + CLK_G = 42, + CLK_H = 43, + CLK_J = 44, + CLK_K = 45, + CLK_L = 46, + CLK_SemicolonAndColon = 47, + CLK_ApostropheAndDoubleQuote = 48, + CLK_LeftShift = 49, + CLK_NonUsBackslash = 50, + CLK_Z = 51, + CLK_X = 52, + CLK_C = 53, + CLK_V = 54, + CLK_B = 55, + CLK_N = 56, + CLK_M = 57, + CLK_CommaAndLessThan = 58, + CLK_PeriodAndBiggerThan = 59, + CLK_SlashAndQuestionMark = 60, + CLK_LeftCtrl = 61, + CLK_LeftGui = 62, + CLK_LeftAlt = 63, + CLK_Lang2 = 64, + CLK_Space = 65, + CLK_Lang1 = 66, + CLK_International2 = 67, + CLK_RightAlt = 68, + CLK_RightGui = 69, + CLK_Application = 70, + CLK_LedProgramming = 71, + CLK_Brightness = 72, + CLK_F12 = 73, + CLK_PrintScreen = 74, + CLK_ScrollLock = 75, + CLK_PauseBreak = 76, + CLK_Insert = 77, + CLK_Home = 78, + CLK_PageUp = 79, + CLK_BracketRight = 80, + CLK_Backslash = 81, + CLK_NonUsTilde = 82, + CLK_Enter = 83, + CLK_International1 = 84, + CLK_EqualsAndPlus = 85, + CLK_International3 = 86, + CLK_Backspace = 87, + CLK_Delete = 88, + CLK_End = 89, + CLK_PageDown = 90, + CLK_RightShift = 91, + CLK_RightCtrl = 92, + CLK_UpArrow = 93, + CLK_LeftArrow = 94, + CLK_DownArrow = 95, + CLK_RightArrow = 96, + CLK_WinLock = 97, + CLK_Mute = 98, + CLK_Stop = 99, + CLK_ScanPreviousTrack = 100, + CLK_PlayPause = 101, + CLK_ScanNextTrack = 102, + CLK_NumLock = 103, + CLK_KeypadSlash = 104, + CLK_KeypadAsterisk = 105, + CLK_KeypadMinus = 106, + CLK_KeypadPlus = 107, + CLK_KeypadEnter = 108, + CLK_Keypad7 = 109, + CLK_Keypad8 = 110, + CLK_Keypad9 = 111, + CLK_KeypadComma = 112, + CLK_Keypad4 = 113, + CLK_Keypad5 = 114, + CLK_Keypad6 = 115, + CLK_Keypad1 = 116, + CLK_Keypad2 = 117, + CLK_Keypad3 = 118, + CLK_Keypad0 = 119, + CLK_KeypadPeriodAndDelete = 120, + CLK_G1 = 121, + CLK_G2 = 122, + CLK_G3 = 123, + CLK_G4 = 124, + CLK_G5 = 125, + CLK_G6 = 126, + CLK_G7 = 127, + CLK_G8 = 128, + CLK_G9 = 129, + CLK_G10 = 130, + CLK_VolumeUp = 131, + CLK_VolumeDown = 132, + CLK_MR = 133, + CLK_M1 = 134, + CLK_M2 = 135, + CLK_M3 = 136, + CLK_G11 = 137, + CLK_G12 = 138, + CLK_G13 = 139, + CLK_G14 = 140, + CLK_G15 = 141, + CLK_G16 = 142, + CLK_G17 = 143, + CLK_G18 = 144, + CLK_International5 = 145, + CLK_International4 = 146, + CLK_Fn = 147, + CLM_1 = 148, + CLM_2 = 149, + CLM_3 = 150, + CLM_4 = 151, + CLH_LeftLogo = 152, + CLH_RightLogo = 153, + CLK_Logo = 154, + + CLI_Last = CLK_Logo +}; diff --git a/include/LogitechLEDLib.h b/include/LogitechLEDLib.h index 4277698..5c0bb39 100644 --- a/include/LogitechLEDLib.h +++ b/include/LogitechLEDLib.h @@ -11,10 +11,21 @@ #define LOGI_LED_BITMAP_HEIGHT 6 #define LOGI_LED_BITMAP_BYTES_PER_KEY 4 -#define LOGI_LED_BITMAP_SIZE LOGI_LED_BITMAP_WIDTH*LOGI_LED_BITMAP_HEIGHT*LOGI_LED_BITMAP_BYTES_PER_KEY +#define LOGI_LED_BITMAP_SIZE (LOGI_LED_BITMAP_WIDTH*LOGI_LED_BITMAP_HEIGHT*LOGI_LED_BITMAP_BYTES_PER_KEY) #define LOGI_LED_DURATION_INFINITE 0 +#define LOGI_DEVICETYPE_MONOCHROME_ORD 0 +#define LOGI_DEVICETYPE_RGB_ORD 1 +#define LOGI_DEVICETYPE_PERKEY_RGB_ORD 2 + +#define LOGI_DEVICETYPE_MONOCHROME (1 << LOGI_DEVICETYPE_MONOCHROME_ORD) +#define LOGI_DEVICETYPE_RGB (1 << LOGI_DEVICETYPE_RGB_ORD) +#define LOGI_DEVICETYPE_PERKEY_RGB (1 << LOGI_DEVICETYPE_PERKEY_RGB_ORD) + +#define LOGI_DEVICETYPE_ALL (LOGI_DEVICETYPE_MONOCHROME | LOGI_DEVICETYPE_RGB | LOGI_DEVICETYPE_PERKEY_RGB) + + namespace LogiLed { typedef enum @@ -128,17 +139,32 @@ namespace LogiLed } bool LogiLedInit(); + +bool LogiLedGetSdkVersion(int *majorNum, int *minorNum, int *buildNum); + +//Generic functions => Apply to any device type. +bool LogiLedSetTargetDevice(int targetDevice); bool LogiLedSaveCurrentLighting(); bool LogiLedSetLighting(int redPercentage, int greenPercentage, int bluePercentage); bool LogiLedRestoreLighting(); bool LogiLedFlashLighting(int redPercentage, int greenPercentage, int bluePercentage, int milliSecondsDuration, int milliSecondsInterval); bool LogiLedPulseLighting(int redPercentage, int greenPercentage, int bluePercentage, int milliSecondsDuration, int milliSecondsInterval); bool LogiLedStopEffects(); -bool LogiLedSetLightingFromBitmap(BYTE bitmap[]); + +//Per-key functions => only apply to LOGI_DEVICETYPE_PERKEY_RGB devices. +bool LogiLedSetLightingFromBitmap(unsigned char bitmap[]); bool LogiLedSetLightingForKeyWithScanCode(int keyCode, int redPercentage, int greenPercentage, int bluePercentage); bool LogiLedSetLightingForKeyWithHidCode(int keyCode, int redPercentage, int greenPercentage, int bluePercentage); bool LogiLedSetLightingForKeyWithQuartzCode(int keyCode, int redPercentage, int greenPercentage, int bluePercentage); bool LogiLedSetLightingForKeyWithKeyName(LogiLed::KeyName keyName, int redPercentage, int greenPercentage, int bluePercentage); +bool LogiLedSaveLightingForKey(LogiLed::KeyName keyName); +bool LogiLedRestoreLightingForKey(LogiLed::KeyName keyName); + +//Per-key effects => only apply to LOGI_DEVICETYPE_PERKEY_RGB devices. +bool LogiLedFlashSingleKey(LogiLed::KeyName keyName, int redPercentage, int greenPercentage, int bluePercentage, int msDuration, int msInterval); +bool LogiLedPulseSingleKey(LogiLed::KeyName keyName, int startRedPercentage, int startGreenPercentage, int startBluePercentage, int finishRedPercentage, int finishGreenPercentage, int finishBluePercentage, int msDuration, bool isInfinite); +bool LogiLedStopEffectsOnKey(LogiLed::KeyName keyName); + void LogiLedShutdown(); diff --git a/lib/x64/CUESDK.x64_2013.dll b/lib/x64/CUESDK.x64_2013.dll new file mode 100644 index 0000000..64fbe92 Binary files /dev/null and b/lib/x64/CUESDK.x64_2013.dll differ diff --git a/lib/x64/CUESDK.x64_2013.lib b/lib/x64/CUESDK.x64_2013.lib new file mode 100644 index 0000000..abc6b7b Binary files /dev/null and b/lib/x64/CUESDK.x64_2013.lib differ diff --git a/lib/x64/LogitechLEDLib.lib b/lib/x64/LogitechLEDLib.lib index 52dd5cd..649bd7c 100644 Binary files a/lib/x64/LogitechLEDLib.lib and b/lib/x64/LogitechLEDLib.lib differ diff --git a/lib/x86/CUESDK_2013.dll b/lib/x86/CUESDK_2013.dll new file mode 100644 index 0000000..c2dbf62 Binary files /dev/null and b/lib/x86/CUESDK_2013.dll differ diff --git a/lib/x86/CUESDK_2013.lib b/lib/x86/CUESDK_2013.lib new file mode 100644 index 0000000..fe756f3 Binary files /dev/null and b/lib/x86/CUESDK_2013.lib differ diff --git a/lib/x86/LogitechLEDLib.lib b/lib/x86/LogitechLEDLib.lib index 0e8d46e..45ec532 100644 Binary files a/lib/x86/LogitechLEDLib.lib and b/lib/x86/LogitechLEDLib.lib differ diff --git a/src/Config/MainConfigFile.cpp b/src/Config/MainConfigFile.cpp index 6532c30..c1e2bd5 100644 --- a/src/Config/MainConfigFile.cpp +++ b/src/Config/MainConfigFile.cpp @@ -31,8 +31,16 @@ #define CONF_DEVICES_LOGITECH_COLORRANGE_OUTMAX L"LightFXMax" #define CONF_DEVICES_LOGITECH_COLORRANGE_INMIN L"LogitechMin" #define CONF_DEVICES_LOGITECH_COLORRANGE_INMAX L"LogitechMax" +#define CONF_DEVICES_LOGITECH_RESTORELIGHTSONNULL L"RestoreLightsOnNullEnabled" #define CONF_DEVICES_LOGITECH_G110WORKAROUND L"G110WorkaroundEnabled" +#define CONF_DEVICES_CORSAIR L"Corsair" +#define CONF_DEVICES_CORSAIR_COLORRANGE L"ColorRange" +#define CONF_DEVICES_CORSAIR_COLORRANGE_OUTMIN L"LightFXMin" +#define CONF_DEVICES_CORSAIR_COLORRANGE_OUTMAX L"LightFXMax" +#define CONF_DEVICES_CORSAIR_COLORRANGE_INMIN L"CorsairMin" +#define CONF_DEVICES_CORSAIR_COLORRANGE_INMAX L"CorsairMax" + #define CONF_DEVICES_LIGHTPACK L"Lightpack" #define CONF_DEVICES_LIGHTPACK_API L"SocketApi" #define CONF_DEVICES_LIGHTPACK_API_HOST L"Hostname" @@ -76,8 +84,14 @@ namespace lightfx { this->LogitechColorRangeOutMax = 255; this->LogitechColorRangeInMin = 0; this->LogitechColorRangeInMax = 100; + this->LogitechRestoreLightsOnNullEnabled = false; this->LogitechG110WorkaroundEnabled = false; + this->CorsairColorRangeOutMin = 0; + this->CorsairColorRangeOutMax = 255; + this->CorsairColorRangeInMin = 0; + this->CorsairColorRangeInMax = 255; + this->GuildWars2TeamColorEnabled = true; this->GuildWars2TeamColorAnimation = L"Pulse"; } @@ -174,10 +188,24 @@ namespace lightfx { objLogitechColorRange.AddMember(CONF_DEVICES_LOGITECH_COLORRANGE_INMIN, this->LogitechColorRangeInMin, allocator); objLogitechColorRange.AddMember(CONF_DEVICES_LOGITECH_COLORRANGE_INMAX, this->LogitechColorRangeInMax, allocator); objLogitech.AddMember(CONF_DEVICES_LOGITECH_COLORRANGE, objLogitechColorRange, allocator); + objLogitech.AddMember(CONF_DEVICES_LOGITECH_RESTORELIGHTSONNULL, this->LogitechRestoreLightsOnNullEnabled, allocator); objLogitech.AddMember(CONF_DEVICES_LOGITECH_G110WORKAROUND, this->LogitechG110WorkaroundEnabled, allocator); obj.AddMember(CONF_DEVICES_LOGITECH, objLogitech, allocator); + // Logitech + WValue objCorsair(kObjectType); + + // Logitech color range + WValue objCorsairColorRange(kObjectType); + objCorsairColorRange.AddMember(CONF_DEVICES_CORSAIR_COLORRANGE_OUTMIN, this->CorsairColorRangeOutMin, allocator); + objCorsairColorRange.AddMember(CONF_DEVICES_CORSAIR_COLORRANGE_OUTMAX, this->CorsairColorRangeOutMax, allocator); + objCorsairColorRange.AddMember(CONF_DEVICES_CORSAIR_COLORRANGE_INMIN, this->CorsairColorRangeInMin, allocator); + objCorsairColorRange.AddMember(CONF_DEVICES_CORSAIR_COLORRANGE_INMAX, this->CorsairColorRangeInMax, allocator); + objCorsair.AddMember(CONF_DEVICES_CORSAIR_COLORRANGE, objCorsairColorRange, allocator); + + obj.AddMember(CONF_DEVICES_CORSAIR, objCorsair, allocator); + return obj; } @@ -309,7 +337,31 @@ namespace lightfx { if (objLogitech.HasMember(CONF_DEVICES_LOGITECH_G110WORKAROUND) && objLogitech[CONF_DEVICES_LOGITECH_G110WORKAROUND].IsBool()) { this->LogitechG110WorkaroundEnabled = objLogitech[CONF_DEVICES_LOGITECH_G110WORKAROUND].GetBool(); } + if (objLogitech.HasMember(CONF_DEVICES_LOGITECH_RESTORELIGHTSONNULL) && objLogitech[CONF_DEVICES_LOGITECH_RESTORELIGHTSONNULL].IsBool()) { + this->LogitechRestoreLightsOnNullEnabled = objLogitech[CONF_DEVICES_LOGITECH_RESTORELIGHTSONNULL].GetBool(); + } } + + // Corsair + if (objDevices.HasMember(CONF_DEVICES_CORSAIR) && objDevices[CONF_DEVICES_CORSAIR].IsObject()) { + const WValue& objCorsair = objDevices[CONF_DEVICES_CORSAIR]; + // Corsair color range + if (objCorsair.HasMember(CONF_DEVICES_CORSAIR_COLORRANGE) && objCorsair[CONF_DEVICES_CORSAIR_COLORRANGE].IsObject()) { + const WValue& colorRange = objCorsair[CONF_DEVICES_CORSAIR_COLORRANGE]; + if (colorRange.HasMember(CONF_DEVICES_CORSAIR_COLORRANGE_OUTMIN) && colorRange[CONF_DEVICES_CORSAIR_COLORRANGE_OUTMIN].IsInt()) { + this->CorsairColorRangeOutMin = colorRange[CONF_DEVICES_CORSAIR_COLORRANGE_OUTMIN].GetInt(); + } + if (colorRange.HasMember(CONF_DEVICES_CORSAIR_COLORRANGE_OUTMAX) && colorRange[CONF_DEVICES_CORSAIR_COLORRANGE_OUTMAX].IsInt()) { + this->CorsairColorRangeOutMax = colorRange[CONF_DEVICES_CORSAIR_COLORRANGE_OUTMAX].GetInt(); + } + if (colorRange.HasMember(CONF_DEVICES_CORSAIR_COLORRANGE_INMIN) && colorRange[CONF_DEVICES_CORSAIR_COLORRANGE_INMIN].IsInt()) { + this->CorsairColorRangeInMin = colorRange[CONF_DEVICES_CORSAIR_COLORRANGE_INMIN].GetInt(); + } + if (colorRange.HasMember(CONF_DEVICES_CORSAIR_COLORRANGE_INMAX) && colorRange[CONF_DEVICES_CORSAIR_COLORRANGE_INMAX].IsInt()) { + this->CorsairColorRangeInMax = colorRange[CONF_DEVICES_CORSAIR_COLORRANGE_INMAX].GetInt(); + } + } + } } } diff --git a/src/Config/MainConfigFile.h b/src/Config/MainConfigFile.h index 144f6b9..007b45a 100644 --- a/src/Config/MainConfigFile.h +++ b/src/Config/MainConfigFile.h @@ -44,8 +44,14 @@ namespace lightfx { int LogitechColorRangeOutMax = 255; int LogitechColorRangeInMin = 0; int LogitechColorRangeInMax = 100; + bool LogitechRestoreLightsOnNullEnabled = false; bool LogitechG110WorkaroundEnabled = false; + int CorsairColorRangeOutMin = 0; + int CorsairColorRangeOutMax = 255; + int CorsairColorRangeInMin = 0; + int CorsairColorRangeInMax = 255; + bool GuildWars2TeamColorEnabled = true; std::wstring GuildWars2TeamColorAnimation = L"Pulse"; diff --git a/src/Devices/DeviceCorsair.cpp b/src/Devices/DeviceCorsair.cpp new file mode 100644 index 0000000..bf625bd --- /dev/null +++ b/src/Devices/DeviceCorsair.cpp @@ -0,0 +1,137 @@ +#ifndef LFXE_EXPORTS +#define LFXE_EXPORTS +#endif + +#include "DeviceCorsair.h" + +// Windows includes +#include "../Common/Windows.h" +#include + +// 3rd party includes +#include "CUESDK.h" + +#include +#include +#include +#include +#include + + +// Project includes +#include "../LightFXExtender.h" +#include "../Utils/Log.h" + + +#define LOG(logLevel, message) LOG_(logLevel, wstring(L"Device ") + this->GetDeviceName() + L" - " + message) + +using namespace std; +using namespace lightfx::managers; +using namespace lightfx::timelines; +using namespace lightfx::utils; + +namespace lightfx { + namespace devices { + + LFXE_API void DeviceCorsair::SetRange(const int outMin, const int outMax, const int inMin, const int inMax) { + this->rangeOutMin = outMin; + this->rangeOutMax = outMax; + this->rangeInMin = inMin; + this->rangeInMax = inMax; + } + + LFXE_API bool DeviceCorsair::Initialize() { + if (!this->IsInitialized()) { + if (Device::Initialize()) { + // Just do an initial pass to set how many LEDs there are available + this->SetNumberOfLights(1); + this->SetLightData(0, LightData()); + + this->Reset(); + return true; + } + } + this->SetInitialized(false); + return false; + } + + LFXE_API bool DeviceCorsair::Enable() { + if (!this->IsEnabled()) { + if (Device::Enable()) { + + CorsairPerformProtocolHandshake(); + if (const auto error = CorsairGetLastError()) { + const char* str_error = toString(error); + wstring wstr(str_error, str_error + strlen(str_error)); + LOG(LogLevel::Error, L"Handshake with Corsair failed: " + wstr); + } + else + { + this->Reset(); + this->ledPositions = CorsairGetLedPositions(); + return true; + } + } + } + this->SetEnabled(false); + return false; + } + + LFXE_API bool DeviceCorsair::Disable() { + if (this->IsEnabled()) { + if (Device::Disable()) { + return true; + } + } + this->SetEnabled(true); + return false; + } + + LFXE_API bool DeviceCorsair::PushColorToDevice(const vector& colors) { + double red = colors[0].red; + double green = colors[0].green; + double blue = colors[0].blue; + double alpha = colors[0].brightness; + + double divider = (this->rangeOutMax - this->rangeOutMin) / ((this->rangeInMax - this->rangeInMin) / 100.0) / 100.0; + + int updated_red = (int)(red * (alpha / 255.0)); + int updated_green = (int)(green * (alpha / 255.0)); + int updated_blue = (int)(blue * (alpha / 255.0)); + + std::vector vec; + + if (this->ledPositions) { + for (auto i = 0; i < this->ledPositions->numberOfLed; i++) { + auto ledId = this->ledPositions->pLedPosition[i].ledId; + vec.push_back(CorsairLedColor{ ledId, updated_red, updated_green, updated_blue }); + } + } + + LOG(LogLevel::Debug, L"Update color to (" + to_wstring(updated_red) + L"," + to_wstring(updated_green) + L"," + to_wstring(updated_blue) + L")"); + + return CorsairSetLedsColorsAsync(vec.size(), vec.data(), nullptr, nullptr); + } + + + const char* DeviceCorsair::toString(CorsairError error) + { + switch (error) { + case CE_Success: + return "CE_Success"; + case CE_ServerNotFound: + return "CE_ServerNotFound"; + case CE_NoControl: + return "CE_NoControl"; + case CE_ProtocolHandshakeMissing: + return "CE_ProtocolHandshakeMissing"; + case CE_IncompatibleProtocol: + return "CE_IncompatibleProtocol"; + case CE_InvalidArguments: + return "CE_InvalidArguments"; + default: + return "unknown error"; + } + } + } +} \ No newline at end of file diff --git a/src/Devices/DeviceCorsair.h b/src/Devices/DeviceCorsair.h new file mode 100644 index 0000000..ba29241 --- /dev/null +++ b/src/Devices/DeviceCorsair.h @@ -0,0 +1,41 @@ +#pragma once + +// Windows includes +#include "Device.h" + +// API exports +#include "../Common/ApiExports.h" + +#include "CUESDK.h" + + +namespace lightfx { + namespace devices { + + class LFXE_API DeviceCorsair : public Device { + + public: + void SetRange(const int outMin, const int outMax, const int inMin, const int inMax); + + virtual bool Initialize() override; + virtual bool Enable() override; + virtual bool Disable() override; + + virtual const std::wstring GetDeviceName() override { return L"Corsair"; } + virtual const DeviceType GetDeviceType() override { return DeviceType::DeviceKeyboard; } + + protected: + virtual bool PushColorToDevice(const std::vector& colors) override; + + private: + int rangeOutMin = 0; + int rangeOutMax = 255; + int rangeInMin = 0; + int rangeInMax = 255; + CorsairLedPositions* ledPositions; + + const char* toString(CorsairError error); + }; + + } +} diff --git a/src/Devices/DeviceLogitech.cpp b/src/Devices/DeviceLogitech.cpp index fd378ec..38b9f21 100644 --- a/src/Devices/DeviceLogitech.cpp +++ b/src/Devices/DeviceLogitech.cpp @@ -33,6 +33,10 @@ namespace lightfx { this->rangeInMax = inMax; } + LFXE_API void DeviceLogitech::SetRestoreLightsOnNullEnabled(const bool enabled) { + this->RestoreLightsOnNullEnabled = enabled; + } + LFXE_API void DeviceLogitech::SetG110WorkaroundEnabled(const bool enabled) { this->g110WorkaroundEnabled = enabled; } @@ -59,6 +63,7 @@ namespace lightfx { if (Device::Enable()) { if (LogiLedInit()) { this->Reset(); + LogiLedSaveCurrentLighting(); return true; } else { LOG(LogLevel::Error, L"Could not enable Logitech, make sure that Logitech Gaming Software is running and that it's at least at version 8.57.145"); @@ -72,6 +77,7 @@ namespace lightfx { LFXE_API bool DeviceLogitech::Disable() { if (this->IsEnabled()) { if (Device::Disable()) { + LogiLedRestoreLighting(); LogiLedShutdown(); return true; } @@ -84,6 +90,12 @@ namespace lightfx { double red = colors[0].red; double green = colors[0].green; double blue = colors[0].blue; + double alpha = colors[0].brightness; + + if (this->RestoreLightsOnNullEnabled && red == 0.0 && green == 0.0 && blue == 0.0 && alpha == 0.0) + { + return LogiLedRestoreLighting(); + } if (this->g110WorkaroundEnabled) { double total = red + blue; diff --git a/src/Devices/DeviceLogitech.h b/src/Devices/DeviceLogitech.h index dcf9476..6ad7753 100644 --- a/src/Devices/DeviceLogitech.h +++ b/src/Devices/DeviceLogitech.h @@ -14,7 +14,9 @@ namespace lightfx { public: void SetRange(const int outMin, const int outMax, const int inMin, const int inMax); - void SetG110WorkaroundEnabled(const bool enabled); + void SetRestoreLightsOnNullEnabled(const bool enabled); + void SetG110WorkaroundEnabled(const bool enabled); + virtual bool Initialize() override; virtual bool Enable() override; @@ -32,6 +34,7 @@ namespace lightfx { int rangeInMin = 0; int rangeInMax = 100; + bool RestoreLightsOnNullEnabled = false; bool g110WorkaroundEnabled = false; }; diff --git a/src/LightFXExtender.vcxproj b/src/LightFXExtender.vcxproj index 758683f..4e39e18 100644 --- a/src/LightFXExtender.vcxproj +++ b/src/LightFXExtender.vcxproj @@ -169,7 +169,7 @@ true - $(SolutionDir)lib\x86\LogitechLEDLib.lib;%(AdditionalDependencies) + $(SolutionDir)lib\x86\LogitechLEDLib.lib;$(SolutionDir)lib\x86\CUESDK_2013.lib;%(AdditionalDependencies) /ignore:4099 %(AdditionalOptions) $(SolutionDir)\bin\obj\$(ConfigurationName)\$(PlatformTarget)\$(TargetName).lib @@ -184,7 +184,7 @@ true - $(SolutionDir)lib\x64\LogitechLEDLib.lib;%(AdditionalDependencies) + $(SolutionDir)lib\x64\LogitechLEDLib.lib;$(SolutionDir)lib\x64\CUESDK.x64_2013.lib;%(AdditionalDependencies) /ignore:4099 %(AdditionalOptions) $(SolutionDir)\bin\obj\$(ConfigurationName)\$(PlatformTarget)\$(TargetName).lib @@ -199,7 +199,7 @@ true - $(SolutionDir)lib\x86\LogitechLEDLib.lib;%(AdditionalDependencies) + $(SolutionDir)lib\x86\LogitechLEDLib.lib;$(SolutionDir)lib\x86\CUESDK_2013.lib;%(AdditionalDependencies) /ignore:4099 %(AdditionalOptions) $(SolutionDir)\bin\obj\$(ConfigurationName)\$(PlatformTarget)\$(TargetName).lib @@ -214,7 +214,7 @@ true - $(SolutionDir)lib\x64\LogitechLEDLib.lib;%(AdditionalDependencies) + $(SolutionDir)lib\x64\LogitechLEDLib.lib;$(SolutionDir)lib\x64\CUESDK.x64_2013.lib;%(AdditionalDependencies) /ignore:4099 %(AdditionalOptions) $(SolutionDir)\bin\obj\$(ConfigurationName)\$(PlatformTarget)\$(TargetName).lib @@ -233,7 +233,7 @@ true true true - $(SolutionDir)lib\x86\LogitechLEDLib.lib;%(AdditionalDependencies) + $(SolutionDir)lib\x86\LogitechLEDLib.lib;$(SolutionDir)lib\x86\CUESDK_2013.lib;%(AdditionalDependencies) /ignore:4099 %(AdditionalOptions) $(SolutionDir)\bin\obj\$(ConfigurationName)\$(PlatformTarget)\$(TargetName).lib @@ -252,7 +252,7 @@ true true true - $(SolutionDir)lib\x64\LogitechLEDLib.lib;%(AdditionalDependencies) + $(SolutionDir)lib\x64\LogitechLEDLib.lib;$(SolutionDir)lib\x64\CUESDK.x64_2013.lib;%(AdditionalDependencies) /ignore:4099 %(AdditionalOptions) $(SolutionDir)\bin\obj\$(ConfigurationName)\$(PlatformTarget)\$(TargetName).lib @@ -270,7 +270,7 @@ true true true - $(SolutionDir)lib\x86\LogitechLEDLib.lib;%(AdditionalDependencies) + $(SolutionDir)lib\x86\LogitechLEDLib.lib;$(SolutionDir)lib\x86\CUESDK_2013.lib;%(AdditionalDependencies) WIN32;NDEBUG;%(PreprocessorDefinitions) /ignore:4099 %(AdditionalOptions) $(SolutionDir)\bin\obj\$(ConfigurationName)\$(PlatformTarget)\$(TargetName).lib @@ -289,7 +289,7 @@ true true true - $(SolutionDir)lib\x64\LogitechLEDLib.lib;%(AdditionalDependencies) + $(SolutionDir)lib\x64\LogitechLEDLib.lib;$(SolutionDir)lib\x64\CUESDK.x64_2013.lib;%(AdditionalDependencies) WIN32;NDEBUG;%(PreprocessorDefinitions) /ignore:4099 %(AdditionalOptions) $(SolutionDir)\bin\obj\$(ConfigurationName)\$(PlatformTarget)\$(TargetName).lib @@ -301,6 +301,7 @@ + @@ -342,6 +343,7 @@ + @@ -365,6 +367,16 @@ + + + ..\x64\CUESDK.x64_2013.dll + PreserveNewest + + + ..\x86\CUESDK_2013.dll + PreserveNewest + + diff --git a/src/LightFXExtender.vcxproj.filters b/src/LightFXExtender.vcxproj.filters index 3ab71f7..a7da3ef 100644 --- a/src/LightFXExtender.vcxproj.filters +++ b/src/LightFXExtender.vcxproj.filters @@ -120,6 +120,9 @@ Header Files + + Header Files + @@ -207,5 +210,12 @@ Source Files + + Source Files + + + + + \ No newline at end of file diff --git a/src/Managers/DeviceManager.cpp b/src/Managers/DeviceManager.cpp index 675cb7d..50eb4fe 100644 --- a/src/Managers/DeviceManager.cpp +++ b/src/Managers/DeviceManager.cpp @@ -11,6 +11,7 @@ #include "../Devices/DeviceLightFX.h" #include "../Devices/DeviceLightpack.h" #include "../Devices/DeviceLogitech.h" +#include "../Devices/DeviceCorsair.h" #include "../Devices/LightFX2.h" #include "../Utils/FileIO.h" #include "../Utils/LightFX.h" @@ -41,14 +42,25 @@ namespace lightfx { ++i; } + auto logitech = make_shared(); logitech->SetRange(config->LogitechColorRangeOutMin, config->LogitechColorRangeOutMax, config->LogitechColorRangeInMin, config->LogitechColorRangeInMax); this->AddChild(L"Logitech", logitech); + logitech->SetRestoreLightsOnNullEnabled(config->LogitechRestoreLightsOnNullEnabled); logitech->SetG110WorkaroundEnabled(config->LogitechG110WorkaroundEnabled); if (logitech->Initialize()) { ++i; } + + auto corsair = make_shared(); + corsair->SetRange(config->CorsairColorRangeOutMin, config->CorsairColorRangeOutMax, config->CorsairColorRangeInMin, config->CorsairColorRangeInMax); + this->AddChild(L"Corsair", corsair); + if (corsair->Initialize()) { + ++i; + } + + // Load native LightFX devices if (InitializeLightFX(config->AlienwareDllName, config->AlienwareBackupDllName)) { LOG(LogLevel::Debug, L"Alienware LightFX.dll loaded");