3
3
*
4
4
* TODO: Make a proper file header. :-)
5
5
* Modified for Digispark by Digistump
6
+ * Added full Keyboard usage values by Danjovic, February 2016
7
+ * Report Buffer extended up to 6 keytrokes simultaneous by Danjovic, March 2016
8
+ * Added LED control by Danjovic, January 2019
6
9
*/
7
10
#ifndef __DigiKeyboard_h__
8
11
#define __DigiKeyboard_h__
14
17
#include < string.h>
15
18
16
19
#include " usbdrv.h"
20
+ #include " hidkeys.h"
17
21
#include " scancode-ascii-table.h"
18
22
19
23
// TODO: Work around Arduino 12 issues better.
22
26
23
27
typedef uint8_t byte;
24
28
25
-
26
- #define BUFFER_SIZE 2 // Minimum of 2: 1 for modifiers + 1 for keystroke
27
-
28
-
29
- static uchar idleRate; // in 4 ms units
30
-
31
-
32
- /* We use a simplifed keyboard report descriptor which does not support the
33
- * boot protocol. We don't allow setting status LEDs and but we do allow
34
- * simultaneous key presses.
35
- * The report descriptor has been created with usb.org's "HID Descriptor Tool"
36
- * which can be downloaded from http://www.usb.org/developers/hidpage/.
37
- * Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
38
- * for the second INPUT item.
39
- */
40
- const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
41
- (char ) 0x05 , (char ) 0x01 , // USAGE_PAGE (Generic Desktop)
42
- (char ) 0x09 , (char ) 0x06 , // USAGE (Keyboard)
43
- (char ) 0xa1 , (char ) 0x01 , // COLLECTION (Application)
44
- (char ) 0x05 , (char ) 0x07 , // USAGE_PAGE (Keyboard)
45
- (char ) 0x19 , (char ) 0xe0 , // USAGE_MINIMUM (Keyboard LeftControl)
46
- (char ) 0x29 , (char ) 0xe7 , // USAGE_MAXIMUM (Keyboard Right GUI)
47
- (char ) 0x15 , (char ) 0x00 , // LOGICAL_MINIMUM (0)
48
- (char ) 0x25 , (char ) 0x01 , // LOGICAL_MAXIMUM (1)
49
- (char ) 0x75 , (char ) 0x01 , // REPORT_SIZE (1)
50
- (char ) 0x95 , (char ) 0x08 , // REPORT_COUNT (8)
51
- (char ) 0x81 , (char ) 0x02 , // INPUT (Data,Var,Abs)
52
- (char ) 0x95 , (char ) 0x01 , // REPORT_COUNT (simultaneous keystrokes)
53
- (char ) 0x75 , (char ) 0x08 , // REPORT_SIZE (8)
54
- (char ) 0x25 , (char ) 0x65 , // LOGICAL_MAXIMUM (101)
55
- (char ) 0x19 , (char ) 0x00 , // USAGE_MINIMUM (Reserved (no event indicated))
56
- (char ) 0x29 , (char ) 0x65 , // USAGE_MAXIMUM (Keyboard Application)
57
- (char ) 0x81 , (char ) 0x00 , // INPUT (Data,Ary,Abs)
58
- (char ) 0xc0 // END_COLLECTION
29
+ typedef struct {
30
+ uint8_t modifier;
31
+ uint8_t reserved;
32
+ uint8_t keycode[6 ];
33
+ } keyboard_report_t ;
34
+
35
+ // static keyboard_report_t keyboard_report; // sent to PC
36
+ static volatile uchar ledState = 0xff ; // received from PC
37
+ static uchar idleRate; // repeat rate for keyboards in 4 ms units
38
+
39
+
40
+ #define NUM_LOCK (1 <<0 )
41
+ #define CAPS_LOCK (1 <<1 )
42
+ #define SCROLL_LOCK (1 <<2 )
43
+
44
+
45
+ // From Frank Zhao's USB Business Card project
46
+ // http://www.frank-zhao.com/cache/usbbusinesscard_details.php
47
+ const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
48
+ 0x05 , 0x01 , // USAGE_PAGE (Generic Desktop)
49
+ 0x09 , 0x06 , // USAGE (Keyboard)
50
+ 0xa1 , 0x01 , // COLLECTION (Application)
51
+ 0x75 , 0x01 , // REPORT_SIZE (1)
52
+ 0x95 , 0x08 , // REPORT_COUNT (8)
53
+ 0x05 , 0x07 , // USAGE_PAGE (Keyboard)(Key Codes)
54
+ 0x19 , 0xe0 , // USAGE_MINIMUM (Keyboard LeftControl)(224)
55
+ 0x29 , 0xe7 , // USAGE_MAXIMUM (Keyboard Right GUI)(231)
56
+ 0x15 , 0x00 , // LOGICAL_MINIMUM (0)
57
+ 0x25 , 0x01 , // LOGICAL_MAXIMUM (1)
58
+ 0x81 , 0x02 , // INPUT (Data,Var,Abs) ; Modifier byte
59
+ 0x95 , 0x01 , // REPORT_COUNT (1)
60
+ 0x75 , 0x08 , // REPORT_SIZE (8)
61
+ 0x81 , 0x03 , // INPUT (Cnst,Var,Abs) ; Reserved byte
62
+ 0x95 , 0x05 , // REPORT_COUNT (5)
63
+ 0x75 , 0x01 , // REPORT_SIZE (1)
64
+ 0x05 , 0x08 , // USAGE_PAGE (LEDs)
65
+ 0x19 , 0x01 , // USAGE_MINIMUM (Num Lock)
66
+ 0x29 , 0x05 , // USAGE_MAXIMUM (Kana)
67
+ 0x91 , 0x02 , // OUTPUT (Data,Var,Abs) ; LED report
68
+ 0x95 , 0x01 , // REPORT_COUNT (1)
69
+ 0x75 , 0x03 , // REPORT_SIZE (3)
70
+ 0x91 , 0x03 , // OUTPUT (Cnst,Var,Abs) ; LED report padding
71
+ 0x95 , 0x06 , // REPORT_COUNT (6)
72
+ 0x75 , 0x08 , // REPORT_SIZE (8)
73
+ 0x15 , 0x00 , // LOGICAL_MINIMUM (0)
74
+ 0x25 , 0x65 , // LOGICAL_MAXIMUM (101)
75
+ 0x05 , 0x07 , // USAGE_PAGE (Keyboard)(Key Codes)
76
+ 0x19 , 0x00 , // USAGE_MINIMUM (Reserved (no event indicated))(0)
77
+ 0x29 , 0x65 , // USAGE_MAXIMUM (Keyboard Application)(101)
78
+ 0x81 , 0x00 , // INPUT (Data,Ary,Abs)
79
+ 0xc0 // END_COLLECTION
59
80
};
81
+
60
82
61
83
62
-
63
- /* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
64
- * 10 Keyboard/Keypad Page for more codes.
65
- */
66
- #define MOD_CONTROL_LEFT (1 <<0 )
67
- #define MOD_SHIFT_LEFT (1 <<1 )
68
- #define MOD_ALT_LEFT (1 <<2 )
69
- #define MOD_GUI_LEFT (1 <<3 )
70
- #define MOD_CONTROL_RIGHT (1 <<4 )
71
- #define MOD_SHIFT_RIGHT (1 <<5 )
72
- #define MOD_ALT_RIGHT (1 <<6 )
73
- #define MOD_GUI_RIGHT (1 <<7 )
74
-
75
- #define KEY_A 4
76
- #define KEY_B 5
77
- #define KEY_C 6
78
- #define KEY_D 7
79
- #define KEY_E 8
80
- #define KEY_F 9
81
- #define KEY_G 10
82
- #define KEY_H 11
83
- #define KEY_I 12
84
- #define KEY_J 13
85
- #define KEY_K 14
86
- #define KEY_L 15
87
- #define KEY_M 16
88
- #define KEY_N 17
89
- #define KEY_O 18
90
- #define KEY_P 19
91
- #define KEY_Q 20
92
- #define KEY_R 21
93
- #define KEY_S 22
94
- #define KEY_T 23
95
- #define KEY_U 24
96
- #define KEY_V 25
97
- #define KEY_W 26
98
- #define KEY_X 27
99
- #define KEY_Y 28
100
- #define KEY_Z 29
101
- #define KEY_1 30
102
- #define KEY_2 31
103
- #define KEY_3 32
104
- #define KEY_4 33
105
- #define KEY_5 34
106
- #define KEY_6 35
107
- #define KEY_7 36
108
- #define KEY_8 37
109
- #define KEY_9 38
110
- #define KEY_0 39
111
-
112
- #define KEY_ENTER 40
113
- #define KEY_ESC 41
114
- #define KEY_BACKSPACE 42
115
- #define KEY_TAB 43
116
- #define KEY_SPACE 44
117
-
118
- #define KEY_F1 58
119
- #define KEY_F2 59
120
- #define KEY_F3 60
121
- #define KEY_F4 61
122
- #define KEY_F5 62
123
- #define KEY_F6 63
124
- #define KEY_F7 64
125
- #define KEY_F8 65
126
- #define KEY_F9 66
127
- #define KEY_F10 67
128
- #define KEY_F11 68
129
- #define KEY_F12 69
130
- #define KEY_PRT_SCR 70
131
- #define KEY_DELETE 76
132
-
133
- #define KEY_ARROW_UP 82
134
- #define KEY_ARROW_DOWN 81
135
- #define KEY_ARROW_LEFT 80
136
- #define KEY_ARROW_RIGHT 79
137
-
138
84
class DigiKeyboardDevice : public Print {
139
85
public:
140
86
DigiKeyboardDevice () {
@@ -150,10 +96,11 @@ class DigiKeyboardDevice : public Print {
150
96
151
97
// TODO: Remove the next two lines once we fix
152
98
// missing first keystroke bug properly.
153
- memset (reportBuffer, 0 , sizeof (reportBuffer ));
154
- usbSetInterrupt (reportBuffer , sizeof (reportBuffer ));
99
+ memset (( void *)&keyboard_report, 0 , sizeof (keyboard_report ));
100
+ usbSetInterrupt (( unsigned char *)&keyboard_report , sizeof (keyboard_report ));
155
101
}
156
-
102
+
103
+
157
104
void update () {
158
105
usbPoll ();
159
106
}
@@ -169,6 +116,13 @@ class DigiKeyboardDevice : public Print {
169
116
}
170
117
}
171
118
119
+
120
+ // get LED State
121
+ uchar getLEDs (void ) {
122
+ return ledState;
123
+ }
124
+
125
+
172
126
// sendKeyStroke: sends a key press AND release
173
127
void sendKeyStroke (byte keyStroke) {
174
128
sendKeyStroke (keyStroke, 0 );
@@ -198,12 +152,13 @@ class DigiKeyboardDevice : public Print {
198
152
_delay_ms (5 );
199
153
}
200
154
201
- memset (reportBuffer, 0 , sizeof (reportBuffer));
202
155
203
- reportBuffer[0 ] = modifiers;
204
- reportBuffer[1 ] = keyPress;
156
+ memset ((void *)&keyboard_report,0 ,sizeof (keyboard_report)); // memset(reportBuffer, 0, sizeof(reportBuffer));
157
+ keyboard_report.modifier = modifiers; // reportBuffer[0] = modifiers;
158
+ keyboard_report.keycode [1 ] = keyPress; // reportBuffer[1] = keyPress;
205
159
206
- usbSetInterrupt (reportBuffer, sizeof (reportBuffer));
160
+ usbSetInterrupt ((unsigned char *)&keyboard_report, sizeof (keyboard_report)); // usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
161
+
207
162
}
208
163
209
164
size_t write (uint8_t chr) {
@@ -213,7 +168,9 @@ class DigiKeyboardDevice : public Print {
213
168
}
214
169
215
170
// private: TODO: Make friend?
216
- uchar reportBuffer[2 ]; // buffer for HID reports [ 1 modifier byte + (len-1) key strokes]
171
+ // maximum 6 keystrokes, defined in HID report
172
+
173
+ keyboard_report_t keyboard_report; // buffer for HID reports [ 1 modifier byte + (len-1) key strokes]
217
174
using Print::write;
218
175
};
219
176
@@ -226,32 +183,49 @@ extern "C"{
226
183
uchar usbFunctionSetup (uchar data[8 ]) {
227
184
usbRequest_t *rq = (usbRequest_t *)((void *)data);
228
185
229
- usbMsgPtr = DigiKeyboard.reportBuffer ; //
230
- if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
231
- /* class request type */
232
-
233
- if (rq->bRequest == USBRQ_HID_GET_REPORT) {
234
- /* wValue: ReportType (highbyte), ReportID (lowbyte) */
235
-
236
- /* we only have one report type, so don't look at wValue */
237
- // TODO: Ensure it's okay not to return anything here?
238
- return 0 ;
239
-
240
- } else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
241
- // usbMsgPtr = &idleRate;
242
- // return 1;
243
- return 0 ;
244
-
245
- } else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
246
- idleRate = rq->wValue .bytes [1 ];
247
-
248
- }
249
- } else {
250
- /* no vendor specific requests implemented */
186
+ // usbMsgPtr = (unsigned char*)&DigiKeyboard.keyboard_report ;//usbMsgPtr = DigiKeyboard.reportBuffer; //
187
+
188
+
189
+ if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
190
+ switch (rq->bRequest ) {
191
+ case USBRQ_HID_GET_REPORT: // send "no keys pressed" if asked here
192
+ // wValue: ReportType (highbyte), ReportID (lowbyte)
193
+ usbMsgPtr = (unsigned char *)&DigiKeyboard.keyboard_report ;// usbMsgPtr = DigiKeyboard.reportBuffer; //
194
+ DigiKeyboard.keyboard_report .modifier = 0 ;
195
+ DigiKeyboard.keyboard_report .keycode [0 ] = 0 ;
196
+ return sizeof (DigiKeyboard.keyboard_report );
197
+ case USBRQ_HID_SET_REPORT: // if wLength == 1, should be LED state
198
+ return (rq->wLength .word == 1 ) ? USB_NO_MSG : 0 ;
199
+ case USBRQ_HID_GET_IDLE: // send idle rate to PC as required by spec
200
+ usbMsgPtr = &idleRate;
201
+ return 1 ;
202
+ case USBRQ_HID_SET_IDLE: // save idle rate as required by spec
203
+ idleRate = rq->wValue .bytes [1 ];
204
+ return 0 ;
205
+ }
251
206
}
252
-
207
+
253
208
return 0 ;
254
209
}
210
+ #ifdef __cplusplus
211
+ } // extern "C"
212
+ #endif
213
+
214
+ #ifdef __cplusplus
215
+ extern " C" {
216
+ #endif
217
+ // update LED state
218
+ usbMsgLen_t usbFunctionWrite (uint8_t * data, uchar len) {
219
+
220
+ if (data[0 ] == ledState)
221
+ return 1 ;
222
+ else
223
+ ledState = data[0 ];
224
+
225
+ return 1 ; // Data read, not expecting more
226
+ }
227
+
228
+
255
229
#ifdef __cplusplus
256
230
} // extern "C"
257
231
#endif
0 commit comments