Skip to content

Commit a8da805

Browse files
author
Florian Fleissner
committed
Implemented host_keymaps
host_keymaps enable defining keymaps in a natural fashion. Instead of using Key constants like Key_A or LSHIFT(Key_A) it allows to conveniently write "a" or "A". The mappings between ascii and unicode characters to USB-HID keys works by reverse engineering the host keymaps of a linux system. The information of the provided keymap files allows for precisely figuring out the Kaleidoscope-Key that is needed to generate a specific utf8 character in a given keymap. For non-unicode keycodes, the linux XKB-keysym name is mapped to a Kaleidoscope-Key. The newly introduced host_keymap system is easily extensible and allows users to define their own non-english keymaps, if necessary by extending an existing keymap. Signed-off-by: Florian Fleissner <[email protected]>
1 parent 2609ee9 commit a8da805

File tree

12 files changed

+3831
-0
lines changed

12 files changed

+3831
-0
lines changed

doc/host-keymaps.md

+199
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Kaleidoscope's host keymap system
2+
3+
The host_keymap system enables specifying keymaps in a natural fashion
4+
by using characters or character strings instead of Kaleidoscope's C++ `Key_...` constants. Furthermore, it allows to select one or more host keymaps and automagically use their mappings from unicode keys to Kaleidoscope's key constants.
5+
6+
## Usage
7+
8+
To use host keymaps you must include on or more keymap specification
9+
headers at the top of the firmware sketch, e.g.
10+
11+
```cpp
12+
#include "kaleidoscope/host_keymap/linux/us/standard/keymap.h"
13+
```
14+
15+
Next, you must make the newly host keymap available at global scope, somewhere
16+
before you specify the keymap. This is done by invoking macro `USE_HOST_KEYMAP`, e.g. as
17+
18+
```cpp
19+
USE_HOST_KEYMAP(linux, us, standard)
20+
```
21+
22+
This declares the us standard keymap as the default host keymap. Any characters (unicode/ascii string literals) that you define in the
23+
`KEYMAP` definition will be interpreted with respect to this
24+
default host keymap.
25+
26+
You can now use key characters like e.g. "a" instead of Key_A in you
27+
keymap definitions.
28+
29+
```cpp
30+
KEYMAPS(
31+
[0] = KEYMAP_STACKED
32+
(
33+
XXX, L"a", L"b", ...
34+
)
35+
)
36+
```
37+
38+
## C++ char and wchar_t strings
39+
40+
Please note the prefix L in the above KEYMAP definition in front of the letter strings. That prefix tells C++ that the character string literals
41+
is to be interpreted as wide character string (possibly a unicode string). You can omit the prefix L for ASCII characters only.
42+
43+
## Key mapping agnostic KEYMAP formulation
44+
45+
The great advantage of host keymaps is that you do not have to consider
46+
the question what Kaleidoscope Key to generate in order for a specific
47+
keycode to be generated on the host.
48+
49+
Let's look at the german standard keymap for an example why this is usefull.
50+
51+
The german language has some special non-ascii characters, called
52+
umlauts, those are ä, ö, ü and ß. Those are placed in different places
53+
of the keymap, partially on keys where on the us english keymap there are
54+
special characters.
55+
56+
By using Kaleidoscope's Key constants, it is pretty difficult to
57+
define a german keymap as one has first to find out, which Key constant
58+
generates which of the Umlauts. But that's not all. Some of the
59+
characters are in different places, compared to the us english standard layout.
60+
61+
With Kaleidoscope's host keymaps, this is now a simple task. Just
62+
include the german keymap and use the german characters (normal characters, umlauts and symbols) in your keymap. Under the hood
63+
Kaleidoscope will take care to generate the appropriate keycodes
64+
for the correct german characters to be generated when the german
65+
keyboard layout is active on the host.
66+
67+
## Specifying individual characters
68+
69+
Individual characters can be directly specified in the keymap as "a", "+", ...
70+
71+
## Case specific version of alphabetical characters
72+
73+
For alphabetical characters the shift modifier
74+
is automatcially added when upper case letters like "A" are used
75+
in the KEYMAP.
76+
77+
## Adding modifiers to keys
78+
79+
To conveniently add modifiers, you can specify strings like "c+a" which
80+
will be interpreted as ctrl+a and will generate LCTRL(Key_A).
81+
82+
Similar to the c-modifier for the control key, there are several more
83+
modifier keys, such as
84+
85+
s: shift
86+
c: control
87+
a: alt
88+
m: meta
89+
g: gui
90+
91+
You can add several modifiers at once. "s+c+a" is equal
92+
to LSHIFT(LCTRL(Key_A)).
93+
94+
## Left and right hand modifier versions
95+
96+
For some modifiers there are left and right hand versions. By default,
97+
the left hand version will be used. For those characters that support
98+
a right hand version (e.g. alt), use the capital modifier character "A"
99+
instead.
100+
101+
## Special keys for non printable actions
102+
103+
Every standard keyboard has special keys that triggers special characters, like line feed
104+
being emitted or other actions that are represented by non-printable
105+
characters (e.g. print screen).
106+
107+
For some of these characters, Kaleidoscope supplies the unicode
108+
symbols that are printed on common keyboards. Have a look in
109+
header `kaleidoscope/host_keymap/unicode.h`.
110+
111+
## Toggling hand keys
112+
113+
Kaleidoscope does not only allow for modifiers to be added
114+
to keys in the keymap like `LCTRL(Key_A)` but also to assign the
115+
modifier key itself to a key in the keymap, like e.g. `Key_LeftShift`.
116+
117+
In header `kaleidoscope/host_keymap/unicode.h` there are unicode
118+
symbols for all modifiers defined, like e.g. '⌃' for control, '⇧' for shift, and so on. Those unicode symbols generated the left hand version
119+
of each modifier. To generate a right hand version, just prefix the
120+
modifier symbol with the character 'r' when used in the KEYMAP, e.g.
121+
like L"r+⇧" to generate `Key_RightShift` instead.
122+
123+
## Separator characters
124+
125+
The characters " ", "\t" and "+" are considered as separators and are
126+
ignored unless being the last character in a sequence (the key-character). The specifications "c + a", "ca" and "c a" are thus equal
127+
and all generate `LCTRL(Key_A)`.
128+
129+
## Modifier key symbols
130+
131+
To make things a little more convenient, there are unicode versions of modifier keys as well
132+
133+
⇧: shift
134+
⌃: control
135+
⌥: alt
136+
⌘: meta
137+
⌘: gui
138+
139+
You can use them e.g. as L"⌥+a" to define a key that equals LALT(Key_A).
140+
141+
Important: Always prefix with L if any non ASCII characters are involved.
142+
143+
## Escaping separators
144+
145+
If one of the separator keys (' ', '\t' and '+') is meant to be output,
146+
it must be escaped by prefixing a "#". This means that "c+# " will generate LCTRL(Key_Spacebar).
147+
The escape character "#" itself must also be escaped. "c+##" will
148+
generate LCTRL(LSHIFT(Key_3)) (in case the us standard host keymap being
149+
the default keymap).
150+
151+
## Adding new keymaps
152+
153+
Alternative keymaps can be easily defined by using the
154+
HOST_KEYMAP_LINUX macro that is defined in
155+
`kaleidoscope/host_keymap/linux.h`.
156+
See the `keymap.h` headers in the subdirectories of `kaleidoscope/host_keymap/linux` for examples how this might look.
157+
158+
## Using more than one host keymap in the same Kaleidoscope KEYMAP
159+
160+
Use the macro MAP_WITH_HOST_KEYMAP to define convenience macros
161+
that help to work with different keymaps in the same sketch, like e.g.
162+
163+
```cpp
164+
#include "kaleidoscope/host_keymap/linux/us/standard/keymap.h"
165+
#include "kaleidoscope/host_keymap/linux/de/standard/keymap.h"
166+
167+
// Important, only supply strings with normal double quotes to macros
168+
// D and U. They will automatically treated as wide characters strings.
169+
//
170+
#define D(KEY_STRING) MAP_WITH_HOST_KEYMAP(linux, de, standard, L##KEY_STRING)
171+
#define U(KEY_STRING) MAP_WITH_HOST_KEYMAP(linux, us, standard, L##KEY_STRING)
172+
173+
// Note: Characters 'z' and 'y' are swapped on a german keyboard in comparison
174+
// to an us standard keyboard.
175+
//
176+
static_assert(D("z") == U("y"), "");
177+
static_assert(D("y") == U("z"), "");
178+
179+
KEYMAPS(
180+
[0] = KEYMAP_STACKED
181+
(
182+
XXX, "1", "2", "3", "4", "5", XXX,
183+
"`", "q", "w", "e", "r", "t", "\t",
184+
L"⇞", "a", D("z"), U("d"), "f", "g",
185+
L"⇟", "z", "x", "c", "v", "b", L"⎋",
186+
187+
L"⌃", L"⌫", L"⌘", L"⇧",
188+
XXX,
189+
190+
XXX, "6", "7", "8", "9", "0", XXX,
191+
L"⎆", "y", "u", "i", "o", "p", "=",
192+
"h", "j", "k", "l", ";", "\"",
193+
XXX, "n", "m", ",", ".", "/", "-",
194+
195+
L"r⇧", L"r⌥", L"␣", L"r⌃",
196+
XXX
197+
)
198+
)
199+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* -*- mode: c++ -*-
2+
* Kaleidoscope-Unicode -- Unicode input helpers
3+
* Copyright (C) 2016, 2017, 2018 Keyboard.io, Inc
4+
*
5+
* This program is free software: you can redistribute it and/or modify it under
6+
* the terms of the GNU General Public License as published by the Free Software
7+
* Foundation, version 3.
8+
*
9+
* This program is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12+
* details.
13+
*
14+
* You should have received a copy of the GNU General Public License along with
15+
* this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include <Kaleidoscope.h>
19+
20+
#include "kaleidoscope/host_keymap/linux/us/standard/keymap.h"
21+
22+
USE_HOST_KEYMAP(linux, us, standard)
23+
24+
// *INDENT-OFF*
25+
26+
KEYMAPS(
27+
[0] = KEYMAP_STACKED
28+
(
29+
XXX, "1", "2", "3", "4", "5", XXX,
30+
"`", "q", "w", "e", "r", "t", "\t",
31+
L"", "a", "s", "d", "f", "g",
32+
L"", "z", "x", "c", "v", "b", L"",
33+
34+
L"", L"", L"", L"",
35+
XXX,
36+
37+
XXX, "6", "7", "8", "9", "0", XXX,
38+
L"", "y", "u", "i", "o", "p", "=",
39+
"h", "j", "k", "l", ";", "\"",
40+
XXX, "n", "m", ",", ".", "/", "-",
41+
42+
L"r⇧", L"r⌥", L"", L"r⌃",
43+
XXX
44+
)
45+
)
46+
// *INDENT-ON*
47+
48+
//KALEIDOSCOPE_INIT_PLUGINS();
49+
50+
void setup() {
51+
Kaleidoscope.setup();
52+
}
53+
54+
void loop() {
55+
Kaleidoscope.loop();
56+
}

src/kaleidoscope/host_keymap/README

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The linux keymaps were generated on an Ubuntu 19.04 system based on XKeyboardConfig 2.23.

src/kaleidoscope/host_keymap/ascii.h

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* Kaleidoscope - Firmware for computer input devices
2+
* Copyright (C) 2013-2018 Keyboard.io, Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify it under
5+
* the terms of the GNU General Public License as published by the Free Software
6+
* Foundation, version 3.
7+
*
8+
* This program is distributed in the hope that it will be useful, but WITHOUT
9+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11+
* details.
12+
*
13+
* You should have received a copy of the GNU General Public License along with
14+
* this program. If not, see <http://www.gnu.org/licenses/>.
15+
*/
16+
17+
#pragma once
18+
19+
#include "kaleidoscope/host_keymap/host_keymap.h"
20+
21+
namespace kaleidoscope {
22+
namespace host_keymap {
23+
namespace ascii {
24+
25+
struct CharProcessor {
26+
static constexpr bool isEscapeChar(char c) {
27+
return c == '#';
28+
}
29+
30+
static constexpr bool isSeparator(char c) {
31+
return (c == ' ')
32+
|| (c == '\t')
33+
|| (c == '+');
34+
}
35+
36+
static constexpr bool isMirrorChar(char c) {
37+
return c == 'r';
38+
}
39+
};
40+
41+
#define _HOST_KEYMAP_CAST_ON_MODIFIERS_ASCII(OP) \
42+
OP('s', LSHIFT(k)) \
43+
OP('S', LSHIFT(k)) \
44+
OP('c', LCTRL(k)) \
45+
OP('C', LCTRL(k)) \
46+
OP('a', LALT(k)) \
47+
OP('A', RALT(k)) \
48+
OP('m', LGUI(k)) \
49+
OP('M', LGUI(k)) \
50+
OP('g', LGUI(k)) \
51+
OP('G', LGUI(k))
52+
53+
// Define a AsciiConverterBase template base class that any ascii keymap converters
54+
// are derived from by means of invoking the HOST_KEYMAP_ASCII_LANGUAGE_CONVERTER
55+
// function macro.
56+
//
57+
_HOST_KEYMAP_DEFINE_CHAR_CONVERTER(
58+
ConverterBase, char, _HOST_KEYMAP_CAST_ON_MODIFIERS_ASCII)
59+
60+
#undef _HOST_KEYMAP_CAST_ON_MODIFIERS_ASCII
61+
62+
typedef _CharParsingStandardFallback<char> CharParsingStandardFallback;
63+
64+
} // namespace ascii
65+
} // namespace host_keymap
66+
} // namespace kaleidoscope
67+
68+
#define HOST_KEYMAP_ASCII_CONVERTER(LANGUAGE_KEYMAP, CHAR_PARSING_FALLBACK) \
69+
struct AsciiConverter \
70+
: public ascii::ConverterBase<AsciiConverter, ascii::CharProcessor> \
71+
{ \
72+
typedef ascii::ConverterBase<AsciiConverter, ascii::CharProcessor> Parent; \
73+
\
74+
using typename Parent::StringMemberType; \
75+
using typename Parent::CharType; \
76+
\
77+
static constexpr bool isKeyChar(char c) { \
78+
return LANGUAGE_KEYMAP(_HOST_KEYMAP_IS_KEY_CHAR) \
79+
CHAR_PARSING_FALLBACK::isKeyChar(c); \
80+
} \
81+
\
82+
static constexpr Key charToKey(char c) { \
83+
return LANGUAGE_KEYMAP( \
84+
_HOST_KEYMAP_MAP_KEY_CHAR_TO_KALEIDOSCOPE_KEY \
85+
) \
86+
CHAR_PARSING_FALLBACK::charToKey(c); \
87+
} \
88+
}; \
89+
\
90+
constexpr Key convertToKey(char c) { \
91+
return AsciiConverter::convertToKey(c); \
92+
} \
93+
template<int _Size> \
94+
constexpr Key convertToKey(char const(&string) [_Size]) { \
95+
return AsciiConverter::convertToKey(string); \
96+
}

0 commit comments

Comments
 (0)