From 95b7a7b684395e4a05ade2b135685aea810d8c45 Mon Sep 17 00:00:00 2001 From: iliana etaoin Date: Sat, 28 May 2022 15:19:25 -0700 Subject: [PATCH 1/5] Add PrefixLayer plugin Signed-off-by: iliana etaoin --- .../Keystrokes/PrefixLayer/PrefixLayer.ino | 70 ++++++ examples/Keystrokes/PrefixLayer/sketch.json | 6 + plugins/Kaleidoscope-PrefixLayer/README.md | 60 +++++ .../library.properties | 7 + .../src/Kaleidoscope-PrefixLayer.h | 21 ++ .../src/kaleidoscope/plugin/PrefixLayer.cpp | 77 ++++++ .../src/kaleidoscope/plugin/PrefixLayer.h | 54 ++++ tests/plugins/PrefixLayer/basic/basic.ino | 68 ++++++ tests/plugins/PrefixLayer/basic/sketch.json | 6 + tests/plugins/PrefixLayer/basic/test.ktest | 231 ++++++++++++++++++ 10 files changed, 600 insertions(+) create mode 100644 examples/Keystrokes/PrefixLayer/PrefixLayer.ino create mode 100644 examples/Keystrokes/PrefixLayer/sketch.json create mode 100644 plugins/Kaleidoscope-PrefixLayer/README.md create mode 100644 plugins/Kaleidoscope-PrefixLayer/library.properties create mode 100644 plugins/Kaleidoscope-PrefixLayer/src/Kaleidoscope-PrefixLayer.h create mode 100644 plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp create mode 100644 plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h create mode 100644 tests/plugins/PrefixLayer/basic/basic.ino create mode 100644 tests/plugins/PrefixLayer/basic/sketch.json create mode 100644 tests/plugins/PrefixLayer/basic/test.ktest diff --git a/examples/Keystrokes/PrefixLayer/PrefixLayer.ino b/examples/Keystrokes/PrefixLayer/PrefixLayer.ino new file mode 100644 index 00000000..f6a0ccac --- /dev/null +++ b/examples/Keystrokes/PrefixLayer/PrefixLayer.ino @@ -0,0 +1,70 @@ +// -*- mode: c++ -*- + +/* This example demonstrates the Model 01 / Model 100 butterfly logo key as a + * tmux prefix key. When the key is held, Ctrl-B is pressed prior to the key + * you pressed. + * + * This example also demonstrates the purpose of using an entire layer for this + * plugin: the h/j/k/l keys in the TMUX layer are swapped for arrow keys to + * make switching between panes easier. + */ + +#include +#include + +enum { + PRIMARY, + TMUX, +}; // layers + +/* Used in setup() below. */ +static const kaleidoscope::plugin::PrefixLayer::Entry prefix_layers[] PROGMEM = { + kaleidoscope::plugin::PrefixLayer::Entry(TMUX, LCTRL(Key_B)), +}; + +// clang-format off +KEYMAPS( + [PRIMARY] = KEYMAP_STACKED + (XXX, Key_1, Key_2, Key_3, Key_4, Key_5, XXX, + 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, + XXX, + + XXX, Key_6, Key_7, Key_8, Key_9, Key_0, XXX, + 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, + ShiftToLayer(TMUX), Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus, + Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl, + XXX), + + [TMUX] = KEYMAP_STACKED + (___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___, + + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___), +) +// clang-format on + +KALEIDOSCOPE_INIT_PLUGINS(PrefixLayer); + +void setup() { + Kaleidoscope.setup(); + /* Configure the previously-defined prefix layers. */ + PrefixLayer.prefix_layers = prefix_layers; + PrefixLayer.prefix_layers_length = 1; +} + +void loop() { + Kaleidoscope.loop(); +} diff --git a/examples/Keystrokes/PrefixLayer/sketch.json b/examples/Keystrokes/PrefixLayer/sketch.json new file mode 100644 index 00000000..884ed009 --- /dev/null +++ b/examples/Keystrokes/PrefixLayer/sketch.json @@ -0,0 +1,6 @@ +{ + "cpu": { + "fqbn": "keyboardio:avr:model01", + "port": "" + } +} diff --git a/plugins/Kaleidoscope-PrefixLayer/README.md b/plugins/Kaleidoscope-PrefixLayer/README.md new file mode 100644 index 00000000..c0d6f8bc --- /dev/null +++ b/plugins/Kaleidoscope-PrefixLayer/README.md @@ -0,0 +1,60 @@ +# PrefixLayer + +The `PrefixLayer` plugin allows you to easily create a keyboard layer designed +for use with programs that use a prefix key, such as tmux or screen. When a key +in a prefix layer is pressed, the prefix is injected first, then the key in +that layer is pressed. + +## Using the plugin + +You will need to define a keymap layer and configure the plugin to use that +layer with a prefix key. You can then include the plugin's header and set the +`.prefix_layers` property. + +```c++ +#include +#include + +enum { + PRIMARY, + TMUX, +}; // layers + +static const kaleidoscope::plugin::PrefixLayer::Entry prefix_layers[] PROGMEM = { + kaleidoscope::plugin::PrefixLayer::Entry(TMUX, LCTRL(Key_B)), +}; + +KALEIDOSCOPE_INIT_PLUGINS(LEDControl, PrefixLayer); + +void setup() { + Kaleidoscope.setup(); + PrefixLayer.prefix_layers = prefix_layers; + PrefixLayer.prefix_layers_length = 1; +} +``` + +## Plugin methods + +The plugin provides a `PrefixLayer` object, which has the following methods +and properties: + +### `.prefix_layers` + +> A `kaleidoscope::plugin::PrefixLayer::Entry` array that maps layers to prefix +> keys. The `Entry` constructor accepts `Entry(layer_number, prefix_key)`. This +> array must be stored in `PROGMEM` as shown above. +> +> Defaults to an empty array. + +### `.prefix_layers_length` + +> Length of the `prefix_layers` array. +> +> Defaults to *0* + +## Further reading + +Starting from the [example][plugin:example] is the recommended way of getting +started with the plugin. + + [plugin:example]: /examples/Keystrokes/PrefixLayer/PrefixLayer.ino diff --git a/plugins/Kaleidoscope-PrefixLayer/library.properties b/plugins/Kaleidoscope-PrefixLayer/library.properties new file mode 100644 index 00000000..7b38d9c0 --- /dev/null +++ b/plugins/Kaleidoscope-PrefixLayer/library.properties @@ -0,0 +1,7 @@ +name=Kaleidoscope-PrefixLayer +version=0.0.0 +sentence=Sends a prefix key for every key in a layer. +maintainer=Kaleidoscope's Developers +url=https://github.com/keyboardio/Kaleidoscope +author=iliana etaoin, James Cash +paragraph= diff --git a/plugins/Kaleidoscope-PrefixLayer/src/Kaleidoscope-PrefixLayer.h b/plugins/Kaleidoscope-PrefixLayer/src/Kaleidoscope-PrefixLayer.h new file mode 100644 index 00000000..0f9875cf --- /dev/null +++ b/plugins/Kaleidoscope-PrefixLayer/src/Kaleidoscope-PrefixLayer.h @@ -0,0 +1,21 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-PrefixLayer -- Sends a prefix key for every key in a layer. + * Copyright (C) 2017, 2022 iliana etaoin + * Copyright (C) 2017 James Cash + * + * 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/plugin/PrefixLayer.h" // IWYU pragma: export diff --git a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp new file mode 100644 index 00000000..18cc0c0b --- /dev/null +++ b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp @@ -0,0 +1,77 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-PrefixLayer -- Sends a prefix key for every key in a layer. + * Copyright (C) 2017, 2022 iliana etaoin + * Copyright (C) 2017 James Cash + * + * 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 "kaleidoscope/plugin/PrefixLayer.h" + +#include // for PROGMEM +#include // for uint8_t + +#include "kaleidoscope/KeyEvent.h" // for KeyEvent +#include "kaleidoscope/Runtime.h" // for Runtime +#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult, EventHandlerResult::OK +#include "kaleidoscope/key_defs.h" // for Key +#include "kaleidoscope/keyswitch_state.h" // for keyToggledOn +#include "kaleidoscope/layers.h" // for Layer + +namespace kaleidoscope { +namespace plugin { + +static const PrefixLayer::Entry prefix_layers_default_[] PROGMEM = {}; +const PrefixLayer::Entry *PrefixLayer::prefix_layers = prefix_layers_default_; +uint8_t PrefixLayer::prefix_layers_length = 0; +bool PrefixLayer::clear_modifiers_ = false; + +EventHandlerResult PrefixLayer::onKeyEvent(KeyEvent &event) { + if (event.state & INJECTED) + return EventHandlerResult::OK; + if (!keyToggledOn(event.state)) + return EventHandlerResult::OK; + if (event.key == Key_NoKey) + return EventHandlerResult::OK; + if (!event.key.isKeyboardKey()) + return EventHandlerResult::OK; + if (event.key.isKeyboardModifier()) + return EventHandlerResult::OK; + + for (uint8_t i = 0; i < prefix_layers_length; i++) { + if (Layer.isActive(prefix_layers[i].layer)) { + clear_modifiers_ = true; + Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), IS_PRESSED | INJECTED, prefix_layers[i].prefix}); + Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), WAS_PRESSED | INJECTED, prefix_layers[i].prefix}); + clear_modifiers_ = false; + } + } + + return EventHandlerResult::OK; +} + +EventHandlerResult PrefixLayer::beforeReportingState(const KeyEvent &event) { + if (clear_modifiers_) { + for (uint8_t i = HID_KEYBOARD_FIRST_MODIFIER; i <= HID_KEYBOARD_LAST_MODIFIER; i++) { + Runtime.hid().keyboard().releaseKey(Key(i, KEY_FLAGS)); + } + Runtime.hid().keyboard().pressModifiers(event.key); + } + + return EventHandlerResult::OK; +} + +} // namespace plugin +} // namespace kaleidoscope + +kaleidoscope::plugin::PrefixLayer PrefixLayer; diff --git a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h new file mode 100644 index 00000000..196e1a70 --- /dev/null +++ b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h @@ -0,0 +1,54 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-PrefixLayer -- Sends a prefix key for every key in a layer. + * Copyright (C) 2017, 2022 iliana etaoin + * Copyright (C) 2017 James Cash + * + * 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 // for uint8_t + +#include "kaleidoscope/KeyEvent.h" // for KeyEvent +#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult +#include "kaleidoscope/key_defs.h" // for Key +#include "kaleidoscope/plugin.h" // for Plugin + +namespace kaleidoscope { +namespace plugin { + +class PrefixLayer : public Plugin { + public: + EventHandlerResult onKeyEvent(KeyEvent &event); + EventHandlerResult beforeReportingState(const KeyEvent &event); + + struct Entry { + uint8_t layer; + Key prefix; + + constexpr Entry(uint8_t layer, Key prefix) + : layer(layer), prefix(prefix) {} + }; + + static const Entry *prefix_layers; + static uint8_t prefix_layers_length; + + private: + static bool clear_modifiers_; +}; + +} // namespace plugin +} // namespace kaleidoscope + +extern kaleidoscope::plugin::PrefixLayer PrefixLayer; diff --git a/tests/plugins/PrefixLayer/basic/basic.ino b/tests/plugins/PrefixLayer/basic/basic.ino new file mode 100644 index 00000000..76a067b9 --- /dev/null +++ b/tests/plugins/PrefixLayer/basic/basic.ino @@ -0,0 +1,68 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2022 iliana etaoin + * + * 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 + +// clang-format off +KEYMAPS( + [0] = KEYMAP_STACKED + (ShiftToLayer(1), ___, ___, ___, ___, ___, ___, + Key_LeftControl, Key_LeftShift, ___, ___, ___, ___, ___, + Key_H, Key_J, Key_K, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___, + + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___), + + [1] = KEYMAP_STACKED + (___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, Key_DownArrow, XXX, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___, + + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___), +) +// clang-format on + +static const kaleidoscope::plugin::PrefixLayer::Entry prefix_layers[] PROGMEM = { + kaleidoscope::plugin::PrefixLayer::Entry(1, LCTRL(Key_B)), +}; + +KALEIDOSCOPE_INIT_PLUGINS(PrefixLayer); + +void setup() { + Kaleidoscope.setup(); + PrefixLayer.prefix_layers = prefix_layers; + PrefixLayer.prefix_layers_length = 1; +} + +void loop() { + Kaleidoscope.loop(); +} diff --git a/tests/plugins/PrefixLayer/basic/sketch.json b/tests/plugins/PrefixLayer/basic/sketch.json new file mode 100644 index 00000000..8cc86922 --- /dev/null +++ b/tests/plugins/PrefixLayer/basic/sketch.json @@ -0,0 +1,6 @@ +{ + "cpu": { + "fqbn": "keyboardio:virtual:model01", + "port": "" + } +} diff --git a/tests/plugins/PrefixLayer/basic/test.ktest b/tests/plugins/PrefixLayer/basic/test.ktest new file mode 100644 index 00000000..bb201048 --- /dev/null +++ b/tests/plugins/PrefixLayer/basic/test.ktest @@ -0,0 +1,231 @@ +VERSION 1 + +KEYSWITCH PREFIX_B 0 0 +KEYSWITCH CTRL 1 0 +KEYSWITCH SHIFT 1 1 +KEYSWITCH H 2 0 +KEYSWITCH J 2 1 +KEYSWITCH K 2 2 + +# ============================================================================== +NAME Prefix layer passthrough + +RUN 4 ms +PRESS PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after pressing PREFIX_B + +RUN 4 ms +PRESS H +RUN 1 cycle +EXPECT keyboard-report Key_LCtrl # press Ctrl +EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held +EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report empty # release Ctrl +EXPECT keyboard-report Key_H # press H + +RUN 4 ms +RELEASE H +RUN 1 cycle +EXPECT keyboard-report empty # release H + +RUN 4 ms +RELEASE PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after releasing PREFIX_B + +# ============================================================================== +NAME Prefix layer explicit + +RUN 4 ms +PRESS PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after pressing PREFIX_B + +RUN 4 ms +PRESS J +RUN 1 cycle +EXPECT keyboard-report Key_LCtrl # press Ctrl +EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held +EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report empty # release Ctrl +EXPECT keyboard-report Key_DownArrow # press J + +RUN 4 ms +RELEASE J +RUN 1 cycle +EXPECT keyboard-report empty # release J + +RUN 4 ms +RELEASE PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after releasing PREFIX_B + +# ============================================================================== +NAME Prefix layer masked + +RUN 4 ms +PRESS PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after pressing PREFIX_B + +RUN 4 ms +PRESS K +RUN 1 cycle +EXPECT no keyboard-report # press K (masked) + +RUN 4 ms +RELEASE K +RUN 1 cycle +EXPECT no keyboard-report # release K (masked) + +RUN 4 ms +RELEASE PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after releasing PREFIX_B + +# ============================================================================== +NAME Prefix layer same modifier first + +RUN 4 ms +PRESS CTRL +RUN 1 cycle +EXPECT keyboard-report Key_LCtrl # press Ctrl + +RUN 4 ms +PRESS PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after pressing PREFIX_B + +RUN 4 ms +PRESS H +RUN 1 cycle +EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held +EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report Key_LCtrl Key_H # press H + +RUN 4 ms +RELEASE H +RUN 1 cycle +EXPECT keyboard-report Key_LCtrl # release H + +RUN 4 ms +RELEASE PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after releasing PREFIX_B + +RUN 4 ms +RELEASE CTRL +RUN 1 cycle +EXPECT keyboard-report empty # release Ctrl + +# ============================================================================== +NAME Prefix layer same modifier second + +RUN 4 ms +PRESS PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after pressing PREFIX_B + +RUN 4 ms +PRESS CTRL +RUN 1 cycle +EXPECT keyboard-report Key_LCtrl # press Ctrl + +RUN 4 ms +PRESS H +RUN 1 cycle +EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held +EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report Key_LCtrl Key_H # press H + +RUN 4 ms +RELEASE H +RUN 1 cycle +EXPECT keyboard-report Key_LCtrl # release H + +RUN 4 ms +RELEASE CTRL +RUN 1 cycle +EXPECT keyboard-report empty # release Ctrl + +RUN 4 ms +RELEASE PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after releasing PREFIX_B + +# ============================================================================== +NAME Prefix layer different modifier first + +RUN 4 ms +PRESS SHIFT +RUN 1 cycle +EXPECT keyboard-report Key_LShift # press Shift + +RUN 4 ms +PRESS PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after pressing PREFIX_B + +RUN 4 ms +PRESS H +RUN 1 cycle +EXPECT keyboard-report Key_LShift Key_LCtrl # press Ctrl +EXPECT keyboard-report Key_LCtrl # release pressed shift +EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held +EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report Key_LShift # restoring pressed Shift +EXPECT keyboard-report Key_LShift Key_H # press H + +RUN 4 ms +RELEASE H +RUN 1 cycle +EXPECT keyboard-report Key_LShift # release H + +RUN 4 ms +RELEASE PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after releasing PREFIX_B + +RUN 4 ms +RELEASE SHIFT +RUN 1 cycle +EXPECT keyboard-report empty # release Ctrl + +# ============================================================================== +NAME Prefix layer different modifier second + +RUN 4 ms +PRESS PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after pressing PREFIX_B + +RUN 4 ms +PRESS SHIFT +RUN 1 cycle +EXPECT keyboard-report Key_LShift # press Shift + +RUN 4 ms +PRESS H +RUN 1 cycle +EXPECT keyboard-report Key_LShift Key_LCtrl # press Ctrl +EXPECT keyboard-report Key_LCtrl # release pressed shift +EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held +EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report Key_LShift # restoring pressed Shift +EXPECT keyboard-report Key_LShift Key_H # press H + +RUN 4 ms +RELEASE H +RUN 1 cycle +EXPECT keyboard-report Key_LShift # release H + +RUN 4 ms +RELEASE SHIFT +RUN 1 cycle +EXPECT keyboard-report empty # release Ctrl + +RUN 4 ms +RELEASE PREFIX_B +RUN 1 cycle +EXPECT no keyboard-report # no report after releasing PREFIX_B From 0810321272579bd606b9add0b862253d53eb388b Mon Sep 17 00:00:00 2001 From: iliana etaoin Date: Sat, 28 May 2022 15:36:22 -0700 Subject: [PATCH 2/5] Fix code style in PrefixLayer example Signed-off-by: iliana etaoin --- examples/Keystrokes/PrefixLayer/PrefixLayer.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Keystrokes/PrefixLayer/PrefixLayer.ino b/examples/Keystrokes/PrefixLayer/PrefixLayer.ino index f6a0ccac..bb5efbca 100644 --- a/examples/Keystrokes/PrefixLayer/PrefixLayer.ino +++ b/examples/Keystrokes/PrefixLayer/PrefixLayer.ino @@ -61,7 +61,7 @@ KALEIDOSCOPE_INIT_PLUGINS(PrefixLayer); void setup() { Kaleidoscope.setup(); /* Configure the previously-defined prefix layers. */ - PrefixLayer.prefix_layers = prefix_layers; + PrefixLayer.prefix_layers = prefix_layers; PrefixLayer.prefix_layers_length = 1; } From a960f5a0cb9276f6ff0235a07ba192460e437b12 Mon Sep 17 00:00:00 2001 From: iliana etaoin Date: Sun, 29 May 2022 11:00:03 -0700 Subject: [PATCH 3/5] PrefixLayer: prefer getter/setter methods Signed-off-by: iliana etaoin --- .../Keystrokes/PrefixLayer/PrefixLayer.ino | 3 +-- .../src/kaleidoscope/plugin/PrefixLayer.cpp | 26 ++++++++++++------- .../src/kaleidoscope/plugin/PrefixLayer.h | 9 ++++--- tests/plugins/PrefixLayer/basic/basic.ino | 3 +-- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/examples/Keystrokes/PrefixLayer/PrefixLayer.ino b/examples/Keystrokes/PrefixLayer/PrefixLayer.ino index bb5efbca..4a767894 100644 --- a/examples/Keystrokes/PrefixLayer/PrefixLayer.ino +++ b/examples/Keystrokes/PrefixLayer/PrefixLayer.ino @@ -61,8 +61,7 @@ KALEIDOSCOPE_INIT_PLUGINS(PrefixLayer); void setup() { Kaleidoscope.setup(); /* Configure the previously-defined prefix layers. */ - PrefixLayer.prefix_layers = prefix_layers; - PrefixLayer.prefix_layers_length = 1; + PrefixLayer.setPrefixLayers(prefix_layers); } void loop() { diff --git a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp index 18cc0c0b..5753771b 100644 --- a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp +++ b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp @@ -31,11 +31,6 @@ namespace kaleidoscope { namespace plugin { -static const PrefixLayer::Entry prefix_layers_default_[] PROGMEM = {}; -const PrefixLayer::Entry *PrefixLayer::prefix_layers = prefix_layers_default_; -uint8_t PrefixLayer::prefix_layers_length = 0; -bool PrefixLayer::clear_modifiers_ = false; - EventHandlerResult PrefixLayer::onKeyEvent(KeyEvent &event) { if (event.state & INJECTED) return EventHandlerResult::OK; @@ -48,11 +43,11 @@ EventHandlerResult PrefixLayer::onKeyEvent(KeyEvent &event) { if (event.key.isKeyboardModifier()) return EventHandlerResult::OK; - for (uint8_t i = 0; i < prefix_layers_length; i++) { - if (Layer.isActive(prefix_layers[i].layer)) { + for (uint8_t i = 0; i < prefix_layers_length_; i++) { + if (Layer.isActive(prefix_layers_[i].layer)) { clear_modifiers_ = true; - Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), IS_PRESSED | INJECTED, prefix_layers[i].prefix}); - Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), WAS_PRESSED | INJECTED, prefix_layers[i].prefix}); + Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), IS_PRESSED | INJECTED, prefix_layers_[i].prefix}); + Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), WAS_PRESSED | INJECTED, prefix_layers_[i].prefix}); clear_modifiers_ = false; } } @@ -71,6 +66,19 @@ EventHandlerResult PrefixLayer::beforeReportingState(const KeyEvent &event) { return EventHandlerResult::OK; } +void PrefixLayer::setPrefixLayers(const PrefixLayer::Entry *prefix_layers) { + prefix_layers_ = prefix_layers; + prefix_layers_length_ = sizeof(prefix_layers) / sizeof(PrefixLayer::Entry); +} + +const PrefixLayer::Entry *PrefixLayer::getPrefixLayers() { + return prefix_layers_; +} + +uint8_t PrefixLayer::getPrefixLayersLength() { + return prefix_layers_length_; +} + } // namespace plugin } // namespace kaleidoscope diff --git a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h index 196e1a70..c87244e0 100644 --- a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h +++ b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h @@ -41,11 +41,14 @@ class PrefixLayer : public Plugin { : layer(layer), prefix(prefix) {} }; - static const Entry *prefix_layers; - static uint8_t prefix_layers_length; + void setPrefixLayers(const Entry *prefix_layers); + const Entry *getPrefixLayers(); + uint8_t getPrefixLayersLength(); private: - static bool clear_modifiers_; + const Entry *prefix_layers_ PROGMEM = {}; + uint8_t prefix_layers_length_ = 0; + bool clear_modifiers_ = false; }; } // namespace plugin diff --git a/tests/plugins/PrefixLayer/basic/basic.ino b/tests/plugins/PrefixLayer/basic/basic.ino index 76a067b9..fc5c2cfc 100644 --- a/tests/plugins/PrefixLayer/basic/basic.ino +++ b/tests/plugins/PrefixLayer/basic/basic.ino @@ -59,8 +59,7 @@ KALEIDOSCOPE_INIT_PLUGINS(PrefixLayer); void setup() { Kaleidoscope.setup(); - PrefixLayer.prefix_layers = prefix_layers; - PrefixLayer.prefix_layers_length = 1; + PrefixLayer.setPrefixLayers(prefix_layers); } void loop() { From 06aebb42b9a5119aaf5cbddc209dc898a853b9a8 Mon Sep 17 00:00:00 2001 From: iliana etaoin Date: Sun, 29 May 2022 13:39:58 -0700 Subject: [PATCH 4/5] PrefixLayer: use onAddToReport instead Signed-off-by: iliana etaoin --- .../src/kaleidoscope/plugin/PrefixLayer.cpp | 17 ++++++++--------- .../src/kaleidoscope/plugin/PrefixLayer.h | 4 ++-- tests/plugins/PrefixLayer/basic/test.ktest | 12 ++++++++---- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp index 5753771b..9c45014a 100644 --- a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp +++ b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp @@ -45,22 +45,21 @@ EventHandlerResult PrefixLayer::onKeyEvent(KeyEvent &event) { for (uint8_t i = 0; i < prefix_layers_length_; i++) { if (Layer.isActive(prefix_layers_[i].layer)) { - clear_modifiers_ = true; - Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), IS_PRESSED | INJECTED, prefix_layers_[i].prefix}); - Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), WAS_PRESSED | INJECTED, prefix_layers_[i].prefix}); - clear_modifiers_ = false; + current_prefix_ = prefix_layers_[i].prefix; + Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), IS_PRESSED | INJECTED, current_prefix_}); + Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), WAS_PRESSED | INJECTED, current_prefix_}); + current_prefix_ = Key_NoKey; } } return EventHandlerResult::OK; } -EventHandlerResult PrefixLayer::beforeReportingState(const KeyEvent &event) { - if (clear_modifiers_) { - for (uint8_t i = HID_KEYBOARD_FIRST_MODIFIER; i <= HID_KEYBOARD_LAST_MODIFIER; i++) { - Runtime.hid().keyboard().releaseKey(Key(i, KEY_FLAGS)); +EventHandlerResult PrefixLayer::onAddToReport(Key key) { + if (current_prefix_ != Key_NoKey) { + if (current_prefix_ != key) { + return EventHandlerResult::ABORT; } - Runtime.hid().keyboard().pressModifiers(event.key); } return EventHandlerResult::OK; diff --git a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h index c87244e0..555a5691 100644 --- a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h +++ b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.h @@ -31,7 +31,7 @@ namespace plugin { class PrefixLayer : public Plugin { public: EventHandlerResult onKeyEvent(KeyEvent &event); - EventHandlerResult beforeReportingState(const KeyEvent &event); + EventHandlerResult onAddToReport(Key key); struct Entry { uint8_t layer; @@ -48,7 +48,7 @@ class PrefixLayer : public Plugin { private: const Entry *prefix_layers_ PROGMEM = {}; uint8_t prefix_layers_length_ = 0; - bool clear_modifiers_ = false; + Key current_prefix_ = Key_NoKey; }; } // namespace plugin diff --git a/tests/plugins/PrefixLayer/basic/test.ktest b/tests/plugins/PrefixLayer/basic/test.ktest index bb201048..137f93fe 100644 --- a/tests/plugins/PrefixLayer/basic/test.ktest +++ b/tests/plugins/PrefixLayer/basic/test.ktest @@ -102,6 +102,8 @@ PRESS H RUN 1 cycle EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report empty # release Ctrl +EXPECT keyboard-report Key_LCtrl # press Ctrl EXPECT keyboard-report Key_LCtrl Key_H # press H RUN 4 ms @@ -137,6 +139,8 @@ PRESS H RUN 1 cycle EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report empty # release Ctrl +EXPECT keyboard-report Key_LCtrl # press Ctrl EXPECT keyboard-report Key_LCtrl Key_H # press H RUN 4 ms @@ -170,10 +174,10 @@ EXPECT no keyboard-report # no report after pressing PREFIX_B RUN 4 ms PRESS H RUN 1 cycle -EXPECT keyboard-report Key_LShift Key_LCtrl # press Ctrl -EXPECT keyboard-report Key_LCtrl # release pressed shift +EXPECT keyboard-report Key_LCtrl # release pressed Shift and press Ctrl EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report empty # release Ctrl EXPECT keyboard-report Key_LShift # restoring pressed Shift EXPECT keyboard-report Key_LShift Key_H # press H @@ -208,10 +212,10 @@ EXPECT keyboard-report Key_LShift # press Shift RUN 4 ms PRESS H RUN 1 cycle -EXPECT keyboard-report Key_LShift Key_LCtrl # press Ctrl -EXPECT keyboard-report Key_LCtrl # release pressed shift +EXPECT keyboard-report Key_LCtrl # release pressed Shift and press Ctrl EXPECT keyboard-report Key_LCtrl Key_B # press B, Ctrl held EXPECT keyboard-report Key_LCtrl # release B, Ctrl held +EXPECT keyboard-report empty # release Ctrl EXPECT keyboard-report Key_LShift # restoring pressed Shift EXPECT keyboard-report Key_LShift Key_H # press H From 3da0ad457afe15ffa7cdaf17f0d2ba05183ebd07 Mon Sep 17 00:00:00 2001 From: iliana etaoin Date: Sun, 29 May 2022 21:47:35 -0700 Subject: [PATCH 5/5] PrefixLayer: clear only modifiers during prefix Signed-off-by: iliana etaoin --- .../src/kaleidoscope/plugin/PrefixLayer.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp index 9c45014a..e6f22048 100644 --- a/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp +++ b/plugins/Kaleidoscope-PrefixLayer/src/kaleidoscope/plugin/PrefixLayer.cpp @@ -56,10 +56,8 @@ EventHandlerResult PrefixLayer::onKeyEvent(KeyEvent &event) { } EventHandlerResult PrefixLayer::onAddToReport(Key key) { - if (current_prefix_ != Key_NoKey) { - if (current_prefix_ != key) { - return EventHandlerResult::ABORT; - } + if (current_prefix_ != Key_NoKey && current_prefix_ != key && key.isKeyboardModifier()) { + return EventHandlerResult::ABORT; } return EventHandlerResult::OK;