Last active
September 9, 2019 13:55
-
-
Save georgyangelov/297de067a00aebc0a4748fa798a0b234 to your computer and use it in GitHub Desktop.
C++ wrapper class for working with the Creative Aurora LED SDK (for the SoundBlasterX Vanguard K08 keyboard)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <initguid.h> | |
#include <windows.h> | |
#include <vector> | |
#include "../sdk/Include/ICTLEDMgr.h" | |
#include "../sdk/Include/CLSID_CCTLEDMgr.h" | |
#include "../sdk/Include/CTIntrfc_DynamicLoad.h" | |
#include "../sdk/Include/CTLEDCommon.h" | |
#include "LEDGroupings.h" | |
struct ConnectedDevice { | |
USHORT vendorId; | |
USHORT productId; | |
WCHAR serialNumber[1000]; | |
DWORD serialNumberSize = 1000; | |
WCHAR instance[1000]; | |
DWORD instanceSize = 1000; | |
USHORT ledInfoFlag; | |
USHORT totalNumLeds; | |
WCHAR friendlyName[1000]; | |
DWORD friendlyNameSize = 1000; | |
}; | |
inline int timerCallback(CTLEDMGRTIMERPROCDATA*, LPARAM); | |
struct KeyboardController { | |
private: | |
ICTLEDMgr* api; | |
int groupCount = ALL_LEDS_COUNT; | |
int ledsInGroup = 1; | |
DWORD grouping[ALL_LEDS_COUNT][2] = {0}; | |
CTLEDMGRCMDPARAM_SetLedSettings ledSettings = { }; | |
CTLED_Pattern pattern[ALL_LEDS_COUNT] = { }; | |
// TODO: Remove the padding | |
CTColour pixels[ALL_LEDS_COUNT + 1000] = {0}; | |
bool running = false; | |
int targetIntervalMillis = 1; | |
friend int timerCallback(CTLEDMGRTIMERPROCDATA*, LPARAM); | |
public: | |
KeyboardController(ICTLEDMgr* api) { | |
this->api = api; | |
configureSingleLedGrouping(grouping); | |
for (int i = 0; i < groupCount; i++) { | |
pattern[i] = CTLED_Pattern_Static; | |
} | |
} | |
std::vector<ConnectedDevice> enumerateConnectedDevices() { | |
std::vector<ConnectedDevice> devices; | |
for (int i = 0; ; i++) { | |
ConnectedDevice device; | |
HRESULT result = api->EnumConnectedDevices( | |
i, | |
&device.vendorId, | |
&device.productId, | |
(LPWSTR)&device.serialNumber, | |
&device.serialNumberSize, | |
(LPWSTR)&device.instance, | |
&device.instanceSize, | |
&device.ledInfoFlag, | |
&device.totalNumLeds, | |
(LPWSTR)&device.friendlyName, | |
&device.friendlyNameSize, | |
0 | |
); | |
if (!SUCCEEDED(result)) { | |
break; | |
} | |
devices.push_back(device); | |
} | |
return devices; | |
} | |
void openDevice(ConnectedDevice* device) { | |
DWORD detailErrorCode; | |
HRESULT result = api->Open( | |
device->vendorId, | |
device->productId, | |
device->serialNumber, | |
device->instance, | |
0, | |
0, | |
false, | |
&detailErrorCode, | |
0 | |
); | |
if (!SUCCEEDED(result)) { | |
// TODO: Error handling | |
throw std::exception("Cannot open device"); | |
} | |
configureLeds(); | |
} | |
void closeDevice() { | |
api->Close(0); | |
} | |
int getPixelCount() { | |
return ALL_LEDS_COUNT; | |
} | |
CTColour* getPixelBuffer() { | |
return pixels; | |
} | |
void fillPixelBuffer(CTColour* colors, int colorCount) { | |
if (colorCount > ALL_LEDS_COUNT) { | |
colorCount = ALL_LEDS_COUNT; | |
} | |
memcpy(pixels, colors, colorCount * sizeof(CTColour)); | |
} | |
void sendPixels() { | |
CTLEDINFOCMDPARAM_FillupAll fill = { }; | |
fill.pLedInfo = &ledSettings.colourLed; | |
fill.dwNumLedGroups = groupCount; | |
fill.pPatternIndividualLedGroupArray1D = &pattern[0]; | |
fill.pdwLedGroupingArray2D = &grouping[0][0]; | |
fill.dwNumColumnsOfLedGroupArray2D = ledsInGroup + 1; | |
fill.dwNumColourLayers = 1; | |
fill.pColourIndividualLedGroupArray2D = &pixels[0]; | |
fill.dwNumColumnsOfColourIndividualLedGroupArray2D = 1; | |
HRESULT result = api->PrepareLedInfo( | |
CTLEDINFOCMD_FillupAll, | |
(LPARAM)&fill, | |
0 | |
); | |
if (!SUCCEEDED(result)) { | |
// TODO: Error handling | |
throw std::exception("Cannot prepare LED info"); | |
} | |
CTInit_CTLEDMGRCMDPARAM_SetLedSettings(&ledSettings); | |
ledSettings.fIgnoreColour = false; | |
ledSettings.fIgnorePattern = false; | |
ledSettings.patternLed = CTLED_Pattern_Static; | |
ledSettings.fIgnorePatternDirection = true; | |
ledSettings.fIgnorePatternDirectionFlag = true; | |
ledSettings.flagLedPatternDirection = CTLED_PatternDirectionFlag_Looping; | |
ledSettings.fIgnorePeriodicTime = true; | |
ledSettings.patternLedThePeriodicTimeIsFor = CTLED_Pattern_Static; | |
ledSettings.dwPeriodicTimeInMilliseconds = 0; | |
ledSettings.dwPeriodicTimeInCyclesPerMinute = 0; | |
result = api->ExecuteCommand(CTLEDMGRCMD_SetLedSettings, (LPARAM)&ledSettings, 0); | |
if (!SUCCEEDED(result)) { | |
// TODO: Error handling | |
throw std::exception("Cannot set LEDs"); | |
} | |
} | |
void enableTimerSending() { | |
CTTIMERINFOPARAM timerParameters = { }; | |
timerParameters.dwDueTimeInMilliseconds = 0; | |
timerParameters.dwPeriodicTimeInMilliseconds = 1; | |
//timerParameters.dwPeriodicTimeInMilliseconds = 1000 / 60; | |
HRESULT result = api->RegisterTimerCallback(timerCallback, &timerParameters, (LPARAM)this, 0); | |
if (!SUCCEEDED(result)) { | |
throw std::exception("Cannot register timer callback"); | |
} | |
running = true; | |
targetIntervalMillis = timerParameters.dwPeriodicTimeInMilliseconds; | |
} | |
void disableTimerSending() { | |
HRESULT result = api->UnregisterTimerCallback(0); | |
if (!SUCCEEDED(result)) { | |
throw std::exception("Cannot unregister timer callback"); | |
} | |
running = false; | |
} | |
private: | |
void configureLeds() { | |
CTLEDINFOCMDPARAM_Initialize initializeConfig = { }; | |
initializeConfig.dwMaxNumLedGroups = groupCount; | |
initializeConfig.dwMaxNumLedsInEachGroup = ledsInGroup; | |
initializeConfig.dwMaxNumColourLayersInEachGroup = 1; | |
initializeConfig.pLedInfo = &ledSettings.colourLed; | |
HRESULT result = api->PrepareLedInfo(CTLEDINFOCMD_Initialize, (LPARAM)&initializeConfig, 0); | |
if (!SUCCEEDED(result)) { | |
// TODO: Error handling | |
throw std::exception("Cannot initialize LED config"); | |
} | |
} | |
}; | |
inline int timerCallback(CTLEDMGRTIMERPROCDATA* timerData, LPARAM userData) { | |
auto controller = (KeyboardController*)userData; | |
if (controller->running){ | |
controller->sendPixels(); | |
} | |
return 0; | |
} | |
#define EXPORTED extern "C" __declspec(dllexport) | |
EXPORTED KeyboardController* create_controller() { | |
HMODULE interfaceUtilsDll = LoadLibraryW(L"CTIntrfu.dll"); | |
ICTLEDMgr* manager; | |
CTINTRFCRESULT result = CTCreateInstanceEx_Dyn( | |
interfaceUtilsDll, CLSID_CCTLEDMgr, NULL, 0, IID_ICTLEDMgr, NULL, NULL, | |
L"CTLEDMgr.dll", NULL, (void**)&manager | |
); | |
if (result != CTINTRFCRESULT_Success) { | |
return nullptr; | |
} | |
DWORD dwFlag = 0; | |
HRESULT initResult = manager->Initialize(DEFINITION_CTLEDMgr_Interface_Version, dwFlag); | |
if (!SUCCEEDED(initResult)) { | |
manager->Release(); | |
CTFreeUnusedLibrariesEx_Dyn(interfaceUtilsDll); | |
return nullptr; | |
} | |
return new KeyboardController(manager); | |
} | |
EXPORTED size_t controller_get_connected_devices(KeyboardController* self, ConnectedDevice* connectedDevices, int connectedDevicesCapacity) { | |
auto devices = self->enumerateConnectedDevices(); | |
if (devices.size() < connectedDevicesCapacity) { | |
return -1; | |
} | |
for (int i = 0; i < devices.size(); i++) { | |
connectedDevices[i] = devices[i]; | |
} | |
return devices.size(); | |
} | |
EXPORTED void controller_open_device(KeyboardController* self, ConnectedDevice* device) { | |
self->openDevice(device); | |
} | |
EXPORTED void controller_close_device(KeyboardController* self) { | |
self->closeDevice(); | |
} | |
EXPORTED int controller_get_pixel_count(KeyboardController* self) { | |
return self->getPixelCount(); | |
} | |
EXPORTED void controller_fill_pixel_buffer(KeyboardController* self, CTColour* pixels, int pixelCount) { | |
self->fillPixelBuffer(pixels, pixelCount); | |
} | |
EXPORTED CTColour* controller_get_pixel_buffer(KeyboardController* self) { | |
return self->getPixelBuffer(); | |
} | |
EXPORTED void controller_send_pixels(KeyboardController* self) { | |
self->sendPixels(); | |
} | |
EXPORTED void controller_enable_timer_sending(KeyboardController* self) { | |
self->enableTimerSending(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
const DWORD ALL_LEDS[] = { | |
CTKEYBOARD_LEDIndex_Esc, | |
CTKEYBOARD_LEDIndex_F1, | |
CTKEYBOARD_LEDIndex_F2, | |
CTKEYBOARD_LEDIndex_F3, | |
CTKEYBOARD_LEDIndex_F4, | |
CTKEYBOARD_LEDIndex_F5, | |
CTKEYBOARD_LEDIndex_F6, | |
CTKEYBOARD_LEDIndex_F7, | |
CTKEYBOARD_LEDIndex_F8, | |
CTKEYBOARD_LEDIndex_F9, | |
CTKEYBOARD_LEDIndex_F10, | |
CTKEYBOARD_LEDIndex_F11, | |
CTKEYBOARD_LEDIndex_F12, | |
CTKEYBOARD_LEDIndex_PrintScreen, | |
CTKEYBOARD_LEDIndex_ScrollLock, | |
CTKEYBOARD_LEDIndex_Pause, | |
CTKEYBOARD_LEDIndex_M1, | |
CTKEYBOARD_LEDIndex_BackQuote, | |
CTKEYBOARD_LEDIndex_1, | |
CTKEYBOARD_LEDIndex_2, | |
CTKEYBOARD_LEDIndex_3, | |
CTKEYBOARD_LEDIndex_4, | |
CTKEYBOARD_LEDIndex_5, | |
CTKEYBOARD_LEDIndex_6, | |
CTKEYBOARD_LEDIndex_7, | |
CTKEYBOARD_LEDIndex_8, | |
CTKEYBOARD_LEDIndex_9, | |
CTKEYBOARD_LEDIndex_0, | |
CTKEYBOARD_LEDIndex_Minus, | |
CTKEYBOARD_LEDIndex_Equal, | |
CTKEYBOARD_LEDIndex_Backspace, | |
CTKEYBOARD_LEDIndex_Insert, | |
CTKEYBOARD_LEDIndex_Home, | |
CTKEYBOARD_LEDIndex_PageUp, | |
CTKEYBOARD_LEDIndex_PadNumLock, | |
CTKEYBOARD_LEDIndex_PadForwardSlash, | |
CTKEYBOARD_LEDIndex_PadAsterisk, | |
CTKEYBOARD_LEDIndex_PadMinus, | |
CTKEYBOARD_LEDIndex_M2, | |
CTKEYBOARD_LEDIndex_Tab, | |
CTKEYBOARD_LEDIndex_Q, | |
CTKEYBOARD_LEDIndex_W, | |
CTKEYBOARD_LEDIndex_E, | |
CTKEYBOARD_LEDIndex_R, | |
CTKEYBOARD_LEDIndex_T, | |
CTKEYBOARD_LEDIndex_Y, | |
CTKEYBOARD_LEDIndex_U, | |
CTKEYBOARD_LEDIndex_I, | |
CTKEYBOARD_LEDIndex_O, | |
CTKEYBOARD_LEDIndex_P, | |
CTKEYBOARD_LEDIndex_OpenBracket, | |
CTKEYBOARD_LEDIndex_ClosedBracket, | |
CTKEYBOARD_LEDIndex_BackSlash, | |
CTKEYBOARD_LEDIndex_Delete, | |
CTKEYBOARD_LEDIndex_End, | |
CTKEYBOARD_LEDIndex_PageDown, | |
CTKEYBOARD_LEDIndex_Pad7, | |
CTKEYBOARD_LEDIndex_Pad8, | |
CTKEYBOARD_LEDIndex_Pad9, | |
CTKEYBOARD_LEDIndex_PadPlus, | |
CTKEYBOARD_LEDIndex_M3, | |
CTKEYBOARD_LEDIndex_CapsLock, | |
CTKEYBOARD_LEDIndex_A, | |
CTKEYBOARD_LEDIndex_S, | |
CTKEYBOARD_LEDIndex_D, | |
CTKEYBOARD_LEDIndex_F, | |
CTKEYBOARD_LEDIndex_G, | |
CTKEYBOARD_LEDIndex_H, | |
CTKEYBOARD_LEDIndex_J, | |
CTKEYBOARD_LEDIndex_K, | |
CTKEYBOARD_LEDIndex_L, | |
CTKEYBOARD_LEDIndex_Semicolon, | |
CTKEYBOARD_LEDIndex_Apostrophe, | |
CTKEYBOARD_LEDIndex_Enter, | |
CTKEYBOARD_LEDIndex_Pad4, | |
CTKEYBOARD_LEDIndex_Pad5, | |
CTKEYBOARD_LEDIndex_Pad6, | |
CTKEYBOARD_LEDIndex_M4, | |
CTKEYBOARD_LEDIndex_LeftShift, | |
CTKEYBOARD_LEDIndex_Z, | |
CTKEYBOARD_LEDIndex_X, | |
CTKEYBOARD_LEDIndex_C, | |
CTKEYBOARD_LEDIndex_V, | |
CTKEYBOARD_LEDIndex_B, | |
CTKEYBOARD_LEDIndex_N, | |
CTKEYBOARD_LEDIndex_M, | |
CTKEYBOARD_LEDIndex_Comma, | |
CTKEYBOARD_LEDIndex_Fullstop, | |
CTKEYBOARD_LEDIndex_ForwardSlash, | |
CTKEYBOARD_LEDIndex_RightShift, | |
CTKEYBOARD_LEDIndex_UpArrow, | |
CTKEYBOARD_LEDIndex_Pad1, | |
CTKEYBOARD_LEDIndex_Pad2, | |
CTKEYBOARD_LEDIndex_Pad3, | |
CTKEYBOARD_LEDIndex_PadEnter, | |
CTKEYBOARD_LEDIndex_M5, | |
CTKEYBOARD_LEDIndex_LeftCtrl, | |
CTKEYBOARD_LEDIndex_LeftWindows, | |
CTKEYBOARD_LEDIndex_LeftAlt, | |
CTKEYBOARD_LEDIndex_Space, | |
CTKEYBOARD_LEDIndex_RightAlt, | |
CTKEYBOARD_LEDIndex_Fn, | |
CTKEYBOARD_LEDIndex_Menu, | |
CTKEYBOARD_LEDIndex_RightCtrl, | |
CTKEYBOARD_LEDIndex_LeftArrow, | |
CTKEYBOARD_LEDIndex_DownArrow, | |
CTKEYBOARD_LEDIndex_RightArrow, | |
CTKEYBOARD_LEDIndex_Pad0, | |
CTKEYBOARD_LEDIndex_PadFullstop, | |
CTKEYBOARD_LEDIndex_Logo, | |
}; | |
const int ALL_LEDS_COUNT = sizeof(ALL_LEDS) / sizeof(ALL_LEDS[0]); | |
inline void configureSingleLedGrouping(DWORD grouping[][2]) { | |
for (int i = 0; i < ALL_LEDS_COUNT; i++) { | |
grouping[i][0] = 1; | |
grouping[i][1] = ALL_LEDS[i]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "KeyboardController.h" | |
#include <iostream> | |
int main() { | |
KeyboardController* controller = create_controller(); | |
auto devices = controller->enumerateConnectedDevices(); | |
if (devices.empty()) { | |
std::cerr << "No connected devices\n"; | |
return 1; | |
} | |
if (devices.size() > 1) { | |
std::cerr << "More than one supported device is connected. Cannot choose.\n"; | |
return 2; | |
} | |
auto device = devices[0]; | |
controller->openDevice(&device); | |
CTColour* colors = controller->getPixelBuffer(); | |
for (int i = 0; i < controller->getPixelCount(); i++) { | |
colors[i] = CTColour{255, 0, 0, 255}; | |
} | |
controller->enableTimerSending(); | |
std::cout << "Press enter to stop..."; | |
std::cin.get(); | |
controller->disableTimerSending(); | |
controller->closeDevice(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Interesting. It seems like something related to the pointer width? Maybe the SDK dlls are compiled in 32bit mode while your code is trying to use it in 64bit? Or vice-versa. You can try changing the build setting in VS for your project and see if that does something