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