diff --git a/examples/Keystrokes/HostKeymap/HostKeymap.ino b/examples/Keystrokes/HostKeymap/HostKeymap.ino
new file mode 100644
index 0000000000..8ee777a809
--- /dev/null
+++ b/examples/Keystrokes/HostKeymap/HostKeymap.ino
@@ -0,0 +1,58 @@
+/* -*- mode: c++ -*-
+ * Kaleidoscope-Unicode -- Unicode input helpers
+ * Copyright (C) 2016, 2017, 2018 Keyboard.io, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#include
+
+#include "kaleidoscope/host_keymap/ascii/us_en.h"
+#include "kaleidoscope/host_keymap/unicode/us_en.h"
+
+USE_HOST_KEYMAP(ascii, us_en)
+USE_HOST_KEYMAP(unicode, us_en)
+
+// *INDENT-OFF*
+
+KEYMAPS(
+ [0] = KEYMAP_STACKED
+ (
+ XXX, "1", "2", "3", "4", "5", XXX,
+ "`", "q", "w", "e", "r", "t", "\t",
+ L"⇞", "a", "s", "d", "f", "g",
+ L"⇟", "z", "x", "c", "v", "b", L"⎋",
+
+ L"⌃", L"⌫", L"⌘", L"⇧",
+ XXX,
+
+ XXX, "6", "7", "8", "9", "0", XXX,
+ L"⎆", "y", "u", "i", "o", "p", "=",
+ "h", "j", "k", "l", ";", "\"",
+ XXX, "n", "m", ",", ".", "/", "-",
+
+ L"r⇧", L"r⌥", L"␣", L"r⌃",
+ XXX
+ )
+)
+// *INDENT-ON*
+
+//KALEIDOSCOPE_INIT_PLUGINS();
+
+void setup() {
+ Kaleidoscope.setup();
+}
+
+void loop() {
+ Kaleidoscope.loop();
+}
diff --git a/src/kaleidoscope/host_keymap/ascii/common.h b/src/kaleidoscope/host_keymap/ascii/common.h
new file mode 100644
index 0000000000..6338800f0f
--- /dev/null
+++ b/src/kaleidoscope/host_keymap/ascii/common.h
@@ -0,0 +1,87 @@
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2013-2018 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+#include "kaleidoscope/host_keymap/host_keymap.h"
+
+namespace kaleidoscope {
+namespace host_keymap {
+namespace ascii {
+
+struct AsciiCharProcessor {
+ static constexpr bool isEscapeChar(char c) {
+ return c == '#';
+ }
+
+ static constexpr bool isSeparator(char c) {
+ return (c == ' ')
+ || (c == '\t')
+ || (c == '+');
+ }
+
+ static constexpr bool isMirrorChar(char c) {
+ return c == 'r';
+ }
+};
+
+#define _HOST_KEYMAP_CAST_ON_MODIFIERS_ASCII(OP) \
+ OP('s', LSHIFT(k)) \
+ OP('S', LSHIFT(k)) \
+ OP('c', LCTRL(k)) \
+ OP('C', LCTRL(k)) \
+ OP('a', LALT(k)) \
+ OP('A', RALT(k)) \
+ OP('m', LGUI(k)) \
+ OP('M', LGUI(k)) \
+ OP('g', LGUI(k)) \
+ OP('G', LGUI(k))
+
+// Define a AsciiConverter template base class that any ascii keymap converters
+// are derived from by means of invoking the HOST_KEYMAP_ASCII_LANGUAGE_CONVERTER
+// function macro.
+//
+_HOST_KEYMAP_DEFINE_CHAR_CONVERTER(
+ AsciiConverter, char, _HOST_KEYMAP_CAST_ON_MODIFIERS_ASCII)
+
+#undef _HOST_KEYMAP_CAST_ON_MODIFIERS_ASCII
+
+typedef _CharParsingStandardFallback CharParsingStandardFallback;
+
+} // namespace ascii
+} // namespace host_keymap
+} // namespace kaleidoscope
+
+#define HOST_KEYMAP_ASCII_LANGUAGE_CONVERTER(LANGUAGE_KEYMAP, CHAR_PARSING_FALLBACK) \
+ struct Converter : public AsciiConverter \
+ { \
+ typedef AsciiConverter Parent; \
+ \
+ using typename Parent::StringMemberType; \
+ using typename Parent::CharType; \
+ \
+ static constexpr bool isKeyChar(char c) { \
+ return LANGUAGE_KEYMAP(_HOST_KEYMAP_IS_KEY_CHAR) \
+ CHAR_PARSING_FALLBACK::isKeyChar(c); \
+ } \
+ \
+ static constexpr Key charToKey(char c) { \
+ return LANGUAGE_KEYMAP( \
+ _HOST_KEYMAP_MAP_KEY_CHAR_TO_KALEIDOSCOPE_KEY \
+ ) \
+ CHAR_PARSING_FALLBACK::charToKey(c); \
+ } \
+ };
diff --git a/src/kaleidoscope/host_keymap/ascii/us_en.h b/src/kaleidoscope/host_keymap/ascii/us_en.h
new file mode 100644
index 0000000000..f42e0331b0
--- /dev/null
+++ b/src/kaleidoscope/host_keymap/ascii/us_en.h
@@ -0,0 +1,142 @@
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2013-2018 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+#include "kaleidoscope/key_defs.h"
+#include "kaleidoscope/key_defs_keyboard.h"
+#include "kaleidoscope/host_keymap/ascii/common.h"
+
+#define ASCII_US_EN_KEYMAP(OP) \
+ OP('\n', Key_Enter) \
+ OP('\t', Key_Tab) \
+ \
+ OP('!', LSHIFT(Key_1)) \
+ OP('@', LSHIFT(Key_2)) \
+ OP('#', LSHIFT(Key_3)) \
+ OP('$', LSHIFT(Key_4)) \
+ OP('%', LSHIFT(Key_5)) \
+ OP('&', LSHIFT(Key_7)) \
+ OP('\'', Key_Quote) \
+ OP('"', LSHIFT(Key_Quote)) \
+ OP('(', LSHIFT(Key_9)) \
+ OP(')', LSHIFT(Key_0)) \
+ OP('*', LSHIFT(Key_8)) \
+ OP('+', LSHIFT(Key_Equals)) \
+ OP(',', Key_Comma) \
+ OP('-', Key_Minus) \
+ OP('.', Key_Period) \
+ OP('/', Key_Slash) \
+ OP('0', Key_0) \
+ OP('1', Key_1) \
+ OP('2', Key_2) \
+ OP('3', Key_3) \
+ OP('4', Key_4) \
+ OP('5', Key_5) \
+ OP('6', Key_6) \
+ OP('7', Key_7) \
+ OP('8', Key_8) \
+ OP('9', Key_9) \
+ OP(':', LSHIFT(Key_Semicolon)) \
+ OP(';', Key_Semicolon) \
+ OP('<', LSHIFT(Key_Comma)) \
+ OP('=', Key_Equals) \
+ OP('>', LSHIFT(Key_Period)) \
+ OP('?', LSHIFT(Key_Slash)) \
+ \
+ OP('A', LSHIFT(Key_A)) \
+ OP('B', LSHIFT(Key_B)) \
+ OP('C', LSHIFT(Key_C)) \
+ OP('D', LSHIFT(Key_D)) \
+ OP('E', LSHIFT(Key_E)) \
+ OP('F', LSHIFT(Key_F)) \
+ OP('G', LSHIFT(Key_G)) \
+ OP('H', LSHIFT(Key_H)) \
+ OP('I', LSHIFT(Key_I)) \
+ OP('J', LSHIFT(Key_J)) \
+ OP('K', LSHIFT(Key_K)) \
+ OP('L', LSHIFT(Key_L)) \
+ OP('M', LSHIFT(Key_M)) \
+ OP('N', LSHIFT(Key_N)) \
+ OP('O', LSHIFT(Key_O)) \
+ OP('P', LSHIFT(Key_P)) \
+ OP('Q', LSHIFT(Key_Q)) \
+ OP('R', LSHIFT(Key_R)) \
+ OP('S', LSHIFT(Key_S)) \
+ OP('T', LSHIFT(Key_T)) \
+ OP('U', LSHIFT(Key_U)) \
+ OP('V', LSHIFT(Key_V)) \
+ OP('W', LSHIFT(Key_W)) \
+ OP('X', LSHIFT(Key_X)) \
+ OP('Y', LSHIFT(Key_Y)) \
+ OP('Z', LSHIFT(Key_Z)) \
+ \
+ OP('[', Key_LeftBracket) \
+ OP('\\', Key_Backslash) \
+ OP(']', Key_RightBracket) \
+ OP('^', LSHIFT(Key_6)) \
+ OP('_', LSHIFT(Key_Minus)) \
+ OP('`', Key_Backtick) \
+ \
+ OP('a', Key_A) \
+ OP('b', Key_B) \
+ OP('c', Key_C) \
+ OP('d', Key_D) \
+ OP('e', Key_E) \
+ OP('f', Key_F) \
+ OP('g', Key_G) \
+ OP('h', Key_H) \
+ OP('i', Key_I) \
+ OP('j', Key_J) \
+ OP('k', Key_K) \
+ OP('l', Key_L) \
+ OP('m', Key_M) \
+ OP('n', Key_N) \
+ OP('o', Key_O) \
+ OP('p', Key_P) \
+ OP('q', Key_Q) \
+ OP('r', Key_R) \
+ OP('s', Key_S) \
+ OP('t', Key_T) \
+ OP('u', Key_U) \
+ OP('v', Key_V) \
+ OP('w', Key_W) \
+ OP('x', Key_X) \
+ OP('y', Key_Y) \
+ OP('z', Key_Z) \
+ \
+ OP('{', LSHIFT(Key_LeftBracket)) \
+ OP('|', LSHIFT(Key_Backslash)) \
+ OP('}', LSHIFT(Key_RightBracket)) \
+ OP('~', Key_Minus) \
+ OP(' ', Key_Spacebar)
+
+namespace kaleidoscope {
+namespace host_keymap {
+namespace ascii {
+namespace us_en {
+
+HOST_KEYMAP_ASCII_LANGUAGE_CONVERTER(
+ ASCII_US_EN_KEYMAP,
+ CharParsingStandardFallback
+)
+
+} // namespace us_en
+} // namespace ascii
+} // namespace host_keymap
+} // namespace kaleidoscope
+
+#undef ASCII_US_EN_KEYMAP
diff --git a/src/kaleidoscope/host_keymap/host_keymap.h b/src/kaleidoscope/host_keymap/host_keymap.h
new file mode 100644
index 0000000000..a46ea82e6b
--- /dev/null
+++ b/src/kaleidoscope/host_keymap/host_keymap.h
@@ -0,0 +1,425 @@
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2013-2018 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+#include "kaleidoscope/key_defs.h"
+#include "kaleidoscope/key_defs_keyboard.h"
+
+//##############################################################################
+// kaleidoscope-host_keymap
+//
+// The host_keymap system enables specifying keymaps in a natural fashion
+// by using characters or character strings (both ascii and unicode).
+//
+// Usage:
+//
+// To use host_keymaps you must include on or more keymap specification headers
+// at the top of the firmware sketch, e.g.
+//
+// #include "kaleidoscope/host_keymap/ascii/us_en.h"
+//
+// to use the ascii version of the us_en keymap.
+//
+// Next, you must make the host_keymap available at global scope, somewhere
+// before you specify the keymap. This is done by invoking a macro.
+//
+// USE_HOST_KEYMAP(ascii, us_en)
+//
+// Now you can use key characters like e.g. "a" instead of Key_A in you
+// keymap definitions
+//
+// KEYMAPS(
+// [0] = KEYMAP_STACKED
+// (
+// XXX, "1", "2", ...
+// )
+// )
+//
+// # Specifying individual characters
+//
+// Individual characters can be directly specified as "a", "+", ...
+//
+// # Case specific version of alphabetical characters
+
+// Please note that for alphabetical characters like "A" the shift modifier
+// is automatcially added to generate an actual uppercase "A".
+//
+// # Adding modifiers to keys
+//
+// To conveniently add modifiers, you can specify strings like "c+a" which
+// will end up as ctrl+a and is the same as LCTRL(Key_A).
+//
+// Similar to the c-modifier for the control key, there are several more
+// modifier keys, such as
+//
+// s: shift
+// c: control
+// a: alt
+// m: meta
+// g: gui
+//
+// You can add several modifiers at once. "s+c+a" is equal
+// to LSHIFT(LCTRL(Key_A)).
+//
+// # Separator characters
+//
+// The characters " ", "\t" and "+" are considered as separators and are
+// ignored unless being the last character in a sequence (the key-character).
+//
+// # Escaping separators
+//
+// When one of the separator keys is meant to be output, it can be escaped
+// by a "#". This means that "c+# " will generate LCTRL(Key_Spacebar).
+// The excape character "#" must also be escaped. "c+##" will
+// generate LCTRL(LSHIFT(Key_3)) (in case of us_en host_keymap).
+//
+// # Unicode characters
+//
+// host_keymaps supports both ascii and unicode characters and strings.
+// For the latter, single characters and strings have both be prefixed with
+// an L which informs C++ to use wide characters.
+//
+// The rest works the same as with ascii specifications. L"a" equals Key_A
+// and L"c+a" LCTRL(Key_A).
+//
+// # Unicode symbol characters
+//
+// The nice thing about unicode is that it provides tons of special symbols.
+// Among those are most of the symbols that are printed on typical off-the-shelf
+// keyboard, like e.g. ␣ for the space bar.
+//
+// host_keymap defines a number of such symbols
+// (have a look at kaleidoscope/host_keymap/unicode/us_en.h).
+//
+// # Modifier key symbols
+//
+// For the unicode versions of host_keymaps there are special symbols for
+// the modifier keys.
+//
+// ⇧: shift
+// ⌃: control
+// ⌥: alt
+// ⌘: meta
+// ⌘: gui
+//
+// You can use them e.g. as L"⌥+a" to define a key that equals LALT(Key_A).
+//
+// # Modifier keys
+//
+// You can define modifier keys alone as L"⇧" for Key_LeftShift, e.g.
+// To gain the right hand side version of the modifier use e.g. L"r⇧"
+// to define Key_RightShift.
+//
+// # Adding new keymaps
+//
+// Alternative keymaps can be easily defined by using the
+// HOST_KEYMAP_UNICODE_LANGUAGE_CONVERTER macro defined in
+// kaleidoscope/host_keymap/unicode/common.h or its ascii sibling
+// defined in kaleidoscope/host_keymap/ascii/common.h.
+// See the header kaleidoscope/host_keymap/unicode/us_en.h for
+// an example how this can be done.
+//
+// For an example that demonstrates how to define a new keymap that is
+// based on another keymap, see the header
+// kaleidoscope/host_keymap/unicode/eurkey.h that defines the
+// EurKey keymap based on the us_en keymap as a fallback mapping.
+//##############################################################################
+
+// Use the USE_HOST_KEYMAP macro in you sketch to make a host_keymap available.
+//
+#define USE_HOST_KEYMAP(CHAR_TYPE, KEYMAP) \
+ namespace kaleidoscope { \
+ \
+ template \
+ constexpr Key convertToKey( \
+ kaleidoscope::host_keymap::CHAR_TYPE::KEYMAP \
+ ::Converter::CharType const (&string) [_Size]) { \
+ return kaleidoscope::host_keymap::CHAR_TYPE::KEYMAP \
+ ::Converter::convertToKey(string); \
+ } \
+ \
+ constexpr Key convertToKey(kaleidoscope::host_keymap::CHAR_TYPE::KEYMAP \
+ ::Converter::CharType c) { \
+ return kaleidoscope::host_keymap::CHAR_TYPE::KEYMAP \
+ ::Converter::convertToKey(c); \
+ } \
+ }
+
+// Use macro IMPORT_NAMED_HOST_KEYMAP to use individual host_keymap
+// keymaps on different layers.
+//
+// Example: Use ascii-us_en keymap on first layer and ascii-de keymap on second
+// layer.
+//
+// // At global scope in firmware sketch
+// //
+// #include "kaleidoscope/host_keymap/ascii/us_en/h"
+// #include "kaleidoscope/host_keymap/ascii/de/h"
+//
+// ...
+//
+// IMPORT_NAMED_HOST_KEYMAP(ascii, us_en, myConvertToKeyAsciiUsEn)
+// IMPORT_NAMED_HOST_KEYMAP(ascii, de, myConvertToKeyAsciiDe)
+//
+// START_KEYMAPS
+// #undef CONVERT_TO_KEY
+// #define CONVERT_TO_KEY(INPUT) myConvertToKeyAsciiUsEn(INPUT)
+// [1] = KEYMAP_STACKED('q', 'w', 'e', 'r', 't', 'y'/* more key definitions ...*/),
+//
+// #undef CONVERT_TO_KEY
+// #define CONVERT_TO_KEY(INPUT) myConvertToKeyAsciiDe(INPUT)
+// [2] = KEYMAP_STACKED('q', 'w', 'e', 'r', 't', 'z', /* more key definitions ...*/),
+//
+// END_KEYMAPS
+//
+#define IMPORT_NAMED_HOST_KEYMAP(CHAR_TYPE, HOST_KEYMAP, NAME) \
+ namespace kaleidoscope { \
+ Key NAME(char c) { \
+ kaleidoscope::host_keymap::CHAR_TYPE::HOST_KEYMAP \
+ ::Converter::convertToKey(c); \
+ } \
+ \
+ template \
+ Key NAME(char const (&string)[_Size]) { \
+ kaleidoscope::host_keymap::CHAR_TYPE::HOST_KEYMAP \
+ ::Converter::convertToKey(string); \
+ } \
+ \
+ Key NAME(Key k) { return k; } \
+ }
+
+namespace kaleidoscope {
+namespace host_keymap {
+
+// A helper class for compile time keymap string parsing.
+//
+template
+class StringMember {
+ public:
+
+ typedef _CharType CharType;
+ typedef _CharProcessor CharProcessor;
+ typedef StringMember<_CharType, _CharProcessor> ThisType;
+
+ template< unsigned _Size >
+ constexpr StringMember(const _CharType(&string)[_Size], int pos = 0)
+ : string_{string},
+ size_{_Size - 1},
+ pos_{pos} {
+ static_assert(_Size >= 1, "Not a string literal");
+ }
+
+ constexpr StringMember(const _CharType * const string, int size, int pos)
+ : string_{string},
+ size_{size},
+ pos_{pos}
+ {}
+
+ constexpr _CharType toChar() const {
+ return string_[pos_];
+ }
+ constexpr bool isValid() const {
+ return pos_ < size_;
+ }
+ constexpr ThisType next() const {
+ return ThisType{string_, size_, pos_ + 1};
+ }
+ constexpr bool is(_CharType c) {
+ return string_[pos_] == c;
+ }
+ constexpr int length() const {
+ return size_;
+ }
+
+ constexpr bool isEscapeChar() const {
+ return CharProcessor::isEscapeChar(string_[pos_]);
+ }
+
+ constexpr bool isSeparator() const {
+ return CharProcessor::isSeparator(string_[pos_]);
+ }
+
+ constexpr bool isMirrorChar() const {
+ return CharProcessor::isMirrorChar(string_[pos_]);
+ }
+
+ constexpr bool isPanultimate() const {
+ return (pos_ + 2) == size_;
+ }
+ constexpr bool onlySeparatorsFollow() const {
+ return this->isValid()
+ ? (this->isSeparator() && this->next().onlySeparatorsFollow())
+ : true;
+ }
+ constexpr bool isLast() const {
+ return (pos_ + 1) == size_;
+ }
+ constexpr bool isLastNonSeparator() const {
+ return this->isValid() && this->next().onlySeparatorsFollow();
+ }
+
+ private:
+
+ const _CharType *const string_;
+ int size_;
+ int pos_;
+};
+
+#define _IS_MOD(TYPE, HAND) (k.getKeyCode() == Key_##HAND##TYPE.getKeyCode())
+#define _IS_ANY_MOD(TYPE) (_IS_MOD(TYPE, Left) || (_IS_MOD(TYPE, Right)))
+
+// TODO: Move this to key_defs.h?
+//
+constexpr bool isModifierKey(Key k) {
+ return _IS_ANY_MOD(Shift)
+ || _IS_ANY_MOD(Control)
+ || _IS_ANY_MOD(Alt)
+ || _IS_ANY_MOD(Gui);
+}
+
+#undef _IS_MOD
+#undef _IS_ANY_MOD
+
+#define _MIRROR_MOD(NAME) \
+ (k.getKeyCode() == Key_Left##NAME.getKeyCode()) \
+ ? Key{Key_Right##NAME.getKeyCode(), k.getFlags()} \
+ : (k.getKeyCode() == Key_Right##NAME.getKeyCode()) \
+ ? Key{Key_Left##NAME.getKeyCode(), k.getFlags()}
+
+// TODO: Move this to key_defs.h?
+//
+constexpr Key mirrorModifier(Key k) {
+ return isModifierKey(k)
+ ? (
+ _MIRROR_MOD(Shift)
+ : _MIRROR_MOD(Control)
+ : _MIRROR_MOD(Alt)
+ : _MIRROR_MOD(Gui)
+ : bad_keymap_key
+ )
+ : bad_keymap_key;
+}
+
+#undef MIRROR_MOD
+
+template
+struct BaseConverter {
+
+ typedef _CharType CharType;
+ typedef StringMember<_CharType, _CharProcessor> StringMemberType;
+
+ template
+ static constexpr Key charToKey(_StringMember s) {
+ return _DerivedConverter::charToKey(s.toChar());
+ }
+
+ // This implements the parser logic that is used to parse keymap
+ // strings like "c+a".
+ //
+ template
+ static constexpr Key parseKeyDefinitionString(_StringMember s) {
+
+ // C++11 constexpr functions do not allow using if/else clauses.
+ // Because of that, we use the ternary operator to express
+ // conditionals instead.
+
+ return
+ (s.length() == 0)
+ ? bad_keymap_key
+ : (s.length() == 1)
+ ? charToKey(s) // Consider the only character as ascii key
+ : s.isEscapeChar() // Is this an escape character?
+ ? (
+ s.next().isLastNonSeparator()
+ ? charToKey(s.next())
+ : bad_keymap_key
+ )
+ : s.isSeparator()
+ ? parseKeyDefinitionString(s.next()) // Ignore separator keys
+ : s.isLastNonSeparator()
+ ? charToKey(s) // The last key is treated as ASCII key
+ : s.isMirrorChar()
+ ? (
+ !s.isLastNonSeparator()
+ ? mirrorModifier(parseKeyDefinitionString(s.next()))
+ : bad_keymap_key
+ )
+ : _DerivedConverter::addModifier( // s must be a modifier key
+ parseKeyDefinitionString(s.next()), // Recurse (continue parsing the remaining string)
+ s // This character must be a modifier token
+ );
+ }
+
+ // This function allows to use character strings to define keys.
+ //
+ template
+ static constexpr Key convertToKey(_CharType const(&string) [_Size]) {
+ return _DerivedConverter
+ ::parseKeyDefinitionString(StringMemberType{string});
+ }
+
+ static constexpr Key convertToKey(_CharType c) {
+ return _DerivedConverter::charToKey(c);
+ }
+};
+
+template
+struct _CharParsingStandardFallback {
+ static constexpr bool isKeyChar(_CharType c) {
+ return false;
+ }
+ static constexpr Key charToKey(_CharType c) {
+ return bad_keymap_key;
+ }
+};
+
+} // namespace host_keymap
+} // namespace kaleidoscope
+
+#define _HOST_KEYMAP_CHECK_IF_MODIFIER(CHAR, OPERATION) s.is((CHAR)) ? true :
+#define _HOST_KEYMAP_ADD_MODIFIER(CHAR, OPERATION) s.is((CHAR)) ? (OPERATION) :
+
+#define _HOST_KEYMAP_IS_KEY_CHAR(KI, KO) (c == (KI)) ? true :
+#define _HOST_KEYMAP_MAP_KEY_CHAR_TO_KALEIDOSCOPE_KEY(KI, KO) (c == (KI)) ? (KO) :
+
+#define _HOST_KEYMAP_DEFINE_CHAR_CONVERTER(NAME, CHAR_TYPE, MODIFIER_MAP) \
+ template \
+ struct NAME \
+ : public BaseConverter { \
+ \
+ typedef BaseConverter \
+ Parent; \
+ \
+ using typename Parent::StringMemberType; \
+ using typename Parent::CharType; \
+ \
+ static constexpr bool isModifierKey(StringMemberType s) { \
+ return MODIFIER_MAP(_HOST_KEYMAP_CHECK_IF_MODIFIER) \
+ false; \
+ } \
+ \
+ static constexpr Key addModifier(Key k, StringMemberType s) { \
+ return (k == bad_keymap_key) \
+ ? bad_keymap_key /* If the input key is already */ \
+ /* the bad_keymap_key we do not */ \
+ /* touch it here. */ \
+ : MODIFIER_MAP(_HOST_KEYMAP_ADD_MODIFIER) \
+ bad_keymap_key; \
+ } \
+ };
diff --git a/src/kaleidoscope/host_keymap/test/host_keymap_test.h b/src/kaleidoscope/host_keymap/test/host_keymap_test.h
new file mode 100644
index 0000000000..c88df9d9f0
--- /dev/null
+++ b/src/kaleidoscope/host_keymap/test/host_keymap_test.h
@@ -0,0 +1,82 @@
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2013-2018 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+#include "Kaleidoscope.h"
+
+#include "kaleidoscope/host_keymap/ascii/us_en.h"
+#include "kaleidoscope/host_keymap/unicode/us_en.h"
+
+USE_HOST_KEYMAP(ascii, us_en)
+USE_HOST_KEYMAP(unicode, us_en)
+
+#define KEY_ASSERTION_(KEY_DEF, TEST_KEY, UC) \
+ static_assert( \
+ kaleidoscope::convertToKey(UC##KEY_DEF) == TEST_KEY, \
+ "host_keymap assertion failed: " #UC #KEY_DEF " != " #TEST_KEY \
+ );
+
+#define KEY_ASSERTION(KEY_DEF, TEST_KEY) \
+ KEY_ASSERTION_(KEY_DEF, TEST_KEY, ) /* ascii */ \
+ KEY_ASSERTION_(KEY_DEF, TEST_KEY, L) /* unicode */
+
+namespace kaleidoscope {
+namespace host_keymap {
+
+// The following can be used to generate compile time errors that
+// allow to determine the key_code/flags value of a key for debugging
+// purposes.
+//
+// template
+// struct _{ constexpr operator char() { return _value + 256; } }; //always overflow
+//
+// constexpr char key_code = _{};
+// constexpr char flags = _{};
+
+KEY_ASSERTION('\\', Key_Backslash)
+KEY_ASSERTION('#', LSHIFT(Key_3))
+KEY_ASSERTION('+', LSHIFT(Key_Equals))
+KEY_ASSERTION(' ', Key_Space)
+KEY_ASSERTION('\t', Key_Tab)
+KEY_ASSERTION('\n', Key_Enter)
+KEY_ASSERTION('a', Key_A)
+KEY_ASSERTION(" a", Key_A)
+KEY_ASSERTION("a ", Key_A)
+KEY_ASSERTION("ca", LCTRL(Key_A))
+KEY_ASSERTION("mca", LGUI(LCTRL(Key_A)))
+KEY_ASSERTION("c+a", LCTRL(Key_A))
+KEY_ASSERTION(" c+a", LCTRL(Key_A))
+KEY_ASSERTION("c +a", LCTRL(Key_A))
+KEY_ASSERTION("c+ a", LCTRL(Key_A))
+KEY_ASSERTION("c+a ", LCTRL(Key_A))
+
+KEY_ASSERTION("", bad_keymap_key)
+KEY_ASSERTION("c+#", bad_keymap_key)
+KEY_ASSERTION("# ", Key_Space)
+KEY_ASSERTION("c+# ", LCTRL(Key_Space))
+KEY_ASSERTION("##", LSHIFT(Key_3))
+KEY_ASSERTION("c+##", LCTRL(LSHIFT(Key_3)))
+KEY_ASSERTION("c+#+", LCTRL(LSHIFT(Key_Equals)))
+KEY_ASSERTION("#", LSHIFT(Key_3)) // If only one key is specified,
+// we accept the escape char as normal ascii char
+KEY_ASSERTION_(L"⇧", Key_LeftShift,)
+KEY_ASSERTION_(L'⇧', Key_LeftShift,)
+KEY_ASSERTION_(L"r⇧", Key_RightShift,)
+KEY_ASSERTION_(L"rr⇧", Key_LeftShift,)
+
+} // namespace host_keymap
+} // namespace kaleidoscope
diff --git a/src/kaleidoscope/host_keymap/unicode/common.h b/src/kaleidoscope/host_keymap/unicode/common.h
new file mode 100644
index 0000000000..079a0b790a
--- /dev/null
+++ b/src/kaleidoscope/host_keymap/unicode/common.h
@@ -0,0 +1,96 @@
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2013-2018 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+#include "kaleidoscope/host_keymap/host_keymap.h"
+
+namespace kaleidoscope {
+namespace host_keymap {
+namespace unicode {
+
+struct UnicodeCharProcessor {
+ static constexpr bool isEscapeChar(wchar_t c) {
+ return c == L'#';
+ }
+
+ static constexpr bool isSeparator(wchar_t c) {
+ return (c == L' ')
+ || (c == L'\t')
+ || (c == L'+');
+ }
+
+ static constexpr bool isMirrorChar(wchar_t c) {
+ return c == L'r';
+ }
+};
+
+#define _HOST_KEYMAP_CAST_ON_MODIFIERS_UNICODE(OP) \
+ \
+ OP(L's', LSHIFT(k)) \
+ OP(L'S', LSHIFT(k)) \
+ OP(L'⇧', LSHIFT(k)) \
+ \
+ OP(L'c', LCTRL(k)) \
+ OP(L'C', LCTRL(k)) \
+ OP(L'⌃', LCTRL(k)) \
+ \
+ OP(L'a', LALT(k)) \
+ OP(L'A', RALT(k)) \
+ OP(L'⌥', LALT(k)) \
+ \
+ OP(L'm', LGUI(k)) \
+ OP(L'M', LGUI(k)) \
+ OP(L'g', LGUI(k)) \
+ OP(L'G', LGUI(k)) \
+ OP(L'⌘', LGUI(k)) \
+
+// Define a UnicodeConverter template base class that any unicode keymap converters
+// are derived from by means of invoking the HOST_KEYMAP_UNICODE_LANGUAGE_CONVERTER
+// function macro.
+//
+_HOST_KEYMAP_DEFINE_CHAR_CONVERTER(
+ UnicodeConverter, wchar_t, _HOST_KEYMAP_CAST_ON_MODIFIERS_UNICODE)
+
+#undef _HOST_KEYMAP_CAST_ON_MODIFIERS_UNICODE
+
+typedef _CharParsingStandardFallback WCharParsingStandardFallback;
+
+} // namespace unicode
+} // namespace host_keymap
+} // namespace kaleidoscope
+
+#define HOST_KEYMAP_UNICODE_LANGUAGE_CONVERTER(LANGUAGE_KEYMAP, \
+ CHAR_PARSING_FALLBACK) \
+ struct Converter : public UnicodeConverter \
+ { \
+ typedef UnicodeConverter Parent; \
+ \
+ using typename Parent::StringMemberType; \
+ using typename Parent::CharType; \
+ \
+ static constexpr bool isKeyChar(wchar_t c) { \
+ return LANGUAGE_KEYMAP(_HOST_KEYMAP_IS_KEY_CHAR) \
+ CHAR_PARSING_FALLBACK::isKeyChar(c); \
+ } \
+ \
+ static constexpr Key charToKey(wchar_t c) { \
+ return LANGUAGE_KEYMAP( \
+ _HOST_KEYMAP_MAP_KEY_CHAR_TO_KALEIDOSCOPE_KEY \
+ ) \
+ CHAR_PARSING_FALLBACK::charToKey(c); \
+ } \
+ };
diff --git a/src/kaleidoscope/host_keymap/unicode/eurkey.h b/src/kaleidoscope/host_keymap/unicode/eurkey.h
new file mode 100644
index 0000000000..ffa9c809e1
--- /dev/null
+++ b/src/kaleidoscope/host_keymap/unicode/eurkey.h
@@ -0,0 +1,55 @@
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2013-2018 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+#include "kaleidoscope/key_defs.h"
+#include "kaleidoscope/key_defs_keyboard.h"
+#include "kaleidoscope/host_keymap/unicode/common.h"
+#include "kaleidoscope/host_keymap/unicode/us_en.h"
+
+// EurKey layout
+
+#define UNICODE_EURKEY_KEYMAP(OP) \
+ OP(L'¡', RALT(Key_1)) \
+ OP(L'ª', RALT(Key_2)) \
+ OP(L'°', RALT(Key_3)) \
+ OP(L'£', RALT(Key_4)) \
+ OP(L'€', RALT(Key_5)) \
+ OP(L'„', RALT(Key_8)) \
+ OP(L'”', RALT(Key_9)) \
+ OP(L'"', RALT(Key_0))
+// TODO: This is work in progress...
+
+namespace kaleidoscope {
+namespace host_keymap {
+namespace unicode {
+namespace eurkey {
+
+// This keymap partially overrides the us_en keymap.
+// Only those keys that are undefined in te above mapping are supplied by us_en.
+//
+HOST_KEYMAP_UNICODE_LANGUAGE_CONVERTER(
+ UNICODE_EURKEY_KEYMAP,
+ kaleidoscope::host_keymap::unicode::us_en::Converter
+)
+
+} // namespace eurkey
+} // namespace unicode
+} // namespace host_keymap
+} // namespace kaleidoscope
+
+#undef UNICODE_EURKEY_KEYMAP
diff --git a/src/kaleidoscope/host_keymap/unicode/us_en.h b/src/kaleidoscope/host_keymap/unicode/us_en.h
new file mode 100644
index 0000000000..4269a2561d
--- /dev/null
+++ b/src/kaleidoscope/host_keymap/unicode/us_en.h
@@ -0,0 +1,173 @@
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2013-2018 Keyboard.io, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+#pragma once
+
+#include "kaleidoscope/key_defs.h"
+#include "kaleidoscope/key_defs_keyboard.h"
+#include "kaleidoscope/host_keymap/unicode/common.h"
+
+#define UNICODE_US_EN_KEYMAP(OP) \
+ \
+ /* Printable characters */ \
+ OP(L'\n', Key_Enter) \
+ OP(L'\t', Key_Tab) \
+ \
+ OP(L'!', LSHIFT(Key_1)) \
+ OP(L'"', Key_Quote) \
+ OP(L'#', LSHIFT(Key_3)) \
+ OP(L'$', LSHIFT(Key_4)) \
+ OP(L'%', LSHIFT(Key_5)) \
+ OP(L'&', LSHIFT(Key_7)) \
+ OP(L'\'', Key_Quote) \
+ OP(L'(', LSHIFT(Key_9)) \
+ OP(L')', LSHIFT(Key_0)) \
+ OP(L'*', LSHIFT(Key_8)) \
+ OP(L'+', LSHIFT(Key_Equals)) \
+ OP(L',', Key_Comma) \
+ OP(L'-', Key_Minus) \
+ OP(L'.', Key_Period) \
+ OP(L'/', Key_Slash) \
+ OP(L'0', Key_0) \
+ OP(L'1', Key_1) \
+ OP(L'2', Key_2) \
+ OP(L'3', Key_3) \
+ OP(L'4', Key_4) \
+ OP(L'5', Key_5) \
+ OP(L'6', Key_6) \
+ OP(L'7', Key_7) \
+ OP(L'8', Key_8) \
+ OP(L'9', Key_9) \
+ OP(L':', LSHIFT(Key_Semicolon)) \
+ OP(L';', Key_Semicolon) \
+ OP(L'<', LSHIFT(Key_Comma)) \
+ OP(L'=', Key_Equals) \
+ OP(L'>', LSHIFT(Key_Period)) \
+ OP(L'?', LSHIFT(Key_Slash)) \
+ OP(L'@', LSHIFT(Key_2)) \
+ \
+ OP(L'A', LSHIFT(Key_A)) \
+ OP(L'B', LSHIFT(Key_B)) \
+ OP(L'C', LSHIFT(Key_C)) \
+ OP(L'D', LSHIFT(Key_D)) \
+ OP(L'E', LSHIFT(Key_E)) \
+ OP(L'F', LSHIFT(Key_F)) \
+ OP(L'G', LSHIFT(Key_G)) \
+ OP(L'H', LSHIFT(Key_H)) \
+ OP(L'I', LSHIFT(Key_I)) \
+ OP(L'J', LSHIFT(Key_J)) \
+ OP(L'K', LSHIFT(Key_K)) \
+ OP(L'L', LSHIFT(Key_L)) \
+ OP(L'M', LSHIFT(Key_M)) \
+ OP(L'N', LSHIFT(Key_N)) \
+ OP(L'O', LSHIFT(Key_O)) \
+ OP(L'P', LSHIFT(Key_P)) \
+ OP(L'Q', LSHIFT(Key_Q)) \
+ OP(L'R', LSHIFT(Key_R)) \
+ OP(L'S', LSHIFT(Key_S)) \
+ OP(L'T', LSHIFT(Key_T)) \
+ OP(L'U', LSHIFT(Key_U)) \
+ OP(L'V', LSHIFT(Key_V)) \
+ OP(L'W', LSHIFT(Key_W)) \
+ OP(L'X', LSHIFT(Key_X)) \
+ OP(L'Y', LSHIFT(Key_Y)) \
+ OP(L'Z', LSHIFT(Key_Z)) \
+ \
+ OP(L'[', Key_LeftBracket) \
+ OP(L'\\', Key_Backslash) \
+ OP(L']', Key_RightBracket) \
+ OP(L'^', LSHIFT(Key_6)) \
+ OP(L'_', LSHIFT(Key_Minus)) \
+ OP(L'`', Key_Backtick) \
+ \
+ OP(L'a', Key_A) \
+ OP(L'b', Key_B) \
+ OP(L'c', Key_C) \
+ OP(L'd', Key_D) \
+ OP(L'e', Key_E) \
+ OP(L'f', Key_F) \
+ OP(L'g', Key_G) \
+ OP(L'h', Key_H) \
+ OP(L'i', Key_I) \
+ OP(L'j', Key_J) \
+ OP(L'k', Key_K) \
+ OP(L'l', Key_L) \
+ OP(L'm', Key_M) \
+ OP(L'n', Key_N) \
+ OP(L'o', Key_O) \
+ OP(L'p', Key_P) \
+ OP(L'q', Key_Q) \
+ OP(L'r', Key_R) \
+ OP(L's', Key_S) \
+ OP(L't', Key_T) \
+ OP(L'u', Key_U) \
+ OP(L'v', Key_V) \
+ OP(L'w', Key_W) \
+ OP(L'x', Key_X) \
+ OP(L'y', Key_Y) \
+ OP(L'z', Key_Z) \
+ \
+ OP(L'{', LSHIFT(Key_LeftBracket)) \
+ OP(L'|', LSHIFT(Key_Backslash)) \
+ OP(L'}', LSHIFT(Key_RightBracket)) \
+ OP(L'~', Key_Minus) \
+ OP(L' ', Key_Spacebar) \
+ \
+ /* Non printable characters */ \
+ OP(L'⎋', Key_Escape) \
+ OP(L'⌫', Key_Backspace) \
+ OP(L'↹', Key_Tab) \
+ OP(L'␣', Key_Spacebar) \
+ OP(L'⇪', Key_CapsLock) \
+ OP(L'↩', Key_Return) \
+ OP(L'⎆', Key_Enter) \
+ OP(L'⎙', Key_PrintScreen) \
+ OP(L'⤓', Key_ScrollLock) \
+ OP(L'⇳', Key_ScrollLock) \
+ OP(L'⎉', Key_Pause) \
+ OP(L'⎀', Key_Insert) \
+ OP(L'↖', Key_Home) \
+ OP(L'⇞', Key_PageUp) \
+ OP(L'⌦', Key_Delete) \
+ OP(L'↘', Key_End) \
+ OP(L'⇟', Key_PageDown) \
+ OP(L'→', Key_RightArrow) \
+ OP(L'←', Key_LeftArrow) \
+ OP(L'↓', Key_DownArrow) \
+ OP(L'↑', Key_UpArrow) \
+ OP(L'⇭', Key_KeypadNumLock) \
+ OP(L'⌽', Key_Power) \
+ OP(L'⌃', Key_LeftControl) \
+ OP(L'⌘', Key_LeftGui) \
+ OP(L'⇧', Key_LeftShift) \
+ OP(L'⌥', Key_LeftAlt)
+
+namespace kaleidoscope {
+namespace host_keymap {
+namespace unicode {
+namespace us_en {
+
+HOST_KEYMAP_UNICODE_LANGUAGE_CONVERTER(
+ UNICODE_US_EN_KEYMAP,
+ WCharParsingStandardFallback
+)
+
+} // namespace us_en
+} // namespace unicode
+} // namespace host_keymap
+} // namespace kaleidoscope
+
+#undef ASCII_US_EN_KEYMAP