Skip to content

Commit 3dbd179

Browse files
committed
standalone Keyboard library
1 parent 462ac21 commit 3dbd179

File tree

2 files changed

+368
-0
lines changed

2 files changed

+368
-0
lines changed

libraries/Keyboard/Keyboard.cpp

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
#if defined(USBCON)
2+
3+
#include "HID.h"
4+
#include "Keyboard.h"
5+
6+
//================================================================================
7+
//================================================================================
8+
// Keyboard
9+
10+
Keyboard_ Keyboard;
11+
12+
Keyboard_::Keyboard_(void)
13+
{
14+
}
15+
16+
void Keyboard_::begin(void)
17+
{
18+
}
19+
20+
void Keyboard_::end(void)
21+
{
22+
}
23+
24+
void Keyboard_::sendReport(KeyReport* keys)
25+
{
26+
HID_SendReport(2,keys,sizeof(KeyReport));
27+
}
28+
29+
extern
30+
const uint8_t _asciimap[128] PROGMEM;
31+
32+
#define SHIFT 0x80
33+
const uint8_t _asciimap[128] =
34+
{
35+
0x00, // NUL
36+
0x00, // SOH
37+
0x00, // STX
38+
0x00, // ETX
39+
0x00, // EOT
40+
0x00, // ENQ
41+
0x00, // ACK
42+
0x00, // BEL
43+
0x2a, // BS Backspace
44+
0x2b, // TAB Tab
45+
0x28, // LF Enter
46+
0x00, // VT
47+
0x00, // FF
48+
0x00, // CR
49+
0x00, // SO
50+
0x00, // SI
51+
0x00, // DEL
52+
0x00, // DC1
53+
0x00, // DC2
54+
0x00, // DC3
55+
0x00, // DC4
56+
0x00, // NAK
57+
0x00, // SYN
58+
0x00, // ETB
59+
0x00, // CAN
60+
0x00, // EM
61+
0x00, // SUB
62+
0x00, // ESC
63+
0x00, // FS
64+
0x00, // GS
65+
0x00, // RS
66+
0x00, // US
67+
68+
0x2c, // ' '
69+
0x1e|SHIFT, // !
70+
0x34|SHIFT, // "
71+
0x20|SHIFT, // #
72+
0x21|SHIFT, // $
73+
0x22|SHIFT, // %
74+
0x24|SHIFT, // &
75+
0x34, // '
76+
0x26|SHIFT, // (
77+
0x27|SHIFT, // )
78+
0x25|SHIFT, // *
79+
0x2e|SHIFT, // +
80+
0x36, // ,
81+
0x2d, // -
82+
0x37, // .
83+
0x38, // /
84+
0x27, // 0
85+
0x1e, // 1
86+
0x1f, // 2
87+
0x20, // 3
88+
0x21, // 4
89+
0x22, // 5
90+
0x23, // 6
91+
0x24, // 7
92+
0x25, // 8
93+
0x26, // 9
94+
0x33|SHIFT, // :
95+
0x33, // ;
96+
0x36|SHIFT, // <
97+
0x2e, // =
98+
0x37|SHIFT, // >
99+
0x38|SHIFT, // ?
100+
0x1f|SHIFT, // @
101+
0x04|SHIFT, // A
102+
0x05|SHIFT, // B
103+
0x06|SHIFT, // C
104+
0x07|SHIFT, // D
105+
0x08|SHIFT, // E
106+
0x09|SHIFT, // F
107+
0x0a|SHIFT, // G
108+
0x0b|SHIFT, // H
109+
0x0c|SHIFT, // I
110+
0x0d|SHIFT, // J
111+
0x0e|SHIFT, // K
112+
0x0f|SHIFT, // L
113+
0x10|SHIFT, // M
114+
0x11|SHIFT, // N
115+
0x12|SHIFT, // O
116+
0x13|SHIFT, // P
117+
0x14|SHIFT, // Q
118+
0x15|SHIFT, // R
119+
0x16|SHIFT, // S
120+
0x17|SHIFT, // T
121+
0x18|SHIFT, // U
122+
0x19|SHIFT, // V
123+
0x1a|SHIFT, // W
124+
0x1b|SHIFT, // X
125+
0x1c|SHIFT, // Y
126+
0x1d|SHIFT, // Z
127+
0x2f, // [
128+
0x31, // bslash
129+
0x30, // ]
130+
0x23|SHIFT, // ^
131+
0x2d|SHIFT, // _
132+
0x35, // `
133+
0x04, // a
134+
0x05, // b
135+
0x06, // c
136+
0x07, // d
137+
0x08, // e
138+
0x09, // f
139+
0x0a, // g
140+
0x0b, // h
141+
0x0c, // i
142+
0x0d, // j
143+
0x0e, // k
144+
0x0f, // l
145+
0x10, // m
146+
0x11, // n
147+
0x12, // o
148+
0x13, // p
149+
0x14, // q
150+
0x15, // r
151+
0x16, // s
152+
0x17, // t
153+
0x18, // u
154+
0x19, // v
155+
0x1a, // w
156+
0x1b, // x
157+
0x1c, // y
158+
0x1d, // z
159+
0x2f|SHIFT, //
160+
0x31|SHIFT, // |
161+
0x30|SHIFT, // }
162+
0x35|SHIFT, // ~
163+
0 // DEL
164+
};
165+
166+
uint8_t USBPutChar(uint8_t c);
167+
168+
// press() adds the specified key (printing, non-printing, or modifier)
169+
// to the persistent key report and sends the report. Because of the way
170+
// USB HID works, the host acts like the key remains pressed until we
171+
// call release(), releaseAll(), or otherwise clear the report and resend.
172+
size_t Keyboard_::press(uint8_t k)
173+
{
174+
uint8_t i;
175+
if (k >= 136) { // it's a non-printing key (not a modifier)
176+
k = k - 136;
177+
} else if (k >= 128) { // it's a modifier key
178+
_keyReport.modifiers |= (1<<(k-128));
179+
k = 0;
180+
} else { // it's a printing key
181+
k = pgm_read_byte(_asciimap + k);
182+
if (!k) {
183+
setWriteError();
184+
return 0;
185+
}
186+
if (k & 0x80) { // it's a capital letter or other character reached with shift
187+
_keyReport.modifiers |= 0x02; // the left shift modifier
188+
k &= 0x7F;
189+
}
190+
}
191+
192+
// Add k to the key report only if it's not already present
193+
// and if there is an empty slot.
194+
if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
195+
_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
196+
_keyReport.keys[4] != k && _keyReport.keys[5] != k) {
197+
198+
for (i=0; i<6; i++) {
199+
if (_keyReport.keys[i] == 0x00) {
200+
_keyReport.keys[i] = k;
201+
break;
202+
}
203+
}
204+
if (i == 6) {
205+
setWriteError();
206+
return 0;
207+
}
208+
}
209+
sendReport(&_keyReport);
210+
return 1;
211+
}
212+
213+
// release() takes the specified key out of the persistent key report and
214+
// sends the report. This tells the OS the key is no longer pressed and that
215+
// it shouldn't be repeated any more.
216+
size_t Keyboard_::release(uint8_t k)
217+
{
218+
uint8_t i;
219+
if (k >= 136) { // it's a non-printing key (not a modifier)
220+
k = k - 136;
221+
} else if (k >= 128) { // it's a modifier key
222+
_keyReport.modifiers &= ~(1<<(k-128));
223+
k = 0;
224+
} else { // it's a printing key
225+
k = pgm_read_byte(_asciimap + k);
226+
if (!k) {
227+
return 0;
228+
}
229+
if (k & 0x80) { // it's a capital letter or other character reached with shift
230+
_keyReport.modifiers &= ~(0x02); // the left shift modifier
231+
k &= 0x7F;
232+
}
233+
}
234+
235+
// Test the key report to see if k is present. Clear it if it exists.
236+
// Check all positions in case the key is present more than once (which it shouldn't be)
237+
for (i=0; i<6; i++) {
238+
if (0 != k && _keyReport.keys[i] == k) {
239+
_keyReport.keys[i] = 0x00;
240+
}
241+
}
242+
243+
sendReport(&_keyReport);
244+
return 1;
245+
}
246+
247+
void Keyboard_::releaseAll(void)
248+
{
249+
_keyReport.keys[0] = 0;
250+
_keyReport.keys[1] = 0;
251+
_keyReport.keys[2] = 0;
252+
_keyReport.keys[3] = 0;
253+
_keyReport.keys[4] = 0;
254+
_keyReport.keys[5] = 0;
255+
_keyReport.modifiers = 0;
256+
sendReport(&_keyReport);
257+
}
258+
259+
size_t Keyboard_::write(uint8_t c)
260+
{
261+
uint8_t p = press(c); // Keydown
262+
release(c); // Keyup
263+
return p; // just return the result of press() since release() almost always returns 1
264+
}
265+
266+
#endif

libraries/Keyboard/Keyboard.h

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#if defined(USBCON)
2+
3+
//================================================================================
4+
//================================================================================
5+
// Keyboard
6+
7+
extern const u8 _hidReportDescriptor[] PROGMEM;
8+
const u8 _hidReportDescriptor[] = {
9+
10+
// Keyboard
11+
0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47
12+
0x09, 0x06, // USAGE (Keyboard)
13+
0xa1, 0x01, // COLLECTION (Application)
14+
0x85, 0x02, // REPORT_ID (2)
15+
0x05, 0x07, // USAGE_PAGE (Keyboard)
16+
17+
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
18+
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
19+
0x15, 0x00, // LOGICAL_MINIMUM (0)
20+
0x25, 0x01, // LOGICAL_MAXIMUM (1)
21+
0x75, 0x01, // REPORT_SIZE (1)
22+
23+
0x95, 0x08, // REPORT_COUNT (8)
24+
0x81, 0x02, // INPUT (Data,Var,Abs)
25+
0x95, 0x01, // REPORT_COUNT (1)
26+
0x75, 0x08, // REPORT_SIZE (8)
27+
0x81, 0x03, // INPUT (Cnst,Var,Abs)
28+
29+
0x95, 0x06, // REPORT_COUNT (6)
30+
0x75, 0x08, // REPORT_SIZE (8)
31+
0x15, 0x00, // LOGICAL_MINIMUM (0)
32+
0x25, 0x65, // LOGICAL_MAXIMUM (101)
33+
0x05, 0x07, // USAGE_PAGE (Keyboard)
34+
35+
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
36+
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
37+
0x81, 0x00, // INPUT (Data,Ary,Abs)
38+
0xc0, // END_COLLECTION
39+
};
40+
41+
#define KEY_LEFT_CTRL 0x80
42+
#define KEY_LEFT_SHIFT 0x81
43+
#define KEY_LEFT_ALT 0x82
44+
#define KEY_LEFT_GUI 0x83
45+
#define KEY_RIGHT_CTRL 0x84
46+
#define KEY_RIGHT_SHIFT 0x85
47+
#define KEY_RIGHT_ALT 0x86
48+
#define KEY_RIGHT_GUI 0x87
49+
50+
#define KEY_UP_ARROW 0xDA
51+
#define KEY_DOWN_ARROW 0xD9
52+
#define KEY_LEFT_ARROW 0xD8
53+
#define KEY_RIGHT_ARROW 0xD7
54+
#define KEY_BACKSPACE 0xB2
55+
#define KEY_TAB 0xB3
56+
#define KEY_RETURN 0xB0
57+
#define KEY_ESC 0xB1
58+
#define KEY_INSERT 0xD1
59+
#define KEY_DELETE 0xD4
60+
#define KEY_PAGE_UP 0xD3
61+
#define KEY_PAGE_DOWN 0xD6
62+
#define KEY_HOME 0xD2
63+
#define KEY_END 0xD5
64+
#define KEY_CAPS_LOCK 0xC1
65+
#define KEY_F1 0xC2
66+
#define KEY_F2 0xC3
67+
#define KEY_F3 0xC4
68+
#define KEY_F4 0xC5
69+
#define KEY_F5 0xC6
70+
#define KEY_F6 0xC7
71+
#define KEY_F7 0xC8
72+
#define KEY_F8 0xC9
73+
#define KEY_F9 0xCA
74+
#define KEY_F10 0xCB
75+
#define KEY_F11 0xCC
76+
#define KEY_F12 0xCD
77+
78+
// Low level key report: up to 6 keys and shift, ctrl etc at once
79+
typedef struct
80+
{
81+
uint8_t modifiers;
82+
uint8_t reserved;
83+
uint8_t keys[6];
84+
} KeyReport;
85+
86+
class Keyboard_ : public Print
87+
{
88+
private:
89+
KeyReport _keyReport;
90+
void sendReport(KeyReport* keys);
91+
public:
92+
Keyboard_(void);
93+
void begin(void);
94+
void end(void);
95+
virtual size_t write(uint8_t k);
96+
virtual size_t press(uint8_t k);
97+
virtual size_t release(uint8_t k);
98+
virtual void releaseAll(void);
99+
};
100+
extern Keyboard_ Keyboard;
101+
102+
#endif

0 commit comments

Comments
 (0)