Skip to content

Commit 9dc0068

Browse files
NicoHoodobra
authored andcommitted
Added NKRO keyboard
1 parent 3c78257 commit 9dc0068

File tree

10 files changed

+640
-2
lines changed

10 files changed

+640
-2
lines changed

plugins/KeyboardioHID/examples/ImprovedMouse/ImprovedMouse.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Mouse example
66
Press a button to click or move the mouse.
77
8-
You may also use BootMouse to enable a bios compatible mouse.
8+
You may also use BootMouse to enable a bios compatible (single report) mouse.
99
However this is very unusual and not recommended.
1010
Bios mice dont support wheels which can cause problems after a reboot.
1111

plugins/KeyboardioHID/examples/NKROKeyboard/NKROKeyboard.ino

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
NKRO can push 113 keys at the same time,
99
the other Keyboards only 6 keys + 8 modifiers!
1010
11+
You may also use SingleNKROKeyboard to enable a single report NKROKeyboard.
12+
1113
See HID Project documentation for more information.
1214
https://github.com/NicoHood/HID/wiki/Keyboard-API
1315
*/

plugins/KeyboardioHID/keywords.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ Gamepad3 KEYWORD1
7272
Gamepad4 KEYWORD1
7373
TeensyKeyboard KEYWORD1
7474
NKROKeyboard KEYWORD1
75+
SingleNKROKeyboard KEYWORD1
7576
AbsoluteMouse KEYWORD1
7677

7778
#######################################
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
Copyright (c) 2014-2015 NicoHood
3+
See the readme for credit to other people.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.
22+
*/
23+
24+
// Include guard
25+
#pragma once
26+
27+
#include <Arduino.h>
28+
#include "HID-Settings.h"
29+
#include "ImprovedKeylayouts.h"
30+
#include "HID-Tables.h" //TODO
31+
32+
// Max value for USB EP_SIZE 16
33+
// +1 reportID, +1 modifier, +1 custom key
34+
#define NKRO_KEY_COUNT (8*13)
35+
36+
typedef union{
37+
// Modifier + keymap + 1 custom key
38+
uint8_t whole8[];
39+
uint16_t whole16[];
40+
uint32_t whole32[];
41+
struct{
42+
uint8_t modifiers;
43+
uint8_t keys[NKRO_KEY_COUNT / 8];
44+
uint8_t key;
45+
};
46+
} HID_NKROKeyboardReport_Data_t;
47+
48+
49+
class NKROKeyboardAPI : public Print
50+
{
51+
public:
52+
inline NKROKeyboardAPI(void);
53+
inline void begin(void);
54+
inline void end(void);
55+
inline size_t write(uint8_t k);
56+
inline size_t press(uint8_t k);
57+
inline size_t release(uint8_t k);
58+
inline void releaseAll(void);
59+
inline void send_now(void);
60+
61+
inline size_t writeKeycode(uint8_t k);
62+
inline size_t pressKeycode(uint8_t k);
63+
inline size_t releaseKeycode(uint8_t k);
64+
inline size_t addKeyToReport(uint8_t k);
65+
inline size_t addKeycodeToReport(uint8_t k);
66+
inline size_t removeKeyFromReport(uint8_t k);
67+
inline size_t removeKeycodeFromReport(uint8_t k);
68+
69+
// Sending is public in the base class for advanced users.
70+
virtual void SendReport(void* data, int length) = 0;
71+
72+
protected:
73+
HID_NKROKeyboardReport_Data_t _keyReport;
74+
};
75+
76+
// Implementation is inline
77+
#include "NKROKeyboardAPI.hpp"
78+
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/*
2+
Copyright (c) 2015 NicoHood
3+
See the readme for credit to other people.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.
22+
*/
23+
24+
// Include guard
25+
#pragma once
26+
27+
NKROKeyboardAPI::NKROKeyboardAPI(void)
28+
{
29+
// Empty
30+
}
31+
32+
void NKROKeyboardAPI::begin(void)
33+
{
34+
releaseAll();
35+
}
36+
37+
void NKROKeyboardAPI::end(void)
38+
{
39+
releaseAll();
40+
}
41+
42+
void NKROKeyboardAPI::send_now(void){
43+
SendReport(&_keyReport, sizeof(_keyReport));
44+
}
45+
46+
// press() adds the specified key (printing, non-printing, or modifier)
47+
// to the persistent key report and sends the report. Because of the way
48+
// USB HID works, the host acts like the key remains pressed until we
49+
// call release(), releaseAll(), or otherwise clear the report and resend.
50+
size_t NKROKeyboardAPI::press(uint8_t k)
51+
{
52+
size_t ret = addKeyToReport(k);
53+
if(ret){
54+
send_now();
55+
}
56+
return ret;
57+
}
58+
59+
// release() takes the specified key out of the persistent key report and
60+
// sends the report. This tells the OS the key is no longer pressed and that
61+
// it shouldn't be repeated any more.
62+
size_t NKROKeyboardAPI::release(uint8_t k)
63+
{
64+
// it's a non-printing key (not a modifier)
65+
if (k >= 136)
66+
k = k - 136;
67+
68+
// it's a modifier key
69+
else if (k >= 128)
70+
k = k - 128;
71+
72+
// it's a printing key
73+
else {
74+
k = pgm_read_byte(_asciimap + k);
75+
if (!k)
76+
return 0;
77+
78+
// it's a capital letter or other character reached with shift
79+
if (k & SHIFT) {
80+
// the left shift modifier
81+
_keyReport.modifiers &= ~(0x02);
82+
k = k ^ SHIFT;
83+
}
84+
}
85+
86+
removeKeycodeFromReport(k);
87+
send_now();
88+
89+
return 1;
90+
}
91+
92+
void NKROKeyboardAPI::releaseAll(void)
93+
{
94+
// release all keys
95+
memset(&_keyReport, 0x00, sizeof(_keyReport));
96+
send_now();
97+
}
98+
99+
size_t NKROKeyboardAPI::write(uint8_t c)
100+
{
101+
uint8_t p = press(c); // Keydown
102+
release(c); // Keyup
103+
return p; // just return the result of press() since release() almost always returns 1
104+
}
105+
106+
107+
// pressKeycode() adds the specified key (printing, non-printing, or modifier)
108+
// to the persistent key report and sends the report. Because of the way
109+
// USB HID works, the host acts like the key remains pressed until we
110+
// call releaseKeycode(), releaseAll(), or otherwise clear the report and resend.
111+
size_t NKROKeyboardAPI::pressKeycode(uint8_t k)
112+
{
113+
if (!addKeycodeToReport(k)) {
114+
return 0;
115+
}
116+
send_now();
117+
}
118+
119+
size_t NKROKeyboardAPI::addKeyToReport(uint8_t k)
120+
{
121+
if (k >= 136) { // it's a non-printing key (not a modifier)
122+
k = k - 136;
123+
} else if (k >= 128) { // it's a modifier key
124+
_keyReport.modifiers |= (1<<(k-128));
125+
k = 0; //TODO return 1??
126+
} else { // it's a printing key
127+
k = pgm_read_byte(_asciimap + k);
128+
if (!k) {
129+
setWriteError();
130+
return 0;
131+
}
132+
if (k & SHIFT) { // it's a capital letter or other character reached with shift
133+
_keyReport.modifiers |= 0x02; // the left shift modifier
134+
k = k ^ SHIFT;
135+
}
136+
}
137+
138+
return addKeycodeToReport(k);
139+
}
140+
141+
size_t NKROKeyboardAPI::addKeycodeToReport(uint8_t k)
142+
{
143+
// keymap key
144+
if (k < NKRO_KEY_COUNT)
145+
_keyReport.keys[k / 8] |= 1 << (k % 8);
146+
147+
// it's a modifier key
148+
else if ((k >= HID_KEYBOARD_LEFT_CONTROL) && (k <= HID_KEYBOARD_RIGHT_GUI))
149+
_keyReport.modifiers |= (0x01 << (k - HID_KEYBOARD_LEFT_CONTROL));
150+
151+
// custom key
152+
else
153+
_keyReport.key = k;
154+
155+
return 1;
156+
}
157+
158+
159+
// releaseKeycode() takes the specified key out of the persistent key report and
160+
// sends the report. This tells the OS the key is no longer pressed and that
161+
// it shouldn't be repeated any more.
162+
// When send is set to FALSE (= 0) no sendReport() is executed. This comes in
163+
// handy when combining key releases (e.g. SHIFT+A).
164+
size_t NKROKeyboardAPI::releaseKeycode(uint8_t k)
165+
{
166+
if (!removeKeycodeFromReport(k)) {
167+
return 0;
168+
}
169+
send_now();
170+
}
171+
172+
size_t NKROKeyboardAPI::removeKeyFromReport(uint8_t k)
173+
{
174+
if (k >= 136) { // it's a non-printing key (not a modifier)
175+
k = k - 136;
176+
} else if (k >= 128) { // it's a modifier key
177+
_keyReport.modifiers &= ~(1<<(k-128));
178+
k = 0;
179+
} else { // it's a printing key
180+
k = pgm_read_byte(_asciimap + k);
181+
if (!k) {
182+
return 0;
183+
}
184+
if (k & SHIFT) { // it's a capital letter or other character reached with shift
185+
_keyReport.modifiers &= ~(0x02); // the left shift modifier
186+
k = k ^ SHIFT;
187+
}
188+
}
189+
190+
return removeKeycodeFromReport(k);
191+
}
192+
193+
size_t NKROKeyboardAPI::removeKeycodeFromReport(uint8_t k)
194+
{
195+
// keymap key
196+
if (k < NKRO_KEY_COUNT)
197+
_keyReport.keys[k / 8] &= ~(1 << (k % 8));
198+
199+
// it's a modifier key
200+
else if ((k >= HID_KEYBOARD_LEFT_CONTROL) && (k <= HID_KEYBOARD_RIGHT_GUI))
201+
_keyReport.modifiers &= ~(0x01 << (k - HID_KEYBOARD_LEFT_CONTROL));
202+
203+
// custom key
204+
else
205+
_keyReport.key = 0x00;
206+
207+
return 1;
208+
}
209+
210+
211+
size_t NKROKeyboardAPI::writeKeycode(uint8_t c)
212+
{
213+
uint8_t p = pressKeycode(c); // Keydown
214+
releaseKeycode(c); // Keyup
215+
return (p); // just return the result of pressKeycode() since release() almost always returns 1
216+
}

plugins/KeyboardioHID/src/HID-Project.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,6 @@ THE SOFTWARE.
5353
#else
5454
#include "SingleReport/BootKeyboard.h"
5555
#include "MultiReport/ImprovedKeyboard.h"
56-
//#include "NKROKeyboard.h"
56+
#include "SingleReport/SingleNKROKeyboard.h"
57+
#include "MultiReport/NKROKeyboard.h"
5758
#endif

0 commit comments

Comments
 (0)