From 4b2a1002e8209c710aaa1bf82d43902adf6cefe9 Mon Sep 17 00:00:00 2001 From: Kevin Pearson Date: Thu, 27 Apr 2017 11:44:35 -0400 Subject: [PATCH 1/4] Add support for opening a specific device Allow filtration and matching of specified Device ID, Product ID, Serial Number Fix an issue in listKeyboards (hidapi) with an out of bounds search when using serial number Fix possible null reference problem in listKeyboards (hidapi) that caused rare segfaults when traversing the device enumeration in increments of two Fix handling of output of listKeyboards (hidapi) where it was incrementing the dev list pointer, then accessing the node to look for device serial number (potential security risk) Fix handling of serial number output of listKeyboards (hidapi) to handle wchar_t instead of outputting the memory address Fix issue in listKeyboards (libusb) failure to finish cleaning up USB contexts, leading to a segfault if calling a separate function after listing keyboards. Fix issue in close (libusb) segfaulting if m_hidHandle was null, so added a check. Modify listKeyboards to provide a vector of DeviceInfo objects that can be used by calling applications instead of outputting to stdout directly. Implement a struct to hold information regarding device information and ability for a library caller to query this information to make decisions about the currently targeted device. Signed-off-by: Kevin Pearson --- src/classes/Keyboard.cpp | 357 ++++++++++++++++++++++++++------------- src/classes/Keyboard.h | 19 ++- 2 files changed, 255 insertions(+), 121 deletions(-) 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; From 53876ac54e6fe3293b4cf0bbb4f037960efb0126 Mon Sep 17 00:00:00 2001 From: Kevin Pearson Date: Thu, 27 Apr 2017 11:56:57 -0400 Subject: [PATCH 2/4] Add utility to convert string to uint16_t Purpose for this is for command argument parsing of vendor and product IDs Signed-off-by: Kevin Pearson --- src/helpers/utils.cpp | 8 ++++++++ src/helpers/utils.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/helpers/utils.cpp b/src/helpers/utils.cpp index 56c793d..0ea5e0d 100644 --- a/src/helpers/utils.cpp +++ b/src/helpers/utils.cpp @@ -216,4 +216,12 @@ namespace utils { return true; } + bool parseUInt16(std::string val, uint16_t &uint16) { + if (val.length() == 1) val = "0" + val; + if (val.length() == 2) val = "0" + val; + if (val.length() == 3) val = "0" + val; + if (val.length() != 4) return false; + uint16 = std::stoul("0x" + val, nullptr, 16); + return true; + } } diff --git a/src/helpers/utils.h b/src/helpers/utils.h index 5b7a52c..92de26b 100644 --- a/src/helpers/utils.h +++ b/src/helpers/utils.h @@ -16,6 +16,7 @@ namespace utils { bool parseColor(std::string val, LedKeyboard::Color &color); bool parseSpeed(std::string val, uint8_t &speed); bool parseUInt8(std::string val, uint8_t &uint8); + bool parseUInt16(std::string val, uint16_t &uint16); } From 114fa9b703097aec752fb2123ce9a68d6c8443ef Mon Sep 17 00:00:00 2001 From: Kevin Pearson Date: Thu, 27 Apr 2017 12:39:40 -0400 Subject: [PATCH 3/4] Augment command arg parsing to set specific device Change argument parsing to segregate options from the command Add -dv -dp and -ds options to allow matching a vendor ID, device ID, and/or device serial number. Modify --list-keyboards to parse the DeviceInfo vector and output information to stdout. Signed-off-by: Kevin Pearson --- src/helpers/help.cpp | 13 ++++- src/main.cpp | 127 +++++++++++++++++++++++++++++-------------- 2 files changed, 95 insertions(+), 45 deletions(-) diff --git a/src/helpers/help.cpp b/src/helpers/help.cpp index c77472f..dfcb740 100644 --- a/src/helpers/help.cpp +++ b/src/helpers/help.cpp @@ -16,6 +16,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,68 @@ 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; + } + + 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 == "--help" || arg == "-h") {help::usage(argv[0]); return 0;} + 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;} + else if (arg == "--list-keyboards") return listKeyboards(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; } From c19d4760cebd5eb31b8006c53df3d8c52c052934 Mon Sep 17 00:00:00 2001 From: Kevin Pearson Date: Sat, 29 Apr 2017 08:54:14 -0400 Subject: [PATCH 4/4] Rearrange argument parsing for help commands Help output does not need to initialize a device, so rearrange the parsing to check for help commands prior to performing any device IO. Signed-off-by: Kevin Pearson --- src/main.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6cb0667..4f7b229 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -280,19 +280,22 @@ int main(int argc, char **argv) { 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 == "--help" || arg == "-h") {help::usage(argv[0]); return 0;} - 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;} - else if (arg == "--list-keyboards") return listKeyboards(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]);