diff --git a/src/classes/Keyboard.cpp b/src/classes/Keyboard.cpp index 7dae4fd..e422010 100644 --- a/src/classes/Keyboard.cpp +++ b/src/classes/Keyboard.cpp @@ -5,6 +5,7 @@ #include #if defined(hidapi) + #include #include "hidapi/hidapi.h" #elif defined(libusb) #include "libusb-1.0/libusb.h" @@ -20,38 +21,57 @@ LedKeyboard::~LedKeyboard() { } -bool LedKeyboard::listKeyboards() { +vector LedKeyboard::listKeyboards() { + vector deviceList; + #if defined(hidapi) - if (hid_init() < 0) return false; + if (hid_init() < 0) return deviceList; struct hid_device_info *devs, *dev; devs = hid_enumerate(0x0, 0x0); dev = devs; while (dev) { - for (int i=0; i<(int)SupportedKeyboards.size(); i++) { + for (size_t i=0; ivendor_id == SupportedKeyboards[i][0]) { if (dev->product_id == SupportedKeyboards[i][1]) { - cout<<"0x"<vendor_id \ - <<" 0x"<product_id \ - <<" "<serial_number \ - <<" "<path<<" "; + 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; - cout<serial_number<<" "<path<next; + if (dev != NULL) dev = dev->next; } hid_free_enumeration(devs); - hid_exit(); - return true; #elif defined(libusb) libusb_context *ctx = NULL; - if(libusb_init(&m_ctx) < 0) return false; + if(libusb_init(&m_ctx) < 0) return deviceList; libusb_device **devs; ssize_t cnt = libusb_get_device_list(ctx, &devs); @@ -62,20 +82,37 @@ bool LedKeyboard::listKeyboards() { for (int i=0; i<(int)SupportedKeyboards.size(); i++) { if (desc.idVendor == SupportedKeyboards[i][0]) { if (desc.idProduct == SupportedKeyboards[i][1]) { - cout<<"0x"<= 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); - return true; + m_ctx = NULL; #endif - return false; + return deviceList; } @@ -86,114 +123,204 @@ bool LedKeyboard::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; - - if (m_keyboardModel == KeyboardModel::unknown) { - struct hid_device_info *devs, *dev; - devs = hid_enumerate(0x0, 0x0); - dev = devs; - m_keyboardModel = KeyboardModel::unknown; - while (dev) { - for (int i=0; i<(int)SupportedKeyboards.size(); i++) { - if (dev->vendor_id == SupportedKeyboards[i][0]) { - if (dev->product_id == SupportedKeyboards[i][1]) { - m_vendorID = dev->vendor_id; - m_productID = dev->product_id; - m_keyboardModel = (KeyboardModel)SupportedKeyboards[i][2]; - break; - } + 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]) { + if (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 (m_keyboardModel != KeyboardModel::unknown) break; - dev = dev->next; - } - hid_free_enumeration(devs); - - if (! dev) { - cout<<"Keyboard not found"<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; + if (libusb_init(&m_ctx) < 0) return false; - if (m_keyboardModel == KeyboardModel::unknown) { - libusb_device **devs; - 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); + 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]) { - m_vendorID = desc.idVendor; - m_productID = desc.idProduct; - m_keyboardModel = (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); + 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; } } } - if (m_keyboardModel != KeyboardModel::unknown) break; } - libusb_free_device_list(devs, 1); + 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 (m_keyboardModel == KeyboardModel::unknown) { - cout<<"Keyboard not found"<(static_cast(keyValues[i].key) >> 8 )) { case LedKeyboard::KeyAddressGroup::logo: - switch (m_keyboardModel) { + switch (currentDevice.model) { case LedKeyboard::KeyboardModel::g610: case LedKeyboard::KeyboardModel::g810: if (SortedKeys[0].size() <= 1 && keyValues[i].key == LedKeyboard::Key::logo) @@ -285,7 +412,7 @@ bool LedKeyboard::setKeys(KeyValueArray keyValues) { if (SortedKeys[1].size() <= 5) SortedKeys[1].push_back(keyValues[i]); break; case LedKeyboard::KeyAddressGroup::multimedia: - switch (m_keyboardModel) { + switch (currentDevice.model) { case LedKeyboard::KeyboardModel::g610: case LedKeyboard::KeyboardModel::g810: if (SortedKeys[2].size() <= 5) SortedKeys[2].push_back(keyValues[i]); @@ -295,7 +422,7 @@ bool LedKeyboard::setKeys(KeyValueArray keyValues) { } break; case LedKeyboard::KeyAddressGroup::gkeys: - switch (m_keyboardModel) { + switch (currentDevice.model) { case LedKeyboard::KeyboardModel::g910: if (SortedKeys[3].size() <= 9) SortedKeys[3].push_back(keyValues[i]); break; @@ -304,7 +431,7 @@ bool LedKeyboard::setKeys(KeyValueArray keyValues) { } break; case LedKeyboard::KeyAddressGroup::keys: - switch (m_keyboardModel) { + switch (currentDevice.model) { case LedKeyboard::KeyboardModel::g610: case LedKeyboard::KeyboardModel::g810: case LedKeyboard::KeyboardModel::g910: @@ -433,7 +560,7 @@ bool LedKeyboard::setGroupKeys(KeyGroup keyGroup, LedKeyboard::Color color) { bool LedKeyboard::setAllKeys(LedKeyboard::Color color) { KeyValueArray keyValues; - switch (m_keyboardModel) { + switch (currentDevice.model) { case KeyboardModel::g213: for (uint8_t rIndex=0x01; rIndex <= 0x05; rIndex++) if (! setRegion(rIndex, color)) return false; return true; @@ -461,7 +588,7 @@ bool LedKeyboard::setAllKeys(LedKeyboard::Color color) { bool LedKeyboard::setMRKey(uint8_t value) { LedKeyboard::byte_buffer_t data; - switch (m_keyboardModel) { + switch (currentDevice.model) { case KeyboardModel::g910: switch (value) { case 0x00: @@ -481,7 +608,7 @@ bool LedKeyboard::setMRKey(uint8_t value) { bool LedKeyboard::setMNKey(uint8_t value) { LedKeyboard::byte_buffer_t data; - switch (m_keyboardModel) { + switch (currentDevice.model) { case KeyboardModel::g910: switch (value) { case 0x00: @@ -507,7 +634,7 @@ bool LedKeyboard::setMNKey(uint8_t value) { bool LedKeyboard::setGKeysMode(uint8_t value) { LedKeyboard::byte_buffer_t data; - switch (m_keyboardModel) { + switch (currentDevice.model) { case KeyboardModel::g910: switch (value) { case 0x00: @@ -527,7 +654,7 @@ bool LedKeyboard::setGKeysMode(uint8_t value) { bool LedKeyboard::setRegion(uint8_t region, LedKeyboard::Color color) { LedKeyboard::byte_buffer_t data; - switch (m_keyboardModel) { + switch (currentDevice.model) { case KeyboardModel::g213: data = { 0x11, 0xff, 0x0c, 0x3a, region, 0x01, color.red, color.green, color.blue }; data.resize(20,0x00); @@ -542,7 +669,7 @@ bool LedKeyboard::setRegion(uint8_t region, LedKeyboard::Color color) { bool LedKeyboard::setStartupMode(StartupMode startupMode) { byte_buffer_t data; - switch (m_keyboardModel) { + switch (currentDevice.model) { case KeyboardModel::g213: case KeyboardModel::g410: case KeyboardModel::g610: @@ -564,7 +691,7 @@ bool LedKeyboard::setStartupMode(StartupMode startupMode) { bool LedKeyboard::setNativeEffect(NativeEffect effect, NativeEffectPart part, uint8_t speed, Color color) { uint8_t protocolByte = 0; - switch (m_keyboardModel) { + switch (currentDevice.model) { case KeyboardModel::g213: protocolByte = 0x0c; if (part == NativeEffectPart::logo) return false; //Does not have logo component @@ -686,7 +813,7 @@ bool LedKeyboard::sendDataInternal(byte_buffer_t &data) { } LedKeyboard::byte_buffer_t LedKeyboard::getKeyGroupAddress(LedKeyboard::KeyAddressGroup keyAddressGroup) { - switch (m_keyboardModel) { + switch (currentDevice.model) { case KeyboardModel::g213: return {}; // Device doesn't support per-key setting case KeyboardModel::g410: diff --git a/src/classes/Keyboard.h b/src/classes/Keyboard.h index d99adda..b87698d 100644 --- a/src/classes/Keyboard.h +++ b/src/classes/Keyboard.h @@ -109,7 +109,15 @@ class LedKeyboard { ctrl_right, shift_right, alt_right, win_right }; - + + typedef struct { + uint16_t vendorID = 0x0; + uint16_t productID = 0x0; + std::string manufacturer = ""; + std::string product = ""; + std::string serialNumber = ""; + KeyboardModel model; + } DeviceInfo; struct Color { uint8_t red; @@ -127,10 +135,12 @@ class LedKeyboard { ~LedKeyboard(); - bool listKeyboards(); + std::vector listKeyboards(); bool isOpen(); bool open(); + bool open(uint16_t vendorID, uint16_t productID, std::string serial); + DeviceInfo getCurrentDevice(); bool close(); KeyboardModel getKeyboardModel(); @@ -152,7 +162,6 @@ class LedKeyboard { bool setNativeEffect(NativeEffect effect, NativeEffectPart part, uint8_t speed, Color color); - private: typedef std::vector byte_buffer_t; @@ -191,9 +200,7 @@ class LedKeyboard { }; bool m_isOpen = false; - uint16_t m_vendorID = 0; - uint16_t m_productID = 0; - KeyboardModel m_keyboardModel = KeyboardModel::unknown; + DeviceInfo currentDevice; #if defined(hidapi) hid_device *m_hidHandle; diff --git a/src/helpers/help.cpp b/src/helpers/help.cpp index 8c33944..573b188 100644 --- a/src/helpers/help.cpp +++ b/src/helpers/help.cpp @@ -14,6 +14,8 @@ namespace help { cout<<"--------"< #include #include #include @@ -14,6 +15,27 @@ int commit(LedKeyboard &kbd) { return 1; } +void printDeviceInfo(LedKeyboard::DeviceInfo device) +{ + std::cout<<"Device: "< deviceList = kbd.listKeyboards(); + if (deviceList.empty()) return 1; + + std::vector::iterator iterator; + for (iterator = deviceList.begin(); iterator != deviceList.end(); iterator++) { + LedKeyboard::DeviceInfo device = *iterator; + printDeviceInfo(device); + } + + return 0; +} + int setAllKeys(LedKeyboard &kbd, std::string arg2, bool commit = true) { LedKeyboard::Color color; if (! utils::parseColor(arg2, color)) return 1; @@ -226,47 +248,71 @@ int pipeProfile(LedKeyboard &kbd) { int main(int argc, char **argv) { - if (argc > 1) { - - std::string arg = argv[1]; - - if (arg == "--help" || arg == "-h") help::usage(argv[0]); - else if (arg == "--help-keys") help::keys(argv[0]); - else if (arg == "--help-effects") help::effects(argv[0]); - else if (arg == "--help-samples") help::samples(argv[0]); - - else { - LedKeyboard kbd; - if (arg == "--list-keyboards") kbd.listKeyboards(); - else if (arg == "-c") return commit(kbd); - - else if (argc > 2 && arg == "-a") return setAllKeys(kbd, argv[2]); - else if (argc > 3 && arg == "-g") return setGroupKeys(kbd, argv[2], argv[3]); - else if (argc > 3 && arg == "-k") return setKey(kbd, argv[2], argv[3]); - else if (argc > 2 && arg == "-mr") return setMRKey(kbd, argv[2]); - else if (argc > 2 && arg == "-mn") return setMNKey(kbd, argv[2]); - else if (argc > 2 && arg == "-an") return setAllKeys(kbd, argv[2], false); - else if (argc > 3 && arg == "-gn") return setGroupKeys(kbd, argv[2], argv[3], false); - else if (argc > 3 && arg == "-kn") return setKey(kbd, argv[2], argv[3], false); - else if (argc > 3 && arg == "-r") return setRegion(kbd, argv[2], argv[3]); - - else if (argc > 2 && arg == "-gkm") return setGKeysMode(kbd, argv[2]); - - else if (argc > 2 && arg == "-p") return loadProfile(kbd, argv[2]); - else if (argc > 1 && arg == "-pp") return pipeProfile(kbd); - - else if (argc > 5 && arg == "-fx") return setFX(kbd, argv[2], argv[3], argv[4], argv[5]); - else if (argc > 4 && arg == "-fx") return setFX(kbd, argv[2], argv[3], argv[4]); - - else if (argc > 2 && arg == "--startup-mode") return setStartupMode(kbd, argv[2]); - - else { help::usage(argv[0]); return 1; } - } - - return 0; - + if (argc < 2) { + help::usage(argv[0]); + return 1; } - - help::usage(argv[0]); - return 1; + + LedKeyboard kbd; + std::string serial; + uint16_t vendorID = 0x0; + uint16_t productID = 0x0; + + int argIndex = 1; + while (argIndex < argc) + { + std::string arg = argv[argIndex]; + + // Non-Command arguments + if (argc > (argIndex + 1) && arg == "-ds") { + serial = argv[argIndex + 1]; + argIndex += 2; + continue; + } + else if (argc > (argIndex + 1) && arg == "-dv"){ + if (! utils::parseUInt16(argv[argIndex + 1], vendorID)) return 1; + argIndex += 2; + continue; + } + else if (argc > (argIndex + 1) && arg == "-dp"){ + if (! utils::parseUInt16(argv[argIndex + 1], productID)) return 1; + argIndex += 2; + continue; + } + + //Commands that do not need to initialize a specific device + if (arg == "--help" || arg == "-h") {help::usage(argv[0]); return 0;} + else if (arg == "--list-keyboards") return listKeyboards(kbd); + else if (arg == "--help-keys") {help::keys(argv[0]); return 0;} + else if (arg == "--help-effects") {help::effects(argv[0]); return 0;} + else if (arg == "--help-samples") {help::samples(argv[0]); return 0;} + + //Initialize the device for use + if (!kbd.open(vendorID, productID, serial)) { + std::cout << "Matching or compatible device not found" << std::endl; + return 2; + } + + // Command arguments, these will cause parsing to ignore anything beyond the command and its arguments + if (arg == "-c") return commit(kbd); + else if (arg == "--print-device") {printDeviceInfo(kbd.getCurrentDevice()); return 0;} + else if (argc > (argIndex + 1) && arg == "-a") return setAllKeys(kbd, argv[argIndex + 1]); + else if (argc > (argIndex + 2) && arg == "-g") return setGroupKeys(kbd, argv[argIndex + 1], argv[argIndex + 2]); + else if (argc > (argIndex + 2) && arg == "-k") return setKey(kbd, argv[argIndex + 1], argv[argIndex + 2]); + else if (argc > (argIndex + 1) && arg == "-mr") return setMRKey(kbd, argv[argIndex + 1]); + else if (argc > (argIndex + 1) && arg == "-mn") return setMNKey(kbd, argv[argIndex + 1]); + else if (argc > (argIndex + 1) && arg == "-an") return setAllKeys(kbd, argv[argIndex + 1], false); + else if (argc > (argIndex + 2) && arg == "-gn") return setGroupKeys(kbd, argv[argIndex + 1], argv[argIndex + 2], false); + else if (argc > (argIndex + 2) && arg == "-kn") return setKey(kbd, argv[argIndex + 1], argv[argIndex + 2], false); + else if (argc > (argIndex + 2) && arg == "-r") return setRegion(kbd, argv[argIndex + 1], argv[argIndex + 2]); + else if (argc > (argIndex + 1) && arg == "-gkm") return setGKeysMode(kbd, argv[argIndex + 1]); + else if (argc > (argIndex + 1) && arg == "-p") return loadProfile(kbd, argv[argIndex + 1]); + else if (arg == "-pp") return pipeProfile(kbd); + else if (argc > (argIndex + 4) && arg == "-fx") return setFX(kbd, argv[argIndex + 1], argv[argIndex + 2], argv[argIndex + 3], argv[argIndex + 4]); + else if (argc > (argIndex + 3) && arg == "-fx") return setFX(kbd, argv[argIndex + 1], argv[argIndex + 2], argv[argIndex + 3]); + else if (argc > (argIndex + 1) && arg == "--startup-mode") return setStartupMode(kbd, argv[argIndex + 1]); + else { help::usage(argv[0]); return 1; } + } + + return 0; }