Updated NKRO API to new Keyboard API style
This commit is contained in:
parent
96a8a8a1ad
commit
c78fc923f4
6 changed files with 78 additions and 213 deletions
|
|
@ -24,10 +24,7 @@ THE SOFTWARE.
|
|||
// Include guard
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue