Skip to content

Commit 2ac34d5

Browse files
authored
Merge pull request #53 from edgar-bonet/kbd-layouts
Add support for international layouts
2 parents baf9752 + c609d4a commit 2ac34d5

8 files changed

+781
-142
lines changed

src/Keyboard.cpp

Lines changed: 18 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121

2222
#include "Keyboard.h"
23+
#include "KeyboardLayout.h"
2324

2425
#if defined(_USING_HID)
2526

@@ -64,10 +65,12 @@ Keyboard_::Keyboard_(void)
6465
{
6566
static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
6667
HID().AppendDescriptor(&node);
68+
_asciimap = KeyboardLayout_en_US;
6769
}
6870

69-
void Keyboard_::begin(void)
71+
void Keyboard_::begin(const uint8_t *layout)
7072
{
73+
_asciimap = layout;
7174
}
7275

7376
void Keyboard_::end(void)
@@ -79,144 +82,6 @@ void Keyboard_::sendReport(KeyReport* keys)
7982
HID().SendReport(2,keys,sizeof(KeyReport));
8083
}
8184

82-
extern
83-
const uint8_t _asciimap[128] PROGMEM;
84-
85-
#define SHIFT 0x80
86-
const uint8_t _asciimap[128] =
87-
{
88-
0x00, // NUL
89-
0x00, // SOH
90-
0x00, // STX
91-
0x00, // ETX
92-
0x00, // EOT
93-
0x00, // ENQ
94-
0x00, // ACK
95-
0x00, // BEL
96-
0x2a, // BS Backspace
97-
0x2b, // TAB Tab
98-
0x28, // LF Enter
99-
0x00, // VT
100-
0x00, // FF
101-
0x00, // CR
102-
0x00, // SO
103-
0x00, // SI
104-
0x00, // DEL
105-
0x00, // DC1
106-
0x00, // DC2
107-
0x00, // DC3
108-
0x00, // DC4
109-
0x00, // NAK
110-
0x00, // SYN
111-
0x00, // ETB
112-
0x00, // CAN
113-
0x00, // EM
114-
0x00, // SUB
115-
0x00, // ESC
116-
0x00, // FS
117-
0x00, // GS
118-
0x00, // RS
119-
0x00, // US
120-
121-
0x2c, // ' '
122-
0x1e|SHIFT, // !
123-
0x34|SHIFT, // "
124-
0x20|SHIFT, // #
125-
0x21|SHIFT, // $
126-
0x22|SHIFT, // %
127-
0x24|SHIFT, // &
128-
0x34, // '
129-
0x26|SHIFT, // (
130-
0x27|SHIFT, // )
131-
0x25|SHIFT, // *
132-
0x2e|SHIFT, // +
133-
0x36, // ,
134-
0x2d, // -
135-
0x37, // .
136-
0x38, // /
137-
0x27, // 0
138-
0x1e, // 1
139-
0x1f, // 2
140-
0x20, // 3
141-
0x21, // 4
142-
0x22, // 5
143-
0x23, // 6
144-
0x24, // 7
145-
0x25, // 8
146-
0x26, // 9
147-
0x33|SHIFT, // :
148-
0x33, // ;
149-
0x36|SHIFT, // <
150-
0x2e, // =
151-
0x37|SHIFT, // >
152-
0x38|SHIFT, // ?
153-
0x1f|SHIFT, // @
154-
0x04|SHIFT, // A
155-
0x05|SHIFT, // B
156-
0x06|SHIFT, // C
157-
0x07|SHIFT, // D
158-
0x08|SHIFT, // E
159-
0x09|SHIFT, // F
160-
0x0a|SHIFT, // G
161-
0x0b|SHIFT, // H
162-
0x0c|SHIFT, // I
163-
0x0d|SHIFT, // J
164-
0x0e|SHIFT, // K
165-
0x0f|SHIFT, // L
166-
0x10|SHIFT, // M
167-
0x11|SHIFT, // N
168-
0x12|SHIFT, // O
169-
0x13|SHIFT, // P
170-
0x14|SHIFT, // Q
171-
0x15|SHIFT, // R
172-
0x16|SHIFT, // S
173-
0x17|SHIFT, // T
174-
0x18|SHIFT, // U
175-
0x19|SHIFT, // V
176-
0x1a|SHIFT, // W
177-
0x1b|SHIFT, // X
178-
0x1c|SHIFT, // Y
179-
0x1d|SHIFT, // Z
180-
0x2f, // [
181-
0x31, // bslash
182-
0x30, // ]
183-
0x23|SHIFT, // ^
184-
0x2d|SHIFT, // _
185-
0x35, // `
186-
0x04, // a
187-
0x05, // b
188-
0x06, // c
189-
0x07, // d
190-
0x08, // e
191-
0x09, // f
192-
0x0a, // g
193-
0x0b, // h
194-
0x0c, // i
195-
0x0d, // j
196-
0x0e, // k
197-
0x0f, // l
198-
0x10, // m
199-
0x11, // n
200-
0x12, // o
201-
0x13, // p
202-
0x14, // q
203-
0x15, // r
204-
0x16, // s
205-
0x17, // t
206-
0x18, // u
207-
0x19, // v
208-
0x1a, // w
209-
0x1b, // x
210-
0x1c, // y
211-
0x1d, // z
212-
0x2f|SHIFT, // {
213-
0x31|SHIFT, // |
214-
0x30|SHIFT, // }
215-
0x35|SHIFT, // ~
216-
0x00 // DEL
217-
};
218-
219-
22085
uint8_t USBPutChar(uint8_t c);
22186

22287
// press() adds the specified key (printing, non-printing, or modifier)
@@ -237,10 +102,16 @@ size_t Keyboard_::press(uint8_t k)
237102
setWriteError();
238103
return 0;
239104
}
240-
if (k & 0x80) { // it's a capital letter or other character reached with shift
105+
if ((k & ALT_GR) == ALT_GR) {
106+
_keyReport.modifiers |= 0x40; // AltGr = right Alt
107+
k &= 0x3F;
108+
} else if ((k & SHIFT) == SHIFT) {
241109
_keyReport.modifiers |= 0x02; // the left shift modifier
242110
k &= 0x7F;
243111
}
112+
if (k == ISO_REPLACEMENT) {
113+
k = ISO_KEY;
114+
}
244115
}
245116

246117
// Add k to the key report only if it's not already present
@@ -280,10 +151,16 @@ size_t Keyboard_::release(uint8_t k)
280151
if (!k) {
281152
return 0;
282153
}
283-
if (k & 0x80) { // it's a capital letter or other character reached with shift
154+
if ((k & ALT_GR) == ALT_GR) {
155+
_keyReport.modifiers &= ~(0x40); // AltGr = right Alt
156+
k &= 0x3F;
157+
} else if ((k & SHIFT) == SHIFT) {
284158
_keyReport.modifiers &= ~(0x02); // the left shift modifier
285159
k &= 0x7F;
286160
}
161+
if (k == ISO_REPLACEMENT) {
162+
k = ISO_KEY;
163+
}
287164
}
288165

289166
// Test the key report to see if k is present. Clear it if it exists.

src/Keyboard.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@
8383
#define KEY_F23 0xFA
8484
#define KEY_F24 0xFB
8585

86+
// Supported keyboard layouts
87+
extern const uint8_t KeyboardLayout_de_DE[];
88+
extern const uint8_t KeyboardLayout_en_US[];
89+
extern const uint8_t KeyboardLayout_es_ES[];
90+
extern const uint8_t KeyboardLayout_fr_FR[];
91+
extern const uint8_t KeyboardLayout_it_IT[];
8692

8793
// Low level key report: up to 6 keys and shift, ctrl etc at once
8894
typedef struct
@@ -96,10 +102,11 @@ class Keyboard_ : public Print
96102
{
97103
private:
98104
KeyReport _keyReport;
105+
const uint8_t *_asciimap;
99106
void sendReport(KeyReport* keys);
100107
public:
101108
Keyboard_(void);
102-
void begin(void);
109+
void begin(const uint8_t *layout = KeyboardLayout_en_US);
103110
void end(void);
104111
size_t write(uint8_t k);
105112
size_t write(const uint8_t *buffer, size_t size);

src/KeyboardLayout.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
KeyboardLayout.h
3+
4+
This file is not part of the public API. It is meant to be included
5+
only in Keyboard.cpp and the keyboard layout files. Layout files map
6+
ASCII character codes to keyboard scan codes (technically, to USB HID
7+
Usage codes), possibly altered by the SHIFT or ALT_GR modifiers.
8+
9+
== Creating your own layout ==
10+
11+
In order to create your own layout file, copy an existing layout that
12+
is similar to yours, then modify it to use the correct keys. The
13+
layout is an array in ASCII order. Each entry contains a scan code,
14+
possibly modified by "|SHIFT" or "|ALT_GR", as in this excerpt from
15+
the Italian layout:
16+
17+
0x35, // bslash
18+
0x30|ALT_GR, // ]
19+
0x2e|SHIFT, // ^
20+
21+
Do not change the control characters (those before scan code 0x2c,
22+
corresponding to space). Do not attempt to grow the table past DEL. Do
23+
not use both SHIFT and ALT_GR on the same character: this is not
24+
supported. Unsupported characters should have 0x00 as scan code.
25+
26+
For a keyboard with an ISO physical layout, use the scan codes below:
27+
28+
+---+---+---+---+---+---+---+---+---+---+---+---+---+-------+
29+
|35 |1e |1f |20 |21 |22 |23 |24 |25 |26 |27 |2d |2e |BackSp |
30+
+---+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-----+
31+
| Tab |14 |1a |08 |15 |17 |1c |18 |0c |12 |13 |2f |30 | Ret |
32+
+-----++--++--++--++--++--++--++--++--++--++--++--++--++ |
33+
|CapsL |04 |16 |07 |09 |0a |0b |0d |0e |0f |33 |34 |31 | |
34+
+----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+---+----+
35+
|Shi.|32 |1d |1b |06 |19 |05 |11 |10 |36 |37 |38 | Shift |
36+
+----+---++--+-+-+---+---+---+---+---+--++---+---++----+----+
37+
|Ctrl|Win |Alt | |AlGr|Win |Menu|Ctrl|
38+
+----+----+----+------------------------+----+----+----+----+
39+
40+
The ANSI layout is identical except that key 0x31 is above (rather
41+
than next to) Return, and there is not key 0x32.
42+
43+
Give a unique name to the layout array, then declare it in Keyboard.h
44+
with a line of the form:
45+
46+
extern const uint8_t KeyboardLayout_xx_YY[];
47+
48+
== Encoding details ==
49+
50+
All scan codes are less than 0x80, which makes bit 7 available to
51+
signal that a modifier (Shift or AltGr) is needed to generate the
52+
character. With only one exception, keys that are used with modifiers
53+
have scan codes that are less than 0x40. This makes bit 6 available
54+
to signal whether the modifier is Shift or AltGr. The exception is
55+
0x64, the key next next to Left Shift on the ISO layout (and absent
56+
from the ANSI layout). We handle it by replacing its value by 0x32 in
57+
the layout arrays.
58+
*/
59+
60+
#include <Arduino.h>
61+
62+
#define SHIFT 0x80
63+
#define ALT_GR 0xc0
64+
#define ISO_KEY 0x64
65+
#define ISO_REPLACEMENT 0x32

0 commit comments

Comments
 (0)