diff --git a/doc/plugin/Unicode.md b/doc/plugin/Unicode.md new file mode 100644 index 00000000..12aa8013 --- /dev/null +++ b/doc/plugin/Unicode.md @@ -0,0 +1,116 @@ +# Kaleidoscope-Unicode + +The `Unicode` extension makes it easier to write plugins that input Unicode +symbols on the host. Because inputting Unicode varies from OS to OS, this helper +library was made to hide most of the differences. All one has to do, is set up +the `HostOS` singleton properly, and the `Unicode` library will handle the rest, +by providing an easy interface for inputting Unicode symbols by their 32-bit +codepoints. + +## Using the extension + +Using the extension is as simple as including the header, registering it with +`Kaleidoscope.use()`, and then using any of the methods provided by the +`Unicode` singleton object. + +```c++ +#include +#include +#include +#include + +KALEIDOSCOPE_INIT_PLUGINS(EEPROMSettings, HostOS, Unicode); + +void setup() { + Kaleidoscope.setup(); + + Unicode.type(0x2328); +} +``` + +## Extension methods + +The extension provides a number of methods on the `Unicode` object, but also has +symbols that can be [overridden](#overrideable-methods), to add custom +functionality. + +### `.type(code_point)` + +> Starts the Unicode input method using the [`.start()`](#start) method, inputs +> the `code_point` using [`.typeCode()`](#typeCode), and finishes up with +> the [`.end()`](#end) method. For each hexadecimal digit sent to the host, +> the [`.input()`](#input) method will also be called. +> +> This method is most useful when one knows the code point of the Unicode symbol +> to enter ahead of time, when the code point does not depend on anything else. + +### `.typeCode(code_point)` + +> Inputs the hex codes for `code_point`, and the hex codes only. Use when the +> input method is to be started and ended separately. +> +> For example, a macro that starts Unicode input, and switches to a layer full +> of macros that send the hex codes is one scenario where this function is of +> use. + +### `.start()` + +> Starts the Unicode input method. The way it starts it, depends on the host +> operating system. + +### `.input()` + +> If the host operating system requires keys being held during the Unicode +> input, this function will hold them for us. + +### `.end()` + +> Finishes the Unicode input method, in an OS-specific way. + +## Overrideable methods + +### `hexToKey(hex_digit)` + +> A function that returns a `Key` struct, given a 8-bit hex digit. For most +> uses, the built-in version of this function is sufficient, but if the keymap +> on the OS-side has any of the hexadecimal symbols on other scancodes than +> QWERTY, this function should be overridden to use the correct scan codes. + +### `unicodeCustomStart()` + +> If the host OS type is set to `kaleidoscope::hostos::Custom`, then this function will +> be called whenever the [`.start()`](#start) method is called. The default +> implementation does nothing, and should be overridden to implement the custom +> magic needed to enter unicode input mode. + +### `unicodeCustomInput()` + +> If the host OS type is set to `kaleidoscope::hostos::Custom`, then this function will +> be called whenever the [`.input()`](#input) method is called. The default +> implementation does nothing, and should be overridden to implement the custom +> magic needed while inputting the hex code itself (such as holding additional +> keys). + +### `unicodeCustomEnd()` + +> If the host OS type is set to `kaleidoscope::hostos::Custom`, then this function will +> be called whenever the [`.end()`](#end) method is called. The default +> implementation does nothing, and should be overridden to implement the custom +> magic needed to leave unicode input mode. + +## Dependencies + +* [Kaleidoscope-HostOS](HostOS.md) + +## Other Configuration + +On OS X/macOS, you'll need to change the input method to be "Unicode Hex Input". +You can do this by going to System Preferences > Keyboard > Input Sources, clicking +the `+` button, selecting it from the list, then setting it as the active input method. + +## Further reading + +Starting from the [example][plugin:example] is the recommended way of getting +started with the plugin. + + [plugin:example]: ../../examples/Unicode/Unicode.ino diff --git a/examples/Unicode/Unicode.ino b/examples/Unicode/Unicode.ino new file mode 100644 index 00000000..36c44419 --- /dev/null +++ b/examples/Unicode/Unicode.ino @@ -0,0 +1,76 @@ +/* -*- 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 +#include +#include "Kaleidoscope-Macros.h" +#include + +enum { MACRO_KEYBOARD_EMOJI }; + +// *INDENT-OFF* + +const Key keymaps[][ROWS][COLS] PROGMEM = { + [0] = KEYMAP_STACKED + ( + Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey, + Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab, + Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G, + Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape, + + Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift, + Key_skip, + + M(MACRO_KEYBOARD_EMOJI), Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip, + Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals, + Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote, + Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus, + + Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl, + Key_skip), +}; + +// *INDENT-ON* + +static void unicode(uint32_t character, uint8_t keyState) { + if (keyToggledOn(keyState)) { + Unicode.type(character); + } +} + +const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) { + switch (macroIndex) { + case MACRO_KEYBOARD_EMOJI: + unicode(0x2328, keyState); + break; + } + return MACRO_NONE; +} + +KALEIDOSCOPE_INIT_PLUGINS(EEPROMSettings, + HostOS, + Macros, + Unicode); + +void setup() { + Kaleidoscope.setup(); +} + +void loop() { + Kaleidoscope.loop(); +} diff --git a/src/Kaleidoscope-Unicode.h b/src/Kaleidoscope-Unicode.h new file mode 100644 index 00000000..83c71138 --- /dev/null +++ b/src/Kaleidoscope-Unicode.h @@ -0,0 +1,20 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-Unicode -- Unicode input helpers + * Copyright (C) 2016, 2017 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 diff --git a/src/kaleidoscope/plugin/Unicode.cpp b/src/kaleidoscope/plugin/Unicode.cpp new file mode 100644 index 00000000..c79bc8e2 --- /dev/null +++ b/src/kaleidoscope/plugin/Unicode.cpp @@ -0,0 +1,193 @@ +/* -*- 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/hid.h" + +namespace kaleidoscope { +namespace plugin { + +void Unicode::start(void) { + switch (::HostOS.os()) { + case hostos::LINUX: + hid::pressRawKey(Key_LeftControl); + hid::pressRawKey(Key_LeftShift); + hid::pressRawKey(Key_U); + hid::sendKeyboardReport(); + hid::releaseRawKey(Key_LeftControl); + hid::releaseRawKey(Key_LeftShift); + hid::releaseRawKey(Key_U); + hid::sendKeyboardReport(); + break; + case hostos::WINDOWS: + hid::pressRawKey(Key_LeftAlt); + hid::sendKeyboardReport(); + hid::pressRawKey(Key_KeypadAdd); + hid::sendKeyboardReport(); + hid::releaseRawKey(Key_KeypadAdd); + hid::sendKeyboardReport(); + break; + case hostos::OSX: + hid::pressRawKey(Key_LeftAlt); + break; + default: + unicodeCustomStart(); + break; + } +} + +void Unicode::input(void) { + switch (::HostOS.os()) { + case hostos::LINUX: + break; + case hostos::WINDOWS: + case hostos::OSX: + hid::pressRawKey(Key_LeftAlt); + break; + default: + unicodeCustomInput(); + break; + } +} + +void Unicode::end(void) { + switch (::HostOS.os()) { + case hostos::LINUX: + hid::pressRawKey(Key_Spacebar); + hid::sendKeyboardReport(); + hid::releaseRawKey(Key_Spacebar); + hid::sendKeyboardReport(); + break; + case hostos::WINDOWS: + case hostos::OSX: + hid::releaseRawKey(Key_LeftAlt); + hid::sendKeyboardReport(); + break; + default: + unicodeCustomEnd(); + break; + } +} + +void Unicode::typeCode(uint32_t unicode) { + bool on_zero_start = true; + for (int8_t i = 7; i >= 0; i--) { + if (i <= 3) { + on_zero_start = false; + } + uint8_t digit = ((unicode >> (i * 4)) & 0xF); + if (digit == 0) { + if (on_zero_start == false) { + Key key; + if (::HostOS.os() == hostos::WINDOWS) { + key = hexToKeysWithNumpad(digit); + } else { + key = hexToKey(digit); + } + input(); + hid::pressRawKey(key); + hid::sendKeyboardReport(); + input(); + hid::releaseRawKey(key); + hid::sendKeyboardReport(); + } + } else { + Key key; + if (::HostOS.os() == hostos::WINDOWS) { + key = hexToKeysWithNumpad(digit); + } else { + key = hexToKey(digit); + } + input(); + hid::pressRawKey(key); + hid::sendKeyboardReport(); + input(); + hid::releaseRawKey(key); + hid::sendKeyboardReport(); + on_zero_start = false; + } + delay(5); + } +} + +void Unicode::type(uint32_t unicode) { + start(); + typeCode(unicode); + end(); +} + +} +} + +__attribute__((weak)) Key hexToKey(uint8_t hex) { + uint8_t m; + if (hex == 0x0) { + return Key_0; + } + if (hex < 0xA) { + m = Key_1.keyCode + (hex - 0x1); + } else { + m = Key_A.keyCode + (hex - 0xA); + } + return { m, KEY_FLAGS }; +} + +__attribute__((weak)) Key hexToKeysWithNumpad(uint8_t hex) { + uint8_t m; + if (hex == 0x0) { + return Key_Keypad0; + } + if (hex < 0xA) { + m = Key_Keypad1.keyCode + (hex - 0x1); + } else { + switch (hex) { + case 0xA: + m = Key_A.keyCode; + break; + case 0xB: + m = Key_B.keyCode; + break; + case 0xC: + m = Key_C.keyCode; + break; + case 0xD: + m = Key_D.keyCode; + break; + case 0xE: + m = Key_E.keyCode; + break; + case 0xF: + m = Key_F.keyCode; + break; + default: + m = Key_NoKey.keyCode; + break; + } + } + return { m, KEY_FLAGS }; +} + +__attribute__((weak)) void unicodeCustomStart(void) { +} + +__attribute__((weak)) void unicodeCustomEnd(void) { +} + +__attribute__((weak)) void unicodeCustomInput(void) { +} + +kaleidoscope::plugin::Unicode Unicode; diff --git a/src/kaleidoscope/plugin/Unicode.h b/src/kaleidoscope/plugin/Unicode.h new file mode 100644 index 00000000..49a94be0 --- /dev/null +++ b/src/kaleidoscope/plugin/Unicode.h @@ -0,0 +1,46 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace kaleidoscope { +namespace plugin { +class Unicode : public kaleidoscope::Plugin { + public: + Unicode(void) {} + + static void start(void); + static void input(void); + static void end(void); + + static void type(uint32_t unicode); + static void typeCode(uint32_t unicode); +}; +} +} + +Key hexToKey(uint8_t hex); +Key hexToKeysWithNumpad(uint8_t hex); + +void unicodeCustomStart(void); +void unicodeCustomEnd(void); +void unicodeCustomInput(void); + +extern kaleidoscope::plugin::Unicode Unicode;