Skip to content

Commit 8ea07ec

Browse files
2 parents 660b98d + 109617b commit 8ea07ec

File tree

4 files changed

+391
-143
lines changed

4 files changed

+391
-143
lines changed

digistump-avr/libraries/DigisparkKeyboard/DigiKeyboard.h

Lines changed: 115 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
*
44
* TODO: Make a proper file header. :-)
55
* 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
69
*/
710
#ifndef __DigiKeyboard_h__
811
#define __DigiKeyboard_h__
@@ -14,6 +17,7 @@
1417
#include <string.h>
1518

1619
#include "usbdrv.h"
20+
#include "hidkeys.h"
1721
#include "scancode-ascii-table.h"
1822

1923
// TODO: Work around Arduino 12 issues better.
@@ -22,119 +26,61 @@
2226

2327
typedef uint8_t byte;
2428

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
5980
};
81+
6082

6183

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-
13884
class DigiKeyboardDevice : public Print {
13985
public:
14086
DigiKeyboardDevice () {
@@ -150,10 +96,11 @@ class DigiKeyboardDevice : public Print {
15096

15197
// TODO: Remove the next two lines once we fix
15298
// 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));
155101
}
156-
102+
103+
157104
void update() {
158105
usbPoll();
159106
}
@@ -169,6 +116,13 @@ class DigiKeyboardDevice : public Print {
169116
}
170117
}
171118

119+
120+
// get LED State
121+
uchar getLEDs (void) {
122+
return ledState;
123+
}
124+
125+
172126
//sendKeyStroke: sends a key press AND release
173127
void sendKeyStroke(byte keyStroke) {
174128
sendKeyStroke(keyStroke, 0);
@@ -198,12 +152,13 @@ class DigiKeyboardDevice : public Print {
198152
_delay_ms(5);
199153
}
200154

201-
memset(reportBuffer, 0, sizeof(reportBuffer));
202155

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;
205159

206-
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
160+
usbSetInterrupt((unsigned char*)&keyboard_report, sizeof(keyboard_report)); // usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
161+
207162
}
208163

209164
size_t write(uint8_t chr) {
@@ -213,7 +168,9 @@ class DigiKeyboardDevice : public Print {
213168
}
214169

215170
//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]
217174
using Print::write;
218175
};
219176

@@ -226,32 +183,49 @@ extern "C"{
226183
uchar usbFunctionSetup(uchar data[8]) {
227184
usbRequest_t *rq = (usbRequest_t *)((void *)data);
228185

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+
}
251206
}
252-
207+
253208
return 0;
254209
}
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+
255229
#ifdef __cplusplus
256230
} // extern "C"
257231
#endif
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/***
2+
* ___ _ _ _ __ _ _
3+
* | \(_)__ _(_) |/ /___ _ _| |__ ___ __ _ _ _ __| |
4+
* | |) | / _` | | ' </ -_) || | '_ \/ _ \/ _` | '_/ _` |
5+
* |___/|_\__, |_|_|\_\___|\_, |_.__/\___/\__,_|_| \__,_|
6+
* __ |___/_ _ _|__/___ ___
7+
* \ \ / (_) |_| |_ | | | __| \ ___
8+
* \ \/\/ /| | _| ' \ | |__| _|| |) (_-<
9+
* \_/\_/ |_|\__|_||_| |____|___|___//__/
10+
*
11+
* Danjovic, March 2020
12+
*/
13+
14+
// Use modified version of DigiKeyboard library
15+
//
16+
#include "DigiKeyboard.h"
17+
18+
void setup() {
19+
pinMode(1,OUTPUT); // BuiltIn LED as output
20+
}
21+
22+
23+
void loop() {
24+
// Check the state of Caps Lock and change led accordingly
25+
if (DigiKeyboard.getLEDs() & CAPS_LOCK)
26+
digitalWrite(1, HIGH);
27+
else
28+
digitalWrite(1, LOW);
29+
DigiKeyboard.delay(10);
30+
}

0 commit comments

Comments
 (0)