diff --git a/src/HID-APIs/NKROKeyboardAPI.h b/src/HID-APIs/NKROKeyboardAPI.h index c5a9fec..7dafbd7 100644 --- a/src/HID-APIs/NKROKeyboardAPI.h +++ b/src/HID-APIs/NKROKeyboardAPI.h @@ -24,10 +24,7 @@ THE SOFTWARE. // Include guard #pragma once -#include -#include "HID-Settings.h" -#include "ImprovedKeylayouts.h" -#include "HID-Tables.h" //TODO +#include "KeyboardAPI.h" // Max value for USB EP_SIZE 16 // +1 reportID, +1 modifier, +1 custom key @@ -43,34 +40,24 @@ typedef union{ uint8_t keys[NKRO_KEY_COUNT / 8]; uint8_t key; }; + uint8_t allkeys[2 + NKRO_KEY_COUNT / 8]; } HID_NKROKeyboardReport_Data_t; -class NKROKeyboardAPI : public Print +class NKROKeyboardAPI : public KeyboardAPI { public: - inline NKROKeyboardAPI(void); - inline void begin(void); - inline void end(void); - inline size_t write(uint8_t k); - inline size_t press(uint8_t k); - inline size_t release(uint8_t k); - inline void releaseAll(void); - inline void send_now(void); + // Implement adding/removing key functions + inline virtual size_t removeAll(void) override; + + // Needs to be implemented in a lower level + virtual int send(void) = 0; - inline size_t writeKeycode(uint8_t k); - inline size_t pressKeycode(uint8_t k); - inline size_t releaseKeycode(uint8_t k); - inline size_t addKeyToReport(uint8_t k); - inline size_t addKeycodeToReport(uint8_t k); - inline size_t removeKeyFromReport(uint8_t k); - inline size_t removeKeycodeFromReport(uint8_t k); - - // Sending is public in the base class for advanced users. - virtual void SendReport(void* data, int length) = 0; - protected: - HID_NKROKeyboardReport_Data_t _keyReport; + HID_NKROKeyboardReport_Data_t _keyReport; + +private: + inline virtual size_t set(KeyboardKeycode k, bool s) override; }; // Implementation is inline diff --git a/src/HID-APIs/NKROKeyboardAPI.hpp b/src/HID-APIs/NKROKeyboardAPI.hpp index 9d15ed7..fe9e6d6 100644 --- a/src/HID-APIs/NKROKeyboardAPI.hpp +++ b/src/HID-APIs/NKROKeyboardAPI.hpp @@ -24,193 +24,71 @@ THE SOFTWARE. // Include guard #pragma once -NKROKeyboardAPI::NKROKeyboardAPI(void) + +size_t NKROKeyboardAPI::set(KeyboardKeycode k, bool s) { - // Empty + // Press keymap key + if (k < NKRO_KEY_COUNT){ + uint8_t bit = 1 << (uint8_t(k) % 8); + if(s){ + _keyReport.keys[k / 8] |= bit; + } + else{ + _keyReport.keys[k / 8] &= ~bit; + } + return 1; + } + + // It's a modifier key + else if(k >= KEY_LEFT_CTRL && k <= KEY_RIGHT_GUI) + { + // 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 custom key (outside our keymap) + 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. + auto key = _keyReport.key; + + // Is key already in the list or did we found an empty slot? + if (s && (key == uint8_t(k) || key == KEY_RESERVED)) { + _keyReport.key = k; + return 1; + } + + // Test the key report to see if k is present. Clear it if it exists. + if (!s && (key == k)) { + _keyReport.key = KEY_RESERVED; + return 1; + } + } + + // No empty/pressed key was found + return 0; } -void NKROKeyboardAPI::begin(void) +size_t NKROKeyboardAPI::removeAll(void) { - releaseAll(); -} - -void NKROKeyboardAPI::end(void) -{ - releaseAll(); -} - -void NKROKeyboardAPI::send_now(void){ - SendReport(&_keyReport, sizeof(_keyReport)); -} - -// press() adds the specified key (printing, non-printing, or modifier) -// to the persistent key report and sends the report. Because of the way -// USB HID works, the host acts like the key remains pressed until we -// call release(), releaseAll(), or otherwise clear the report and resend. -size_t NKROKeyboardAPI::press(uint8_t k) -{ - size_t ret = addKeyToReport(k); - if(ret){ - send_now(); + // Release all keys + size_t ret = 0; + for (uint8_t i = 0; i < sizeof(_keyReport.allkeys); i++) + { + // Is a key in the list or did we found an empty slot? + //TODO count every bit? + if(_keyReport.allkeys[i]){ + ret++; + } + _keyReport.allkeys[i] = 0x00; } return ret; } -// release() takes the specified key out of the persistent key report and -// sends the report. This tells the OS the key is no longer pressed and that -// it shouldn't be repeated any more. -size_t NKROKeyboardAPI::release(uint8_t k) -{ - // it's a non-printing key (not a modifier) - if (k >= 136) - k = k - 136; - - // it's a modifier key - else if (k >= 128) - k = k - 128; - - // it's a printing key - else { - k = pgm_read_byte(_asciimap + k); - if (!k) - return 0; - - // it's a capital letter or other character reached with shift - if (k & SHIFT) { - // the left shift modifier - _keyReport.modifiers &= ~(0x02); - k = k ^ SHIFT; - } - } - - removeKeycodeFromReport(k); - send_now(); - - return 1; -} - -void NKROKeyboardAPI::releaseAll(void) -{ - // release all keys - memset(&_keyReport, 0x00, sizeof(_keyReport)); - send_now(); -} - -size_t NKROKeyboardAPI::write(uint8_t c) -{ - uint8_t p = press(c); // Keydown - release(c); // Keyup - return p; // just return the result of press() since release() almost always returns 1 -} - - -// pressKeycode() adds the specified key (printing, non-printing, or modifier) -// to the persistent key report and sends the report. Because of the way -// USB HID works, the host acts like the key remains pressed until we -// call releaseKeycode(), releaseAll(), or otherwise clear the report and resend. -size_t NKROKeyboardAPI::pressKeycode(uint8_t k) -{ - if (!addKeycodeToReport(k)) { - return 0; - } - send_now(); -} - -size_t NKROKeyboardAPI::addKeyToReport(uint8_t k) -{ - if (k >= 136) { // it's a non-printing key (not a modifier) - k = k - 136; - } else if (k >= 128) { // it's a modifier key - _keyReport.modifiers |= (1<<(k-128)); - k = 0; //TODO return 1?? - } else { // it's a printing key - k = pgm_read_byte(_asciimap + k); - if (!k) { - setWriteError(); - return 0; - } - if (k & SHIFT) { // it's a capital letter or other character reached with shift - _keyReport.modifiers |= 0x02; // the left shift modifier - k = k ^ SHIFT; - } - } - - return addKeycodeToReport(k); -} - -size_t NKROKeyboardAPI::addKeycodeToReport(uint8_t k) -{ - // keymap key - if (k < NKRO_KEY_COUNT) - _keyReport.keys[k / 8] |= 1 << (k % 8); - - // it's a modifier key - else if ((k >= HID_KEYBOARD_LEFT_CONTROL) && (k <= HID_KEYBOARD_RIGHT_GUI)) - _keyReport.modifiers |= (0x01 << (k - HID_KEYBOARD_LEFT_CONTROL)); - - // custom key - else - _keyReport.key = k; - - return 1; -} - - -// releaseKeycode() takes the specified key out of the persistent key report and -// sends the report. This tells the OS the key is no longer pressed and that -// it shouldn't be repeated any more. -// When send is set to FALSE (= 0) no sendReport() is executed. This comes in -// handy when combining key releases (e.g. SHIFT+A). -size_t NKROKeyboardAPI::releaseKeycode(uint8_t k) -{ - if (!removeKeycodeFromReport(k)) { - return 0; - } - send_now(); -} - -size_t NKROKeyboardAPI::removeKeyFromReport(uint8_t k) -{ - if (k >= 136) { // it's a non-printing key (not a modifier) - k = k - 136; - } else if (k >= 128) { // it's a modifier key - _keyReport.modifiers &= ~(1<<(k-128)); - k = 0; - } else { // it's a printing key - k = pgm_read_byte(_asciimap + k); - if (!k) { - return 0; - } - if (k & SHIFT) { // it's a capital letter or other character reached with shift - _keyReport.modifiers &= ~(0x02); // the left shift modifier - k = k ^ SHIFT; - } - } - - return removeKeycodeFromReport(k); -} - -size_t NKROKeyboardAPI::removeKeycodeFromReport(uint8_t k) -{ - // keymap key - if (k < NKRO_KEY_COUNT) - _keyReport.keys[k / 8] &= ~(1 << (k % 8)); - - // it's a modifier key - else if ((k >= HID_KEYBOARD_LEFT_CONTROL) && (k <= HID_KEYBOARD_RIGHT_GUI)) - _keyReport.modifiers &= ~(0x01 << (k - HID_KEYBOARD_LEFT_CONTROL)); - - // custom key - else - _keyReport.key = 0x00; - - return 1; -} - - -size_t NKROKeyboardAPI::writeKeycode(uint8_t c) -{ - uint8_t p = pressKeycode(c); // Keydown - releaseKeycode(c); // Keyup - return (p); // just return the result of pressKeycode() since release() almost always returns 1 -} diff --git a/src/MultiReport/NKROKeyboard.cpp b/src/MultiReport/NKROKeyboard.cpp index 4accc87..27c2148 100644 --- a/src/MultiReport/NKROKeyboard.cpp +++ b/src/MultiReport/NKROKeyboard.cpp @@ -68,9 +68,9 @@ NKROKeyboard_::NKROKeyboard_(void) HID().AppendDescriptor(&node); } -void NKROKeyboard_::SendReport(void* data, int length) +int NKROKeyboard_::send(void) { - HID().SendReport(HID_REPORTID_NKRO_KEYBOARD, data, length); + return HID().SendReport(HID_REPORTID_NKRO_KEYBOARD, &_keyReport, sizeof(_keyReport)); } NKROKeyboard_ NKROKeyboard; diff --git a/src/MultiReport/NKROKeyboard.h b/src/MultiReport/NKROKeyboard.h index 7b94add..933c127 100644 --- a/src/MultiReport/NKROKeyboard.h +++ b/src/MultiReport/NKROKeyboard.h @@ -37,7 +37,7 @@ public: NKROKeyboard_(void); protected: - virtual inline void SendReport(void* data, int length) override; + virtual inline int send(void) override; }; extern NKROKeyboard_ NKROKeyboard; diff --git a/src/SingleReport/SingleNKROKeyboard.cpp b/src/SingleReport/SingleNKROKeyboard.cpp index c5d5e24..ab7c269 100644 --- a/src/SingleReport/SingleNKROKeyboard.cpp +++ b/src/SingleReport/SingleNKROKeyboard.cpp @@ -151,8 +151,8 @@ uint8_t SingleNKROKeyboard_::getLeds(void){ return leds; } -void SingleNKROKeyboard_::SendReport(void* data, int length){ - USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, length); +int SingleNKROKeyboard_::send(void){ + return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &_keyReport, sizeof(_keyReport)); } SingleNKROKeyboard_ SingleNKROKeyboard; diff --git a/src/SingleReport/SingleNKROKeyboard.h b/src/SingleReport/SingleNKROKeyboard.h index 131eaa3..422a47b 100644 --- a/src/SingleReport/SingleNKROKeyboard.h +++ b/src/SingleReport/SingleNKROKeyboard.h @@ -50,7 +50,7 @@ protected: uint8_t leds; - virtual void SendReport(void* data, int length) override; + virtual inline int send(void) override; }; extern SingleNKROKeyboard_ SingleNKROKeyboard;