Skip to content

Commit 2f0fe1e

Browse files
2 parents 3863f50 + 2763428 commit 2f0fe1e

File tree

2 files changed

+415
-0
lines changed

2 files changed

+415
-0
lines changed
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
/*
2+
* Based on Obdev's AVRUSB code and under the same license.
3+
*
4+
* TODO: Make a proper file header. :-)
5+
* Modified for Digispark by Digistump
6+
* Version working with belgian keyboards
7+
*/
8+
#ifndef __DigiKeyboard_h__
9+
#define __DigiKeyboard_h__
10+
11+
#include <Arduino.h>
12+
#include <avr/pgmspace.h>
13+
#include <avr/interrupt.h>
14+
#include <avr/delay.h>
15+
#include <string.h>
16+
17+
#include "usbdrv.h"
18+
#include "scancode-ascii-table-be.h"
19+
20+
// TODO: Work around Arduino 12 issues better.
21+
//#include <WConstants.h>
22+
//#undef int()
23+
24+
typedef uint8_t byte;
25+
26+
27+
#define BUFFER_SIZE 2 // Minimum of 2: 1 for modifiers + 1 for keystroke
28+
29+
30+
static uchar idleRate; // in 4 ms units
31+
32+
33+
/* We use a simplifed keyboard report descriptor which does not support the
34+
* boot protocol. We don't allow setting status LEDs and but we do allow
35+
* simultaneous key presses.
36+
* The report descriptor has been created with usb.org's "HID Descriptor Tool"
37+
* which can be downloaded from http://www.usb.org/developers/hidpage/.
38+
* Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
39+
* for the second INPUT item.
40+
*/
41+
const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
42+
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
43+
0x09, 0x06, // USAGE (Keyboard)
44+
0xa1, 0x01, // COLLECTION (Application)
45+
0x05, 0x07, // USAGE_PAGE (Keyboard)
46+
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
47+
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
48+
0x15, 0x00, // LOGICAL_MINIMUM (0)
49+
0x25, 0x01, // LOGICAL_MAXIMUM (1)
50+
0x75, 0x01, // REPORT_SIZE (1)
51+
0x95, 0x08, // REPORT_COUNT (8)
52+
0x81, 0x02, // INPUT (Data,Var,Abs)
53+
0x95, 0x01, // REPORT_COUNT (simultaneous keystrokes)
54+
0x75, 0x08, // REPORT_SIZE (8)
55+
0x25, 0x65, // LOGICAL_MAXIMUM (101)
56+
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
57+
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
58+
0x81, 0x00, // INPUT (Data,Ary,Abs)
59+
0xc0 // END_COLLECTION
60+
};
61+
62+
63+
64+
/* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
65+
* 10 Keyboard/Keypad Page for more codes.
66+
*/
67+
#define MOD_CONTROL_LEFT (1<<0)
68+
#define MOD_SHIFT_LEFT (1<<1)
69+
#define MOD_ALT_LEFT (1<<2)
70+
#define MOD_GUI_LEFT (1<<3)
71+
#define MOD_CONTROL_RIGHT (1<<4)
72+
#define MOD_SHIFT_RIGHT (1<<5)
73+
#define MOD_ALT_RIGHT (1<<6)
74+
#define MOD_GUI_RIGHT (1<<7)
75+
76+
#define KEY_A 20
77+
#define KEY_B 5
78+
#define KEY_C 6
79+
#define KEY_D 7
80+
#define KEY_E 8
81+
#define KEY_F 9
82+
#define KEY_G 10
83+
#define KEY_H 11
84+
#define KEY_I 12
85+
#define KEY_J 13
86+
#define KEY_K 14
87+
#define KEY_L 15
88+
#define KEY_M 51
89+
#define KEY_N 17
90+
#define KEY_O 18
91+
#define KEY_P 19
92+
#define KEY_Q 4
93+
#define KEY_R 21
94+
#define KEY_S 22
95+
#define KEY_T 23
96+
#define KEY_U 24
97+
#define KEY_V 25
98+
#define KEY_W 29
99+
#define KEY_X 27
100+
#define KEY_Y 28
101+
#define KEY_Z 26
102+
#define KEY_1 30
103+
#define KEY_2 31
104+
#define KEY_3 32
105+
#define KEY_4 33
106+
#define KEY_5 34
107+
#define KEY_6 35
108+
#define KEY_7 36
109+
#define KEY_8 37
110+
#define KEY_9 38
111+
#define KEY_0 39
112+
113+
#define KEY_ENTER 40
114+
115+
#define KEY_SPACE 44
116+
117+
#define KEY_F1 58
118+
#define KEY_F2 59
119+
#define KEY_F3 60
120+
#define KEY_F4 61
121+
#define KEY_F5 62
122+
#define KEY_F6 63
123+
#define KEY_F7 64
124+
#define KEY_F8 65
125+
#define KEY_F9 66
126+
#define KEY_F10 67
127+
#define KEY_F11 68
128+
#define KEY_F12 69
129+
130+
#define KEY_ARROW_LEFT 0x50
131+
132+
133+
class DigiKeyboardDevice : public Print {
134+
public:
135+
DigiKeyboardDevice () {
136+
cli();
137+
usbDeviceDisconnect();
138+
_delay_ms(250);
139+
usbDeviceConnect();
140+
141+
142+
usbInit();
143+
144+
sei();
145+
146+
// TODO: Remove the next two lines once we fix
147+
// missing first keystroke bug properly.
148+
memset(reportBuffer, 0, sizeof(reportBuffer));
149+
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
150+
}
151+
152+
void update() {
153+
usbPoll();
154+
}
155+
156+
// delay while updating until we are finished delaying
157+
void delay(long milli) {
158+
unsigned long last = millis();
159+
while (milli > 0) {
160+
unsigned long now = millis();
161+
milli -= now - last;
162+
last = now;
163+
update();
164+
}
165+
}
166+
167+
//sendKeyStroke: sends a key press AND release
168+
void sendKeyStroke(byte keyStroke) {
169+
sendKeyStroke(keyStroke, 0);
170+
}
171+
172+
//sendKeyStroke: sends a key press AND release with modifiers
173+
void sendKeyStroke(byte keyStroke, byte modifiers) {
174+
sendKeyPress(keyStroke, modifiers);
175+
// This stops endlessly repeating keystrokes:
176+
sendKeyPress(0,0);
177+
}
178+
179+
//sendKeyPress: sends a key press only - no release
180+
//to release the key, send again with keyPress=0
181+
void sendKeyPress(byte keyPress) {
182+
sendKeyPress(keyPress, 0);
183+
}
184+
185+
//sendKeyPress: sends a key press only, with modifiers - no release
186+
//to release the key, send again with keyPress=0
187+
void sendKeyPress(byte keyPress, byte modifiers) {
188+
while (!usbInterruptIsReady()) {
189+
// Note: We wait until we can send keyPress
190+
// so we know the previous keyPress was
191+
// sent.
192+
usbPoll();
193+
_delay_ms(5);
194+
}
195+
196+
memset(reportBuffer, 0, sizeof(reportBuffer));
197+
198+
reportBuffer[0] = modifiers;
199+
reportBuffer[1] = keyPress;
200+
201+
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
202+
}
203+
204+
size_t write(uint8_t chr) {
205+
// Scan codes which use 7 bits
206+
if(chr == '<')
207+
sendKeyStroke(0x64);
208+
else if(chr == '>')
209+
sendKeyStroke(0x64, MOD_SHIFT_RIGHT);
210+
else if(chr == '\\')
211+
sendKeyStroke(0x64, MOD_ALT_RIGHT);
212+
213+
else
214+
{
215+
uint8_t data = pgm_read_byte_near(ascii_to_scan_code_table + (chr - 8));
216+
sendKeyStroke(data & 0b00111111, data >> 7 ? MOD_SHIFT_RIGHT : 0 | (data << 1) >> 7 ? MOD_ALT_RIGHT : 0);
217+
}
218+
//#define CONVERTDEADKEYS
219+
#ifdef CONVERTDEADKEYS
220+
/* To convert some dead keys to symbols */
221+
if(chr == '~' || chr == '`')
222+
{
223+
sendKeyStroke(0x2C); //Space
224+
}
225+
#endif
226+
227+
return 1;
228+
}
229+
230+
//private: TODO: Make friend?
231+
uchar reportBuffer[2]; // buffer for HID reports [ 1 modifier byte + (len-1) key strokes]
232+
using Print::write;
233+
};
234+
235+
DigiKeyboardDevice DigiKeyboard = DigiKeyboardDevice();
236+
237+
#ifdef __cplusplus
238+
extern "C"{
239+
#endif
240+
// USB_PUBLIC uchar usbFunctionSetup
241+
uchar usbFunctionSetup(uchar data[8]) {
242+
usbRequest_t *rq = (usbRequest_t *)((void *)data);
243+
244+
usbMsgPtr = DigiKeyboard.reportBuffer; //
245+
if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
246+
/* class request type */
247+
248+
if (rq->bRequest == USBRQ_HID_GET_REPORT) {
249+
/* wValue: ReportType (highbyte), ReportID (lowbyte) */
250+
251+
/* we only have one report type, so don't look at wValue */
252+
// TODO: Ensure it's okay not to return anything here?
253+
return 0;
254+
255+
} else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
256+
//usbMsgPtr = &idleRate;
257+
//return 1;
258+
return 0;
259+
260+
} else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
261+
idleRate = rq->wValue.bytes[1];
262+
263+
}
264+
} else {
265+
/* no vendor specific requests implemented */
266+
}
267+
268+
return 0;
269+
}
270+
#ifdef __cplusplus
271+
} // extern "C"
272+
#endif
273+
274+
275+
#endif // __DigiKeyboard_h__

0 commit comments

Comments
 (0)