/* This file is part of g810-led. g810-led is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. g810-led is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with g810-led. If not, see . */ #include "Keyboard.h" #include #include #include #if defined(hidapi) #include #include "hidapi/hidapi.h" #elif defined(libusb) #include "libusb-1.0/libusb.h" #endif using namespace std; LedKeyboard::~LedKeyboard() { close(); } vector LedKeyboard::listKeyboards() { vector deviceList; #if defined(hidapi) if (hid_init() < 0) return deviceList; struct hid_device_info *devs, *dev; devs = hid_enumerate(0x0, 0x0); dev = devs; while (dev) { for (size_t i = 0; i < SupportedKeyboards.size(); i++) { if (dev->vendor_id == SupportedKeyboards[i][0]) { if (dev->product_id == SupportedKeyboards[i][1]) { DeviceInfo deviceInfo; deviceInfo.vendorID=dev->vendor_id; deviceInfo.productID=dev->product_id; if (dev->serial_number != NULL) { char buf[256]; wcstombs(buf, dev->serial_number, 256); deviceInfo.serialNumber = string(buf); } if (dev->manufacturer_string != NULL) { char buf[256]; wcstombs(buf, dev->manufacturer_string, 256); deviceInfo.manufacturer = string(buf); } if (dev->product_string != NULL) { char buf[256]; wcstombs(buf, dev->product_string, 256); deviceInfo.product = string(buf); } deviceList.push_back(deviceInfo); dev = dev->next; break; } } } if (dev != NULL) dev = dev->next; } hid_free_enumeration(devs); hid_exit(); #elif defined(libusb) libusb_context *ctx = NULL; if(libusb_init(&m_ctx) < 0) return deviceList; libusb_device **devs; ssize_t cnt = libusb_get_device_list(ctx, &devs); for(ssize_t i = 0; i < cnt; i++) { libusb_device *device = devs[i]; libusb_device_descriptor desc; libusb_get_device_descriptor(device, &desc); for (int i=0; i<(int)SupportedKeyboards.size(); i++) { if (desc.idVendor == SupportedKeyboards[i][0]) { if (desc.idProduct == SupportedKeyboards[i][1]) { unsigned char buf[256]; DeviceInfo deviceInfo; deviceInfo.vendorID=desc.idVendor; deviceInfo.productID=desc.idProduct; if (libusb_open(device, &m_hidHandle) != 0) continue; if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iSerialNumber, buf, 256) >= 1) deviceInfo.serialNumber = string((char*)buf); if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iManufacturer, buf, 256) >= 1) deviceInfo.manufacturer = string((char*)buf); if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iProduct, buf, 256) >= 1) deviceInfo.product = string((char*)buf); deviceList.push_back(deviceInfo); libusb_close(m_hidHandle); m_hidHandle = NULL; break; } } } } libusb_free_device_list(devs, 1); if (m_hidHandle != NULL) { libusb_close(m_hidHandle); m_hidHandle = NULL; } libusb_exit(m_ctx); m_ctx = NULL; #endif return deviceList; } bool LedKeyboard::isOpen() { return m_isOpen; } bool LedKeyboard::open() { if (m_isOpen) return true; return open(0x0, 0x0, ""); } bool LedKeyboard::open(uint16_t vendorID, uint16_t productID, string serial) { if (m_isOpen && ! close()) return false; currentDevice.model = KeyboardModel::unknown; #if defined(hidapi) if (hid_init() < 0) return false; struct hid_device_info *devs, *dev; devs = hid_enumerate(vendorID, productID); dev = devs; wstring wideSerial; if (!serial.empty()) { wchar_t tempSerial[256]; if (mbstowcs(tempSerial, serial.c_str(), 256) < 1) return false; wideSerial = wstring(tempSerial); } while (dev) { for (int i=0; i<(int)SupportedKeyboards.size(); i++) { if (dev->vendor_id == SupportedKeyboards[i][0] && dev->product_id == SupportedKeyboards[i][1]) { if (!serial.empty() && dev->serial_number != NULL && wideSerial.compare(dev->serial_number) != 0) break; //Serial didn't match if (dev->serial_number != NULL) { char buf[256]; wcstombs(buf,dev->serial_number,256); currentDevice.serialNumber=string(buf); } if (dev->manufacturer_string != NULL) { char buf[256]; wcstombs(buf,dev->manufacturer_string,256); currentDevice.manufacturer = string(buf); } if (dev->product_string != NULL) { char buf[256]; wcstombs(buf,dev->product_string,256); currentDevice.product = string(buf); } currentDevice.vendorID = dev->vendor_id; currentDevice.productID = dev->product_id; currentDevice.model = (KeyboardModel)SupportedKeyboards[i][2]; break; } } if (currentDevice.model != KeyboardModel::unknown) break; dev = dev->next; } hid_free_enumeration(devs); if (! dev) { currentDevice.model = KeyboardModel::unknown; hid_exit(); return false; } if (wideSerial.empty()) m_hidHandle = hid_open(currentDevice.vendorID, currentDevice.productID, NULL); else m_hidHandle = hid_open(currentDevice.vendorID, currentDevice.productID, wideSerial.c_str()); if(m_hidHandle == 0) { hid_exit(); return false; } m_isOpen = true; return true; #elif defined(libusb) if (libusb_init(&m_ctx) < 0) return false; libusb_device **devs; libusb_device *dev = NULL; ssize_t cnt = libusb_get_device_list(m_ctx, &devs); if(cnt >= 0) { for(ssize_t i = 0; i < cnt; i++) { libusb_device *device = devs[i]; libusb_device_descriptor desc; libusb_get_device_descriptor(device, &desc); if (vendorID != 0x0 && desc.idVendor != vendorID) continue; else if (productID != 0x0 && desc.idProduct != productID) continue; else if (! serial.empty()) { if (desc.iSerialNumber <= 0) continue; //Device does not populate serial number unsigned char buf[256]; if (libusb_open(device, &m_hidHandle) != 0){ m_hidHandle = NULL; continue; } if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iSerialNumber, buf, 256) >= 1 && serial.compare((char*)buf) == 0) { //Make sure entry is a supported keyboard and get model for (int i=0; i<(int)SupportedKeyboards.size(); i++) { if (desc.idVendor == SupportedKeyboards[i][0]) { if (desc.idProduct == SupportedKeyboards[i][1]) { if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iManufacturer, buf, 256) >= 1) currentDevice.manufacturer = string((char*)buf); if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iProduct, buf, 256) >= 1) currentDevice.product = string((char*)buf); currentDevice.serialNumber = serial; currentDevice.vendorID = desc.idVendor; currentDevice.productID = desc.idProduct; currentDevice.model = (KeyboardModel)SupportedKeyboards[i][2]; dev = device; libusb_close(m_hidHandle); m_hidHandle = NULL; break; } } } } else { libusb_close(m_hidHandle); m_hidHandle = NULL; continue; //Serial number set but doesn't match } } //For the case where serial is not specified, find first supported device for (int i=0; i<(int)SupportedKeyboards.size(); i++) { if (desc.idVendor == SupportedKeyboards[i][0]) { if (desc.idProduct == SupportedKeyboards[i][1]) { unsigned char buf[256]; if (libusb_open(device, &m_hidHandle) != 0){ m_hidHandle = NULL; continue; } currentDevice.vendorID = desc.idVendor; currentDevice.productID = desc.idProduct; currentDevice.model = (KeyboardModel)SupportedKeyboards[i][2]; if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iManufacturer, buf, 256) >= 1) currentDevice.manufacturer = string((char*)buf); if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iProduct, buf, 256) >= 1) currentDevice.product = string((char*)buf); if (libusb_get_string_descriptor_ascii(m_hidHandle, desc.iSerialNumber, buf, 256) >= 1) currentDevice.serialNumber = string((char*)buf); libusb_close(m_hidHandle); m_hidHandle=NULL; break; } } } if (currentDevice.model != KeyboardModel::unknown) break; } libusb_free_device_list(devs, 1); } if (currentDevice.model == KeyboardModel::unknown) { libusb_exit(m_ctx); m_ctx = NULL; return false; } if (dev == NULL) m_hidHandle = libusb_open_device_with_vid_pid(m_ctx, currentDevice.vendorID, currentDevice.productID); else libusb_open(dev, &m_hidHandle); if(m_hidHandle == NULL) { libusb_exit(m_ctx); m_ctx = NULL; return false; } if(libusb_kernel_driver_active(m_hidHandle, 1) == 1) { if(libusb_detach_kernel_driver(m_hidHandle, 1) != 0) { libusb_exit(m_ctx); m_ctx = NULL; return false; } m_isKernellDetached = true; } if(libusb_claim_interface(m_hidHandle, 1) < 0) { if(m_isKernellDetached==true) { libusb_attach_kernel_driver(m_hidHandle, 1); m_isKernellDetached = false; } libusb_exit(m_ctx); m_ctx = NULL; return false; } m_isOpen = true; return true; #endif return false; //In case neither is defined } LedKeyboard::DeviceInfo LedKeyboard::getCurrentDevice() { return currentDevice; } bool LedKeyboard::close() { if (! m_isOpen) return true; m_isOpen = false; #if defined(hidapi) hid_close(m_hidHandle); m_hidHandle = NULL; hid_exit(); return true; #elif defined(libusb) if (m_hidHandle == NULL) return true; if(libusb_release_interface(m_hidHandle, 1) != 0) return false; if(m_isKernellDetached==true) { libusb_attach_kernel_driver(m_hidHandle, 1); m_isKernellDetached = false; } libusb_close(m_hidHandle); m_hidHandle = NULL; libusb_exit(m_ctx); m_ctx = NULL; return true; #endif return false; } LedKeyboard::KeyboardModel LedKeyboard::getKeyboardModel() { return currentDevice.model; } bool LedKeyboard::commit() { byte_buffer_t data; switch (currentDevice.model) { case KeyboardModel::g213: case KeyboardModel::g413: return true; // Keyboard is non-transactional case KeyboardModel::g410: case KeyboardModel::g513: case KeyboardModel::g610: case KeyboardModel::g810: case KeyboardModel::gpro: data = { 0x11, 0xff, 0x0c, 0x5a }; break; case KeyboardModel::g910: data = { 0x11, 0xff, 0x0f, 0x5d }; break; default: return false; } data.resize(20, 0x00); return sendDataInternal(data); } bool LedKeyboard::setKey(LedKeyboard::KeyValue keyValue) { return setKeys(KeyValueArray {keyValue}); } bool LedKeyboard::setKeys(KeyValueArray keyValues) { if (keyValues.empty()) return false; bool retval = true; vector> SortedKeys = { {}, // Logo AddressGroup {}, // Indicators AddressGroup {}, // Multimedia AddressGroup {}, // GKeys AddressGroup {} // Keys AddressGroup }; for (uint8_t i = 0; i < keyValues.size(); i++) { switch(static_cast(static_cast(keyValues[i].key) >> 8 )) { case LedKeyboard::KeyAddressGroup::logo: switch (currentDevice.model) { case LedKeyboard::KeyboardModel::g610: case LedKeyboard::KeyboardModel::g810: case LedKeyboard::KeyboardModel::gpro: if (SortedKeys[0].size() <= 1 && keyValues[i].key == LedKeyboard::Key::logo) SortedKeys[0].push_back(keyValues[i]); break; case LedKeyboard::KeyboardModel::g910: if (SortedKeys[0].size() <= 2) SortedKeys[0].push_back(keyValues[i]); break; default: break; } break; case LedKeyboard::KeyAddressGroup::indicators: if (SortedKeys[1].size() <= 5) SortedKeys[1].push_back(keyValues[i]); break; case LedKeyboard::KeyAddressGroup::multimedia: switch (currentDevice.model) { case LedKeyboard::KeyboardModel::g610: case LedKeyboard::KeyboardModel::g810: case LedKeyboard::KeyboardModel::gpro: if (SortedKeys[2].size() <= 5) SortedKeys[2].push_back(keyValues[i]); break; default: break; } break; case LedKeyboard::KeyAddressGroup::gkeys: switch (currentDevice.model) { case LedKeyboard::KeyboardModel::g910: if (SortedKeys[3].size() <= 9) SortedKeys[3].push_back(keyValues[i]); break; default: break; } break; case LedKeyboard::KeyAddressGroup::keys: switch (currentDevice.model) { case LedKeyboard::KeyboardModel::g513: case LedKeyboard::KeyboardModel::g610: case LedKeyboard::KeyboardModel::g810: case LedKeyboard::KeyboardModel::g910: case LedKeyboard::KeyboardModel::gpro: if (SortedKeys[4].size() <= 120) SortedKeys[4].push_back(keyValues[i]); break; case LedKeyboard::KeyboardModel::g410: if (SortedKeys[4].size() <= 120) if (keyValues[i].key < LedKeyboard::Key::num_lock || keyValues[i].key > LedKeyboard::Key::num_dot) SortedKeys[4].push_back(keyValues[i]); break; default: break; } break; } } for (uint8_t kag = 0; kag < 5; kag++) { if (SortedKeys[kag].size() > 0) { uint8_t gi = 0; while (gi < SortedKeys[kag].size()) { size_t data_size = 0; byte_buffer_t data = {}; switch (kag) { case 0: data_size = 20; data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::logo); break; case 1: data_size = 64; data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::indicators); break; case 2: data_size = 64; data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::multimedia); break; case 3: data_size = 64; data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::gkeys); break; case 4: data_size = 64; data = getKeyGroupAddress(LedKeyboard::KeyAddressGroup::keys); break; } const uint8_t maxKeyCount = (data_size - 8) / 4; if (data.size() > 0) { for (uint8_t i = 0; i < maxKeyCount; i++) { if (gi + i < SortedKeys[kag].size()) { data.push_back(static_cast( static_cast(SortedKeys[kag][gi+i].key) & 0x00ff)); data.push_back(SortedKeys[kag][gi+i].color.red); data.push_back(SortedKeys[kag][gi+i].color.green); data.push_back(SortedKeys[kag][gi+i].color.blue); } } data.resize(data_size, 0x00); if (retval) retval = sendDataInternal(data); else sendDataInternal(data); } gi = gi + maxKeyCount; } } } return retval; } bool LedKeyboard::setGroupKeys(KeyGroup keyGroup, LedKeyboard::Color color) { KeyValueArray keyValues; KeyArray keyArray; switch (keyGroup) { case KeyGroup::logo: keyArray = keyGroupLogo; break; case KeyGroup::indicators: keyArray = keyGroupIndicators; break; case KeyGroup::gkeys: keyArray = keyGroupGKeys; break; case KeyGroup::multimedia: keyArray = keyGroupMultimedia; break; case KeyGroup::fkeys: keyArray = keyGroupFKeys; break; case KeyGroup::modifiers: keyArray = keyGroupModifiers; break; case KeyGroup::arrows: keyArray = keyGroupArrows; break; case KeyGroup::numeric: keyArray = keyGroupNumeric; break; case KeyGroup::functions: keyArray = keyGroupFunctions; break; case KeyGroup::keys: keyArray = keyGroupKeys; break; default: break; } for (uint8_t i = 0; i < keyArray.size(); i++) keyValues.push_back({keyArray[i], color}); return setKeys(keyValues); } bool LedKeyboard::setAllKeys(LedKeyboard::Color color) { KeyValueArray keyValues; switch (currentDevice.model) { case KeyboardModel::g213: for (uint8_t rIndex=0x01; rIndex <= 0x05; rIndex++) if (! setRegion(rIndex, color)) return false; return true; case KeyboardModel::g413: setNativeEffect(NativeEffect::color, NativeEffectPart::keys, std::chrono::seconds(0), color, NativeEffectStorage::none); return true; case KeyboardModel::g410: case KeyboardModel::g513: case KeyboardModel::g610: case KeyboardModel::g810: case KeyboardModel::g910: case KeyboardModel::gpro: for (uint8_t i = 0; i < keyGroupLogo.size(); i++) keyValues.push_back({keyGroupLogo[i], color}); for (uint8_t i = 0; i < keyGroupIndicators.size(); i++) keyValues.push_back({keyGroupIndicators[i], color}); for (uint8_t i = 0; i < keyGroupMultimedia.size(); i++) keyValues.push_back({keyGroupMultimedia[i], color}); for (uint8_t i = 0; i < keyGroupGKeys.size(); i++) keyValues.push_back({keyGroupGKeys[i], color}); for (uint8_t i = 0; i < keyGroupFKeys.size(); i++) keyValues.push_back({keyGroupFKeys[i], color}); for (uint8_t i = 0; i < keyGroupFunctions.size(); i++) keyValues.push_back({keyGroupFunctions[i], color}); for (uint8_t i = 0; i < keyGroupArrows.size(); i++) keyValues.push_back({keyGroupArrows[i], color}); for (uint8_t i = 0; i < keyGroupNumeric.size(); i++) keyValues.push_back({keyGroupNumeric[i], color}); for (uint8_t i = 0; i < keyGroupModifiers.size(); i++) keyValues.push_back({keyGroupModifiers[i], color}); for (uint8_t i = 0; i < keyGroupKeys.size(); i++) keyValues.push_back({keyGroupKeys[i], color}); return setKeys(keyValues); default: return false; } return false; } bool LedKeyboard::setMRKey(uint8_t value) { LedKeyboard::byte_buffer_t data; switch (currentDevice.model) { case KeyboardModel::g910: switch (value) { case 0x00: case 0x01: data = { 0x11, 0xff, 0x0a, 0x0e, value }; data.resize(20, 0x00); return sendDataInternal(data); default: break; } break; default: break; } return false; } bool LedKeyboard::setMNKey(uint8_t value) { LedKeyboard::byte_buffer_t data; switch (currentDevice.model) { case KeyboardModel::g910: switch (value) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: data = { 0x11, 0xff, 0x09, 0x1e, value }; data.resize(20, 0x00); return sendDataInternal(data); default: break; } break; default: break; } return false; } bool LedKeyboard::setGKeysMode(uint8_t value) { LedKeyboard::byte_buffer_t data; switch (currentDevice.model) { case KeyboardModel::g910: switch (value) { case 0x00: case 0x01: data = { 0x11, 0xff, 0x08, 0x2e, value }; data.resize(20, 0x00); return sendDataInternal(data); default: break; } break; default: break; } return false; } bool LedKeyboard::setRegion(uint8_t region, LedKeyboard::Color color) { LedKeyboard::byte_buffer_t data; switch (currentDevice.model) { case KeyboardModel::g213: data = { 0x11, 0xff, 0x0c, 0x3a, region, 0x01, color.red, color.green, color.blue }; data.resize(20,0x00); return sendDataInternal(data); break; default: break; } return false; } bool LedKeyboard::setStartupMode(StartupMode startupMode) { byte_buffer_t data; switch (currentDevice.model) { case KeyboardModel::g213: case KeyboardModel::g410: case KeyboardModel::g610: case KeyboardModel::g810: case KeyboardModel::gpro: data = { 0x11, 0xff, 0x0d, 0x5a, 0x00, 0x01 }; break; case KeyboardModel::g910: data = { 0x11, 0xff, 0x10, 0x5e, 0x00, 0x01 }; break; default: return false; } data.push_back((unsigned char)startupMode); data.resize(20, 0x00); return sendDataInternal(data); } bool LedKeyboard::setNativeEffect(NativeEffect effect, NativeEffectPart part, std::chrono::duration period, Color color, NativeEffectStorage storage) { uint8_t protocolByte = 0; NativeEffectGroup effectGroup = static_cast(static_cast(effect) >> 8); // NativeEffectPart::all is not in the device protocol, but an alias for both keys and logo, plus indicators if (part == LedKeyboard::NativeEffectPart::all) { switch (effectGroup) { case NativeEffectGroup::color: if (! setGroupKeys(LedKeyboard::KeyGroup::indicators, color)) return false; if (! commit()) return false; break; case NativeEffectGroup::breathing: if (! setGroupKeys(LedKeyboard::KeyGroup::indicators, color)) return false;; if (! commit()) return false;; break; case NativeEffectGroup::cycle: case NativeEffectGroup::waves: if (! setGroupKeys( LedKeyboard::KeyGroup::indicators, LedKeyboard::Color({0xff, 0xff, 0xff})) ) return false; if (! commit()) return false; break; } return ( setNativeEffect(effect, LedKeyboard::NativeEffectPart::keys, period, color, storage) && setNativeEffect(effect, LedKeyboard::NativeEffectPart::logo, period, color, storage)); } switch (currentDevice.model) { case KeyboardModel::g213: case KeyboardModel::g413: protocolByte = 0x0c; if (part == NativeEffectPart::logo) return true; //Does not have logo component break; case KeyboardModel::g410: case KeyboardModel::g513: case KeyboardModel::g610: // Unconfirmed case KeyboardModel::g810: case KeyboardModel::gpro: protocolByte = 0x0d; break; case KeyboardModel::g910: protocolByte = 0x10; break; default: return false; } if ((effectGroup == NativeEffectGroup::waves) && (part == NativeEffectPart::logo)) { return setNativeEffect(NativeEffect::color, part, std::chrono::seconds(0), Color({0x00, 0xff, 0xff}), storage); } byte_buffer_t data = { 0x11, 0xff, protocolByte, 0x3c, (uint8_t)part, static_cast(effectGroup), // color of static-color and breathing effects color.red, color.green, color.blue, // period of breathing effect (ms) static_cast(period.count() >> 8), static_cast(period.count() & 0xff), // period of cycle effect (ms) static_cast(period.count() >> 8), static_cast(period.count() & 0xff), static_cast(static_cast(effect) & 0xff), // wave variation (e.g. horizontal) 0x64, // unused? // period of wave effect (ms) static_cast(period.count() >> 8), // LSB is shared with cycle effect above static_cast(storage), 0, // unused? 0, // unused? 0, // unused? }; return sendDataInternal(data); } bool LedKeyboard::sendDataInternal(byte_buffer_t &data) { if (data.size() > 0) { #if defined(hidapi) if (! open(currentDevice.vendorID, currentDevice.productID, currentDevice.serialNumber)) return false; data.insert(data.begin(), 0x00); if (hid_write(m_hidHandle, const_cast(data.data()), data.size()) < 0) { std::cout<<"Error: Can not write to hidraw, try with the libusb version"<(data2.data()), data2.size(), 1); */ return true; #elif defined(libusb) if (! m_isOpen) return false; if (data.size() > 20) { if(libusb_control_transfer(m_hidHandle, 0x21, 0x09, 0x0212, 1, const_cast(data.data()), data.size(), 2000) < 0) return false; } else { if(libusb_control_transfer(m_hidHandle, 0x21, 0x09, 0x0211, 1, const_cast(data.data()), data.size(), 2000) < 0) return false; } usleep(1000); unsigned char buffer[64]; int len = 0; libusb_interrupt_transfer(m_hidHandle, 0x82, buffer, sizeof(buffer), &len, 1); return true; #endif } return false; } LedKeyboard::byte_buffer_t LedKeyboard::getKeyGroupAddress(LedKeyboard::KeyAddressGroup keyAddressGroup) { switch (currentDevice.model) { case KeyboardModel::g213: case KeyboardModel::g413: return {}; // Device doesn't support per-key setting case KeyboardModel::g410: case KeyboardModel::g513: case KeyboardModel::gpro: switch (keyAddressGroup) { case LedKeyboard::KeyAddressGroup::logo: return { 0x11, 0xff, 0x0c, 0x3a, 0x00, 0x10, 0x00, 0x01 }; case LedKeyboard::KeyAddressGroup::indicators: return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x40, 0x00, 0x05 }; case LedKeyboard::KeyAddressGroup::gkeys: return {}; case LedKeyboard::KeyAddressGroup::multimedia: return {}; case LedKeyboard::KeyAddressGroup::keys: return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x01, 0x00, 0x0e }; } break; case KeyboardModel::g610: case KeyboardModel::g810: switch (keyAddressGroup) { case LedKeyboard::KeyAddressGroup::logo: return { 0x11, 0xff, 0x0c, 0x3a, 0x00, 0x10, 0x00, 0x01 }; case LedKeyboard::KeyAddressGroup::indicators: return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x40, 0x00, 0x05 }; case LedKeyboard::KeyAddressGroup::gkeys: return {}; case LedKeyboard::KeyAddressGroup::multimedia: return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x02, 0x00, 0x05 }; case LedKeyboard::KeyAddressGroup::keys: return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x01, 0x00, 0x0e }; } break; case KeyboardModel::g910: switch (keyAddressGroup) { case LedKeyboard::KeyAddressGroup::logo: return { 0x11, 0xff, 0x0f, 0x3a, 0x00, 0x10, 0x00, 0x02 }; case LedKeyboard::KeyAddressGroup::indicators: return { 0x12, 0xff, 0x0c, 0x3a, 0x00, 0x40, 0x00, 0x05 }; case LedKeyboard::KeyAddressGroup::gkeys: return { 0x12, 0xff, 0x0f, 0x3e, 0x00, 0x04, 0x00, 0x09 }; case LedKeyboard::KeyAddressGroup::multimedia: return {}; case LedKeyboard::KeyAddressGroup::keys: return { 0x12, 0xff, 0x0f, 0x3d, 0x00, 0x01, 0x00, 0x0e }; } break; default: break; } return {}; }