diff --git a/src/HID-APIs/ImprovedKeylayouts.h b/src/HID-APIs/ImprovedKeylayouts.h index 1f0eb8a..6c6f3e5 100644 --- a/src/HID-APIs/ImprovedKeylayouts.h +++ b/src/HID-APIs/ImprovedKeylayouts.h @@ -29,19 +29,6 @@ THE SOFTWARE. #endif // Hut1_12v2.pdf -enum KeyboardModifier : uint8_t { - KEY_LEFT_CTRL = (1 << 0), - KEY_LEFT_SHIFT = (1 << 1), - KEY_LEFT_ALT = (1 << 2), - KEY_LEFT_GUI = (1 << 3), - KEY_LEFT_WINDOWS = (1 << 3), // Alias - KEY_RIGHT_CTRL = (1 << 4), - KEY_RIGHT_SHIFT = (1 << 5), - KEY_RIGHT_ALT = (1 << 6), - KEY_RIGHT_GUI = (1 << 7), - KEY_RIGHT_WINDOWS = (1 << 7), // Alias -}; - enum KeyboardKeycode : uint8_t { KEY_RESERVED = 0, KEY_ERROR_ROLLOVER = 1, @@ -267,15 +254,16 @@ enum KeyboardKeycode : uint8_t { KEYPAD_DECIMAL = 0xDC, // Disabled (Ubuntu) KEYPAD_HEXADECIMAL = 0xDD, // Disabled (Ubuntu) - // Used in KeyboardModifier enum directly - //KEY_LEFT_CTRL = 0xE0, - //KEY_LEFT_SHIFT = 0xE1, - //KEY_LEFT_ALT = 0xE2, - //KEY_LEFT_GUI = 0xE3, - //KEY_RIGHT_CTRL = 0xE4, - //KEY_RIGHT_SHIFT = 0xE5, - //KEY_RIGHT_ALT = 0xE6, - //KEY_RIGHT_GUI = 0xE7, + KEY_LEFT_CTRL = 0xE0, + KEY_LEFT_SHIFT = 0xE1, + KEY_LEFT_ALT = 0xE2, + KEY_LEFT_GUI = 0xE3, + KEY_LEFT_WINDOWS = 0xE3, // Alias + KEY_RIGHT_CTRL = 0xE4, + KEY_RIGHT_SHIFT = 0xE5, + KEY_RIGHT_ALT = 0xE6, + KEY_RIGHT_GUI = 0xE7, + KEY_RIGHT_WINDOWS = 0xE7, // Alias // Keyboard HID mappings diff --git a/src/HID-APIs/KeyboardAPI.h b/src/HID-APIs/KeyboardAPI.h index 1a96dde..7689a86 100644 --- a/src/HID-APIs/KeyboardAPI.h +++ b/src/HID-APIs/KeyboardAPI.h @@ -37,52 +37,76 @@ typedef union{ struct{ uint8_t modifiers; uint8_t reserved; - KeyboardKeycode keys[6]; + KeyboardKeycode keycodes[6]; }; + uint8_t keys[8]; } HID_KeyboardReport_Data_t; + class KeyboardAPI : public Print { public: inline void begin(void); inline void end(void); - inline size_t write(uint8_t k); + // Raw Keycode API functions inline size_t write(KeyboardKeycode k); - inline size_t write(KeyboardModifier k); - inline size_t write(ConsumerKeycode k); - - inline size_t press(uint8_t k); inline size_t press(KeyboardKeycode k); - inline size_t press(KeyboardModifier k); - inline size_t press(ConsumerKeycode k); - - inline size_t release(uint8_t k); inline size_t release(KeyboardKeycode k); - inline size_t release(KeyboardModifier k); - inline size_t release(ConsumerKeycode k); - - inline size_t add(uint8_t k); - inline size_t add(KeyboardKeycode k); - inline size_t add(KeyboardModifier k); - inline size_t add(ConsumerKeycode k); - - inline size_t remove(uint8_t k); inline size_t remove(KeyboardKeycode k); - inline size_t remove(KeyboardModifier k); - inline size_t remove(ConsumerKeycode k); - + inline size_t add(KeyboardKeycode k); inline size_t releaseAll(void); - inline size_t removeAll(void); - inline int send(void); - inline void wakeupHost(void); - - // Sending is public in the base class for advanced users. - virtual int SendReport(void* data, int length) = 0; + //press(uint8_t key, uint8_t modifier) TODO variadic template + // Print API functions + inline virtual size_t write(uint8_t k) override; + inline size_t press(uint8_t k); + inline size_t release(uint8_t k); + inline size_t add(uint8_t k); + inline size_t remove(uint8_t k); + + // Needs to be implemented in a lower level + virtual size_t removeAll(void) = 0; + virtual int send(void) = 0; + +private: + virtual size_t set(KeyboardKeycode k, bool s) = 0; + inline size_t set(uint8_t k, bool s); +}; + +class DefaultKeyboardAPI : public KeyboardAPI +{ +public: + // Implement adding/removing key functions + inline virtual size_t removeAll(void) override; + + // Add special consumer key API for the reserved byte + inline size_t write(ConsumerKeycode k); + inline size_t press(ConsumerKeycode k); + inline size_t remove(ConsumerKeycode k); + inline size_t add(ConsumerKeycode k); + inline size_t release(ConsumerKeycode k); + + // Also use the base class functions + // http://en.cppreference.com/w/cpp/language/using_declaration + using KeyboardAPI::write; + using KeyboardAPI::press; + using KeyboardAPI::remove; + using KeyboardAPI::add; + using KeyboardAPI::release; + + // Needs to be implemented in a lower level + virtual int send(void) = 0; + protected: HID_KeyboardReport_Data_t _keyReport; + +private: + inline virtual size_t set(KeyboardKeycode k, bool s) override; }; +//TODO NKRO API + + // Implementation is inline #include "KeyboardAPI.hpp" diff --git a/src/HID-APIs/KeyboardAPI.hpp b/src/HID-APIs/KeyboardAPI.hpp index 65e75ca..c363c46 100644 --- a/src/HID-APIs/KeyboardAPI.hpp +++ b/src/HID-APIs/KeyboardAPI.hpp @@ -24,9 +24,14 @@ THE SOFTWARE. // Include guard #pragma once + void KeyboardAPI::begin(void) { - releaseAll(); + // Force API to send a clean report. + // This is important for and HID bridge where the receiver stays on, + // while the sender is resetted. + removeAll(); + send(); } @@ -36,17 +41,6 @@ void KeyboardAPI::end(void) } -size_t KeyboardAPI::write(uint8_t k) -{ - // Press and release key (if press was successfull) - auto ret = press(k); - if(ret){ - release(k); - } - return ret; -} - - size_t KeyboardAPI::write(KeyboardKeycode k) { // Press and release key (if press was successfull) @@ -58,19 +52,55 @@ size_t KeyboardAPI::write(KeyboardKeycode k) } -size_t KeyboardAPI::write(KeyboardModifier k) -{ - // Press and release key (if press was successfull) - auto ret = press(k); +size_t KeyboardAPI::press(KeyboardKeycode k) +{ + // Press key and send report to host + auto ret = add(k); if(ret){ - release(k); + send(); } return ret; } -size_t KeyboardAPI::write(ConsumerKeycode k) +size_t KeyboardAPI::release(KeyboardKeycode k) { + // Release key and send report to host + auto ret = remove(k); + if(ret){ + send(); + } + return ret; +} + + +size_t KeyboardAPI::add(KeyboardKeycode k) +{ + // Add key to report + return set(k, true); +} + + +size_t KeyboardAPI::remove(KeyboardKeycode k) +{ + // Remove key from report + return set(k, false); +} + + +size_t KeyboardAPI::releaseAll(void) +{ + // Release all keys + auto ret = removeAll(); + if(ret){ + send(); + } + return ret; +} + + +size_t KeyboardAPI::write(uint8_t k) +{ // Press and release key (if press was successfull) auto ret = press(k); if(ret){ @@ -91,32 +121,10 @@ size_t KeyboardAPI::press(uint8_t k) } -size_t KeyboardAPI::press(KeyboardKeycode k) +size_t KeyboardAPI::release(uint8_t k) { - // Press key and send report to host - auto ret = add(k); - if(ret){ - send(); - } - return ret; -} - - -size_t KeyboardAPI::press(KeyboardModifier k) -{ - // Press modifier key and send report to host - auto ret = add(k); - if(ret){ - send(); - } - return ret; -} - - -size_t KeyboardAPI::press(ConsumerKeycode k) -{ - // Press key and send report to host - auto ret = add(k); + // Release key and send report to host + auto ret = remove(k); if(ret){ send(); } @@ -126,6 +134,19 @@ size_t KeyboardAPI::press(ConsumerKeycode k) size_t KeyboardAPI::add(uint8_t k) { + // Add key to report + return set(k, true); +} + + +size_t KeyboardAPI::remove(uint8_t k) +{ + // Remove key from report + return set(k, false); +} + + +size_t KeyboardAPI::set(uint8_t k, bool s){ // Ignore invalid input if(k >= sizeof(_asciimap)){ setWriteError(); @@ -134,45 +155,108 @@ size_t KeyboardAPI::add(uint8_t k) // Read key from ascii lookup table k = pgm_read_byte(_asciimap + k); - auto ret = add(KeyboardKeycode(k & ~SHIFT)); + auto ret = set(KeyboardKeycode(k & ~SHIFT), s); - // Only press shift and send if keycode was successfully added - if(ret && k & SHIFT){ - add(KEY_LEFT_SHIFT); + // Only add shift if keycode was successfully added before. + // Always try to release shift (if used). + if((k & SHIFT) && (ret || !s)){ + ret |= set(KEY_LEFT_SHIFT, s); } return ret; } -size_t KeyboardAPI::add(KeyboardKeycode k) +size_t DefaultKeyboardAPI::set(KeyboardKeycode k, bool s) { - // Add k to the key report only if it's not already present - // and if there is an empty slot. - for (uint8_t i = 0; i < sizeof(_keyReport.keys); i++) + // It's a modifier key + if(k >= KEY_LEFT_CTRL && k <= KEY_RIGHT_GUI) { - // Is key already in the list or did we found an empty slot? - auto key = _keyReport.keys[i]; - if (key == uint8_t(k) || key == KEY_RESERVED) { - _keyReport.keys[i] = k; - return 1; + // Convert key into bitfield (0 - 7) + k = KeyboardKeycode(uint8_t(k) - uint8_t(KEY_LEFT_CTRL)); + if(s){ + _keyReport.modifiers = (1 << k); + } + else{ + _keyReport.modifiers &= ~(1 << k); + } + return 1; + } + // Its a normal key + else{ + // Add k to the key report only if it's not already present + // and if there is an empty slot. Remove the first available key. + for (uint8_t i = 0; i < sizeof(_keyReport.keycodes); i++) + { + auto key = _keyReport.keycodes[i]; + + // Is key already in the list or did we found an empty slot? + if (s && (key == uint8_t(k) || key == KEY_RESERVED)) { + _keyReport.keycodes[i] = k; + return 1; + } + + // Test the key report to see if k is present. Clear it if it exists. + if (!s && (key == k)) { + _keyReport.keycodes[i] = KEY_RESERVED; + return 1; + } } } - // No empty key position was found - setWriteError(); + // No empty/pressed key was found return 0; } - -size_t KeyboardAPI::add(KeyboardModifier k) +size_t DefaultKeyboardAPI::removeAll(void) { - // Add modifier key - _keyReport.modifiers |= k; - return 1; + // Release all keys + uint8_t ret = 0; + for (uint8_t i = 0; i < sizeof(_keyReport.keys); i++) + { + // Is a key in the list or did we found an empty slot? + if(_keyReport.keys[i]){ + ret++; + } + _keyReport.keys[i] = 0x00; + } + return ret; } -size_t KeyboardAPI::add(ConsumerKeycode k) +size_t DefaultKeyboardAPI::write(ConsumerKeycode k) +{ + // Press and release key (if press was successfull) + auto ret = press(k); + if(ret){ + release(k); + } + return ret; +} + + +size_t DefaultKeyboardAPI::press(ConsumerKeycode k) +{ + // Press key and send report to host + auto ret = add(k); + if(ret){ + send(); + } + return ret; +} + + +size_t DefaultKeyboardAPI::release(ConsumerKeycode k) +{ + // Release key and send report to host + auto ret = remove(k); + if(ret){ + send(); + } + return ret; +} + + +size_t DefaultKeyboardAPI::add(ConsumerKeycode k) { // No 2 byte keys are supported if(k > 0xFF){ @@ -187,99 +271,7 @@ size_t KeyboardAPI::add(ConsumerKeycode k) } -size_t KeyboardAPI::release(uint8_t k) -{ - // Release key and send report to host - auto ret = remove(k); - if(ret){ - send(); - } - return ret; -} - - -size_t KeyboardAPI::release(KeyboardKeycode k) -{ - // Release key and send report to host - auto ret = remove(k); - if(ret){ - send(); - } - return ret; -} - - -size_t KeyboardAPI::release(KeyboardModifier k) -{ - // Release modifier key and send report to host - auto ret = remove(k); - if(ret){ - send(); - } - return ret; -} - - -size_t KeyboardAPI::release(ConsumerKeycode k) -{ - // Release key and send report to host - auto ret = remove(k); - if(ret){ - send(); - } - return ret; -} - - -size_t KeyboardAPI::remove(uint8_t k) -{ - // Ignore invalid input - if(k >= sizeof(_asciimap)){ - return 0; - } - - // Read key from ascii lookup table - k = pgm_read_byte(_asciimap + k); - auto ret = remove(KeyboardKeycode(k & ~SHIFT)); - - // Always try to release shift (if used) - if(k & SHIFT){ - ret |= remove(KEY_LEFT_SHIFT); - } - return ret; -} - - -size_t KeyboardAPI::remove(KeyboardKeycode k) -{ - // Test the key report to see if k is present. Clear it if it exists. - for (uint8_t i = 0; i < sizeof(_keyReport.keys); i++) { - if (_keyReport.keys[i] == k) { - _keyReport.keys[i] = KEY_RESERVED; - return 1; - } - } - - // No pressed key was found - return 0; -} - - -size_t KeyboardAPI::remove(KeyboardModifier k) -{ - // Release modifier key - auto oldModifier = _keyReport.modifiers; - _keyReport.modifiers &= ~k; - - // Check if we actually released a key - if(_keyReport.modifiers != oldModifier){ - return 1; - } - return 0; -} - - -size_t KeyboardAPI::remove(ConsumerKeycode k) +size_t DefaultKeyboardAPI::remove(ConsumerKeycode k) { // No 2 byte keys are supported if(k > 0xFF){ @@ -291,46 +283,3 @@ size_t KeyboardAPI::remove(ConsumerKeycode k) _keyReport.reserved = HID_CONSUMER_UNASSIGNED; return 1; } - - -size_t KeyboardAPI::releaseAll(void) -{ - // Release all keys - auto ret = removeAll(); - if(ret){ - send(); - } - return ret; -} - - -size_t KeyboardAPI::removeAll(void) -{ - // Release all keys - uint8_t ret = 0; - for (uint8_t i = 0; i < sizeof(_keyReport.keys); i++) - { - // Is a key in the list or did we found an empty slot? - if(_keyReport.keys[i]){ - ret++; - } - - _keyReport.keys[i] = KEY_RESERVED; - } - return ret; -} - - -int KeyboardAPI::send(void){ - // TODO set write error if usb send fails/disconnected? - return SendReport(&_keyReport, sizeof(_keyReport)); -} - - -void KeyboardAPI::wakeupHost(void){ -#ifdef USBCON - USBDevice.wakeupHost(); -#endif -} - - diff --git a/src/MultiReport/ImprovedKeyboard.cpp b/src/MultiReport/ImprovedKeyboard.cpp index 3ca0ae9..3b42a9e 100644 --- a/src/MultiReport/ImprovedKeyboard.cpp +++ b/src/MultiReport/ImprovedKeyboard.cpp @@ -70,9 +70,13 @@ Keyboard_::Keyboard_(void) HID().AppendDescriptor(&node); } -int Keyboard_::SendReport(void* data, int length) +int Keyboard_::send(void) { - return HID().SendReport(HID_REPORTID_KEYBOARD, data, length); + return HID().SendReport(HID_REPORTID_KEYBOARD, &_keyReport, sizeof(_keyReport)); +} + +void Keyboard_::wakeupHost(void){ + USBDevice.wakeupHost(); } Keyboard_ Keyboard; diff --git a/src/MultiReport/ImprovedKeyboard.h b/src/MultiReport/ImprovedKeyboard.h index 86ff6c9..3dc8f47 100644 --- a/src/MultiReport/ImprovedKeyboard.h +++ b/src/MultiReport/ImprovedKeyboard.h @@ -31,13 +31,14 @@ THE SOFTWARE. #include "../HID-APIs/KeyboardAPI.h" -class Keyboard_ : public KeyboardAPI +class Keyboard_ : public DefaultKeyboardAPI { public: Keyboard_(void); + void wakeupHost(void); protected: - virtual inline int SendReport(void* data, int length) override; + virtual inline int send(void) override; }; extern Keyboard_ Keyboard; diff --git a/src/SingleReport/BootKeyboard.cpp b/src/SingleReport/BootKeyboard.cpp index bcc6904..0b4378a 100644 --- a/src/SingleReport/BootKeyboard.cpp +++ b/src/SingleReport/BootKeyboard.cpp @@ -156,10 +156,15 @@ uint8_t BootKeyboard_::getProtocol(void){ return protocol; } -int BootKeyboard_::SendReport(void* data, int length){ - return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, length); +int BootKeyboard_::send(void){ + return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &_keyReport, sizeof(_keyReport)); } +void BootKeyboard_::wakeupHost(void){ + USBDevice.wakeupHost(); +} + + BootKeyboard_ BootKeyboard; diff --git a/src/SingleReport/BootKeyboard.h b/src/SingleReport/BootKeyboard.h index 484b0d1..3c62273 100644 --- a/src/SingleReport/BootKeyboard.h +++ b/src/SingleReport/BootKeyboard.h @@ -31,12 +31,13 @@ THE SOFTWARE. #include "../HID-APIs/KeyboardAPI.h" -class BootKeyboard_ : public PluggableUSBModule, public KeyboardAPI +class BootKeyboard_ : public PluggableUSBModule, public DefaultKeyboardAPI { public: BootKeyboard_(void); uint8_t getLeds(void); uint8_t getProtocol(void); + void wakeupHost(void); protected: // Implementation of the PUSBListNode @@ -50,7 +51,7 @@ protected: uint8_t leds; - virtual int SendReport(void* data, int length) override; + virtual int send(void) override; }; extern BootKeyboard_ BootKeyboard;