diff --git a/Controllers/SkyloongController/RGBController_SkyloongGK104Pro.cpp b/Controllers/SkyloongController/RGBController_SkyloongGK104Pro.cpp new file mode 100644 index 00000000..9ee0a61e --- /dev/null +++ b/Controllers/SkyloongController/RGBController_SkyloongGK104Pro.cpp @@ -0,0 +1,161 @@ +/*---------------------------------------------------------*\ +| RGBController_SkyloongGK104Pro.cpp | +| | +| RGBController for Skyloong GK104 Pro | +| | +| Givo (givowo) 30 Jun 2024 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include "RGBControllerKeyNames.h" +#include "RGBController_SkyloongGK104Pro.h" +#include "KeyboardLayoutManager.h" + +using namespace std::chrono_literals; + +/*---------------------------------------------------------------------*\ +| Skyloong GK104 Pro Keyboard KLM Layout | +\*---------------------------------------------------------------------*/ +layout_values keyboard_offset_values = +{ + { + /* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */ + 0, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + /* BKTK 1 2 3 4 5 6 7 8 9 0 - = BSPC INS HOME PGUP NLCK NP/ NP* NP- */ + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, + /* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NP7 NP8 NP9 NP+ */ + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, + /* CPLK A S D F G H J K L ; " # ENTR NP4 NP5 NP6 */ + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 84, 85, 86, + /* LSFT / Z X C V B N M , . / RSFT ARWU NP1 NP2 NP3 NPEN */ + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 102, 104, 106, 107, 108, 109, + /* LCTL LWIN LALT SPC SPC SPC RALT RFNC RMNU RCTL ARWL ARWD ARWR NP0 NP. */ + 110, 111, 112, 116, 120, 121, 122, 124, 125, 126, 127, 128, 130 + }, + { + /* Add more regional layout fixes here */ + } +}; + +/**------------------------------------------------------------------*\ + @name Skyloong GK104 Pro + @category Keyboard + @type USB + @save :o: + @direct :white_check_mark: + @effects :o: + @detectors SkyloongControllerDetect + @comment +\*-------------------------------------------------------------------*/ + +RGBController_SkyloongGK104Pro::RGBController_SkyloongGK104Pro(SkyloongGK104ProController* controller_ptr) +{ + controller = controller_ptr; + + name = "Skyloong GK104 Pro"; + vendor = "Skyloong"; + description = "Skyloong GK104 Pro Keyboard"; + location = controller->GetDeviceLocation(); + type = DEVICE_TYPE_KEYBOARD; + + mode Direct; + Direct.name = "Direct"; + Direct.value = 0xFFFF; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS; + Direct.color_mode = MODE_COLORS_PER_LED; + Direct.brightness_min = BRIGHTNESS_MIN; + Direct.brightness_max = BRIGHTNESS_MAX; + Direct.brightness = BRIGHTNESS_MAX; + + modes.push_back(Direct); + + SetupZones(); +} + +RGBController_SkyloongGK104Pro::~RGBController_SkyloongGK104Pro() +{ + delete controller; +} + +void RGBController_SkyloongGK104Pro::SetupZones() +{ + /*---------------------------------------------------------*\ + | Create the keyboard zone usiung Keyboard Layout Manager | + \*---------------------------------------------------------*/ + zone new_zone; + new_zone.name = ZONE_EN_KEYBOARD; + new_zone.type = ZONE_TYPE_MATRIX; + + KeyboardLayoutManager new_kb(KEYBOARD_LAYOUT_ANSI_QWERTY, KEYBOARD_SIZE_FULL, keyboard_offset_values); + + new_kb.ChangeKeys( + { + { 0, 4, 12, 0, KEY_EN_RIGHT_SHIFT, KEYBOARD_OPCODE_REMOVE_SHIFT_LEFT }, + { 0, 4, 14, 0, KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT }, + { 0, 5, 4, 114, "Key: Left Space", KEYBOARD_OPCODE_SWAP_ONLY }, + { 0, 5, 8, 118, "Key: Right Space", KEYBOARD_OPCODE_SWAP_ONLY } + } + ); + + matrix_map_type * new_map = new matrix_map_type; + new_zone.matrix_map = new_map; + new_zone.matrix_map->height = new_kb.GetRowCount(); + new_zone.matrix_map->width = new_kb.GetColumnCount(); + + new_zone.matrix_map->map = new unsigned int[new_map->height * new_map->width]; + new_zone.leds_count = new_kb.GetKeyCount(); + new_zone.leds_min = new_zone.leds_count; + new_zone.leds_max = new_zone.leds_count; + + /*---------------------------------------------------------*\ + | Matrix map still uses declared zone rows and columns | + | as the packet structure depends on the matrix map | + \*---------------------------------------------------------*/ + new_kb.GetKeyMap(new_map->map, KEYBOARD_MAP_FILL_TYPE_COUNT, new_map->height, new_map->width); + + /*---------------------------------------------------------*\ + | Create LEDs for the Matrix zone | + | Place keys in the layout to populate the matrix | + \*---------------------------------------------------------*/ + for(unsigned int led_idx = 0; led_idx < new_zone.leds_count; led_idx++) + { + led new_led; + + new_led.name = new_kb.GetKeyNameAt(led_idx); + new_led.value = new_kb.GetKeyValueAt(led_idx); + + leds.push_back(new_led); + } + + zones.push_back(new_zone); + + SetupColors(); +} + +void RGBController_SkyloongGK104Pro::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_SkyloongGK104Pro::DeviceUpdateLEDs() +{ + controller->SendColorPacket(colors, &leds, modes[active_mode].brightness); +} + +void RGBController_SkyloongGK104Pro::UpdateZoneLEDs(int /*zone*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_SkyloongGK104Pro::UpdateSingleLED(int /*led*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_SkyloongGK104Pro::DeviceUpdateMode() +{ +} diff --git a/Controllers/SkyloongController/RGBController_SkyloongGK104Pro.h b/Controllers/SkyloongController/RGBController_SkyloongGK104Pro.h new file mode 100644 index 00000000..385a8090 --- /dev/null +++ b/Controllers/SkyloongController/RGBController_SkyloongGK104Pro.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------*\ +| RGBController_SkyloongGK104Pro.h | +| | +| RGBController for Skyloong GK104 Pro | +| | +| Givo (givowo) 30 Jun 2024 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "SkyloongGK104ProController.h" + +#define BRIGHTNESS_MIN 0 +#define BRIGHTNESS_MAX 134 + +class RGBController_SkyloongGK104Pro : public RGBController +{ +public: + RGBController_SkyloongGK104Pro(SkyloongGK104ProController* controller_ptr); + ~RGBController_SkyloongGK104Pro(); + + void SetupZones(); + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + +private: + SkyloongGK104ProController* controller; +}; diff --git a/Controllers/SkyloongController/SkyloongControllerDetect.cpp b/Controllers/SkyloongController/SkyloongControllerDetect.cpp new file mode 100644 index 00000000..842df064 --- /dev/null +++ b/Controllers/SkyloongController/SkyloongControllerDetect.cpp @@ -0,0 +1,47 @@ +/*---------------------------------------------------------*\ +| SkyloongControllerDetect.cpp | +| | +| Detector for Skyloong Keyboards | +| | +| Givo (givowo) 30 Jun 2024 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include "Detector.h" +#include "SkyloongGK104ProController.h" +#include "RGBController.h" +#include "RGBController_SkyloongGK104Pro.h" + +/*-----------------------------------------------------*\ +| Keyboard product IDs | +\*-----------------------------------------------------*/ +#define SKYLOONG_KEYBOARD_VID 0x1EA7 +#define SKYLOONG_GK104_PRO_PID 0x0907 +#define SKYLOONG_GK104_PRO_I 1 + +/******************************************************************************************\ +* * +* DetectSkyloongGK104Pro * +* * +* Tests the USB address to see if a Skyloong GK104 Pro controller exists there. * +* * +\******************************************************************************************/ +void DetectSkyloongGK104Pro(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + if(dev) + { + SkyloongGK104ProController* controller = new SkyloongGK104ProController(dev, info->path); + RGBController_SkyloongGK104Pro* rgb_controller = new RGBController_SkyloongGK104Pro(controller); + rgb_controller->name = name; + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} + +/*---------------------------------------------------------------------------------------------------------------------------------------------*\ +| Keyboards | +\*---------------------------------------------------------------------------------------------------------------------------------------------*/ +REGISTER_HID_DETECTOR_I("Skyloong GK104 Pro", DetectSkyloongGK104Pro, SKYLOONG_KEYBOARD_VID, SKYLOONG_GK104_PRO_PID, SKYLOONG_GK104_PRO_I); diff --git a/Controllers/SkyloongController/SkyloongGK104ProController.cpp b/Controllers/SkyloongController/SkyloongGK104ProController.cpp new file mode 100644 index 00000000..7ade92bf --- /dev/null +++ b/Controllers/SkyloongController/SkyloongGK104ProController.cpp @@ -0,0 +1,134 @@ +/*---------------------------------------------------------*\ +| SkyloongGK104ProController.cpp | +| | +| Driver for Skyloong GK104 Pro | +| | +| Givo (givowo) 30 Jun 2024 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include "SkyloongGK104ProController.h" + +using namespace std::chrono_literals; + +enum command +{ + ping = 0x0C, + mode = 0xB, + le_define = 0x1A +}; + +SkyloongGK104ProController::SkyloongGK104ProController(hid_device* dev_handle, const char* path) +{ + dev = dev_handle; + location = path; + + SendCommand(command::ping, SUBCOMMAND_NONE); + SendCommand(command::mode, MODE_ONLINE); + SendCommand(command::ping, SUBCOMMAND_NONE); +} + +SkyloongGK104ProController::~SkyloongGK104ProController() +{ + SendCommand(command::mode, MODE_OFFLINE); + hid_close(dev); +} + +std::string SkyloongGK104ProController::GetDeviceLocation() +{ + return("HID: " + location); +} + +void SkyloongGK104ProController::SendCommand(char command, char sub_command) +{ + unsigned char buf[PACKET_SIZE]; + memset(buf, 0x00, PACKET_SIZE); + + buf[0x01] = command; + buf[0x02] = sub_command; + + uint16_t crc = Crc16CcittFalse(buf, PACKET_SIZE); + + buf[0x07] = crc & 0xFF; + buf[0x08] = crc >> 8; + + hid_write(dev, buf, PACKET_SIZE); +} + +void SkyloongGK104ProController::SendColorPacket(std::vector colors, std::vector *leds, int brightness) +{ + unsigned char le_data[TOTAL_LED_BYTES]; + memset(le_data, 0x00, TOTAL_LED_BYTES); + + for(int i = 0; i < leds->size(); i++) + { + int index = leds->at(i).value * 4; + le_data[index++] = RGBGetRValue(colors[i]); + le_data[index++] = RGBGetGValue(colors[i]); + le_data[index++] = RGBGetBValue(colors[i]); + le_data[index++] = brightness; + } + + for(int n = 0; n < TOTAL_LED_BYTES; n += LED_BYTES_IN_CHUNK) { + if(n + LED_BYTES_IN_CHUNK <= TOTAL_LED_BYTES) + { + SetLEDefine(n, &le_data[n], LED_BYTES_IN_CHUNK); + } + else + { + SetLEDefine(n, &le_data[n], TOTAL_LED_BYTES - n); + } + } + + SendCommand(command::le_define, LE_DEFINE_SAVE); +} + +void SkyloongGK104ProController::SetLEDefine(int address, unsigned char *le_data, int le_data_length) +{ + unsigned char buf[PACKET_SIZE]; + memset(buf, 0x00, PACKET_SIZE); + + buf[0x01] = command::le_define; + buf[0x02] = LE_DEFINE_SET; + + int header = (address + ((le_data_length << 24) & 0xFF000000)) | 0; + buf[0x03] = header & 0xFF; + buf[0x04] = (header >> 8) & 0xFF; + buf[0x05] = (header >> 16) & 0xFF; + buf[0x06] = (header >> 24) & 0xFF; + + std::copy(le_data, le_data + le_data_length, buf + 9); + + uint16_t crc = Crc16CcittFalse(buf, PACKET_SIZE); + buf[0x07] = crc & 0xFF; + buf[0x08] = crc >> 8; + + hid_write(dev, buf, PACKET_SIZE); +} + +uint16_t SkyloongGK104ProController::Crc16CcittFalse(const uint8_t *buffer, uint16_t size) +{ + uint16_t crc = 0xFFFF; + + while(size--) + { + crc ^= (*buffer++ << 8); + + for(uint8_t i = 0; i < 8; ++i) + { + if(crc & 0x8000) + { + crc = (crc << 1) ^ 0x1021; + } + else + { + crc = crc << 1; + } + } + } + + return crc; +} diff --git a/Controllers/SkyloongController/SkyloongGK104ProController.h b/Controllers/SkyloongController/SkyloongGK104ProController.h new file mode 100644 index 00000000..b664766f --- /dev/null +++ b/Controllers/SkyloongController/SkyloongGK104ProController.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------*\ +| SkyloongGK104ProController.h | +| | +| Driver for Skyloong GK104 Pro | +| | +| Givo (givowo) 30 Jun 2024 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include + +class SkyloongGK104ProController +{ +public: + SkyloongGK104ProController(hid_device* dev_handle, const char* path); + ~SkyloongGK104ProController(); + + std::string GetDeviceLocation(); + + void Ping(); + void SetMode(int mode); + void SendCommand(char command, char sub_command); + void SendColorPacket(std::vector colors, std::vector *leds, int brightness); + +private: + hid_device* dev; + std::string location; + + uint16_t Crc16CcittFalse(const uint8_t *buffer, uint16_t size); + void SetLEDefine(int address, unsigned char *le_data, int le_data_length); + void SaveLEDefine(); +};