From 86675490297773302acb45d2e59c6f8702e8105f Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Mon, 14 Jun 2021 01:13:53 -0500 Subject: [PATCH 01/11] Make OneShot stickability default to true This makes any non-modifier, non-layer shift key stickable by default. Signed-off-by: Michael Richters --- .../Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp index 63b6b851..f1c881ac 100644 --- a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp +++ b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp @@ -133,7 +133,7 @@ bool OneShot::isStickable(Key key) { return true; #endif } - return false; + return true; } bool OneShot::isTemporary(KeyAddr key_addr) { From f96b5b25f408118ec2cf5e84d95e739dd200e9ad Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sun, 13 Jun 2021 09:48:50 -0500 Subject: [PATCH 02/11] Make OneShot.isStickable() overridable by user code Signed-off-by: Michael Richters --- .../Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp | 5 +++++ .../Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp index f1c881ac..0596bb71 100644 --- a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp +++ b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp @@ -118,7 +118,12 @@ bool OneShot::isSticky() { // could potentially use three different color values for the three // states (sticky | active && !sticky | pressed && !active). +__attribute__((weak)) bool OneShot::isStickable(Key key) { + return isStickableDefault(key); +} + +bool OneShot::isStickableDefault(Key key) { int8_t n; if (key.isKeyboardModifier()) { n = key.getKeyCode() - Key_LeftControl.getKeyCode(); diff --git a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h index 6072a1ed..63e8c83e 100644 --- a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h +++ b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h @@ -153,7 +153,10 @@ class OneShot : public kaleidoscope::Plugin { key.getRaw() <= kaleidoscope::ranges::OS_LAST); } - static bool isStickable(Key key); // inline? + /// Determine if the given `key` is allowed to become sticky. + static bool isStickable(Key key); + + static bool isStickableDefault(Key key); static bool isTemporary(KeyAddr key_addr); // inline? static bool isSticky(KeyAddr key_addr); // inline? From c04542759f1db579df11f1918e9da1fc8521eadc Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sun, 13 Jun 2021 09:58:25 -0500 Subject: [PATCH 03/11] Add public functions to set OneShot key(addr) state Signed-off-by: Michael Richters --- .../src/kaleidoscope/plugin/OneShot.cpp | 29 ++++++++++++++++ .../src/kaleidoscope/plugin/OneShot.h | 34 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp index 0596bb71..aaf4dda1 100644 --- a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp +++ b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp @@ -145,6 +145,10 @@ bool OneShot::isTemporary(KeyAddr key_addr) { return temp_addrs_.read(key_addr); } +bool OneShot::isPending(KeyAddr key_addr) { + return (glue_addrs_.read(key_addr) && temp_addrs_.read(key_addr)); +} + bool OneShot::isSticky(KeyAddr key_addr) { return (glue_addrs_.read(key_addr) && !temp_addrs_.read(key_addr)); } @@ -153,6 +157,31 @@ bool OneShot::isActive(KeyAddr key_addr) { return (isTemporary(key_addr) || glue_addrs_.read(key_addr)); } +// ---------------------------------------------------------------------------- +// Public state-setting functions + +void OneShot::setPending(KeyAddr key_addr) { + temp_addrs_.set(key_addr); + glue_addrs_.clear(key_addr); + start_time_ = Runtime.millisAtCycleStart(); +} + +void OneShot::setOneShot(KeyAddr key_addr) { + temp_addrs_.set(key_addr); + glue_addrs_.set(key_addr); + start_time_ = Runtime.millisAtCycleStart(); +} + +void OneShot::setSticky(KeyAddr key_addr) { + temp_addrs_.clear(key_addr); + glue_addrs_.set(key_addr); +} + +void OneShot::clear(KeyAddr key_addr) { + temp_addrs_.clear(key_addr); + glue_addrs_.clear(key_addr); +} + // ---------------------------------------------------------------------------- // Other functions diff --git a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h index 63e8c83e..768fb553 100644 --- a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h +++ b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h @@ -159,9 +159,43 @@ class OneShot : public kaleidoscope::Plugin { static bool isStickableDefault(Key key); static bool isTemporary(KeyAddr key_addr); // inline? + static bool isPending(KeyAddr key_addr); static bool isSticky(KeyAddr key_addr); // inline? static bool isActive(KeyAddr key_addr); // inline? + // -------------------------------------------------------------------------- + // Public OneShot state control + + /// Put a key in the "pending" OneShot state. + /// + /// This function puts the key at `key_addr` in the "pending" OneShot state. + /// This is appropriate to use when a key toggles on and you want it to behave + /// like a OneShot key starting with the current event, and lasting until the + /// key becomes inactive (cancelled by a subsequent keypress). + static void setPending(KeyAddr key_addr); + + /// Put a key directly in the "one-shot" state. + /// + /// This function puts the key at `key_addr` in the "one-shot" state. This is + /// usually the state of a OneShot key after it is released, but before it is + /// cancelled by a subsequent keypress. In most cases, you probably want to + /// use `setPending()` instead, rather than calling this function explicitly, + /// as OneShot will automatically cause any key in the "pending" state to + /// progress to this state when it is (physically) released. + static void setOneShot(KeyAddr key_addr); + + /// Put a key in the "sticky" OneShot state. + /// + /// This function puts the key at `key_addr` in the "sticky" OneShot state. + /// It will remain active until it is pressed again. + static void setSticky(KeyAddr key_addr); + + /// Clear any OneShot state for a key. + /// + /// This function clears any OneShot state of the key at `key_addr`. It does + /// not, however, release the key if it is held. + static void clear(KeyAddr key_addr); + // -------------------------------------------------------------------------- // Utility function for other plugins to cancel OneShot keys static void cancel(bool with_stickies = false); From d0b6f5a21b7198198368c0bdfbeea280bc3761ac Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sun, 13 Jun 2021 21:57:42 -0500 Subject: [PATCH 04/11] Add Kaleidoscope-OneShotMetaKeys plugin Signed-off-by: Michael Richters --- .../OneShotMetaKeys/OneShotMetaKeys.ino | 88 +++++ .../Keystrokes/OneShotMetaKeys/sketch.json | 6 + .../Kaleidoscope-OneShotMetaKeys/README.md | 56 +++ .../library.properties | 7 + .../src/Kaleidoscope-OneShotMetaKeys.h | 20 ++ .../kaleidoscope/plugin/OneShotMetaKeys.cpp | 94 +++++ .../src/kaleidoscope/plugin/OneShotMetaKeys.h | 52 +++ tests/plugins/OneShot/meta-keys/meta-keys.ino | 53 +++ tests/plugins/OneShot/meta-keys/sketch.json | 6 + tests/plugins/OneShot/meta-keys/test.ktest | 325 ++++++++++++++++++ 10 files changed, 707 insertions(+) create mode 100644 examples/Keystrokes/OneShotMetaKeys/OneShotMetaKeys.ino create mode 100644 examples/Keystrokes/OneShotMetaKeys/sketch.json create mode 100644 plugins/Kaleidoscope-OneShotMetaKeys/README.md create mode 100644 plugins/Kaleidoscope-OneShotMetaKeys/library.properties create mode 100644 plugins/Kaleidoscope-OneShotMetaKeys/src/Kaleidoscope-OneShotMetaKeys.h create mode 100644 plugins/Kaleidoscope-OneShotMetaKeys/src/kaleidoscope/plugin/OneShotMetaKeys.cpp create mode 100644 plugins/Kaleidoscope-OneShotMetaKeys/src/kaleidoscope/plugin/OneShotMetaKeys.h create mode 100644 tests/plugins/OneShot/meta-keys/meta-keys.ino create mode 100644 tests/plugins/OneShot/meta-keys/sketch.json create mode 100644 tests/plugins/OneShot/meta-keys/test.ktest diff --git a/examples/Keystrokes/OneShotMetaKeys/OneShotMetaKeys.ino b/examples/Keystrokes/OneShotMetaKeys/OneShotMetaKeys.ino new file mode 100644 index 00000000..1a155c4a --- /dev/null +++ b/examples/Keystrokes/OneShotMetaKeys/OneShotMetaKeys.ino @@ -0,0 +1,88 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-OneShotMetaKeys -- Special OneShot keys + * Copyright (C) 2021 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 + +// Macros +enum { + TOGGLE_ONESHOT, +}; + +// *INDENT-OFF* +KEYMAPS( + [0] = KEYMAP_STACKED + ( + M(TOGGLE_ONESHOT), Key_1, Key_2, Key_3, Key_4, Key_5, OneShot_MetaStickyKey, + 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, + + OSM(LeftControl), Key_Backspace, OSM(LeftGui), OSM(LeftShift), + Key_Meh, + + OneShot_ActiveStickyKey, Key_6, Key_7, Key_8, Key_9, Key_0, ___, + 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_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus, + + Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl, + OSL(1)), + + [1] = KEYMAP_STACKED + ( + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + + ___, ___, ___, ___, + ___, + + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + Key_UpArrow, Key_DownArrow, Key_LeftArrow, Key_RightArrow,___, ___, + ___, ___, ___, ___, ___, ___, ___, + + ___, ___, ___, ___, + ___), +) +// *INDENT-ON* + +void macroToggleOneShot() { + OneShot.toggleAutoOneShot(); +} + +const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) { + if (macro_id == TOGGLE_ONESHOT) { + macroToggleOneShot(); + } + + return MACRO_NONE; +} + +KALEIDOSCOPE_INIT_PLUGINS(OneShot, OneShotMetaKeys, Macros); + +void setup() { + Kaleidoscope.setup(); +} + +void loop() { + Kaleidoscope.loop(); +} diff --git a/examples/Keystrokes/OneShotMetaKeys/sketch.json b/examples/Keystrokes/OneShotMetaKeys/sketch.json new file mode 100644 index 00000000..884ed009 --- /dev/null +++ b/examples/Keystrokes/OneShotMetaKeys/sketch.json @@ -0,0 +1,6 @@ +{ + "cpu": { + "fqbn": "keyboardio:avr:model01", + "port": "" + } +} diff --git a/plugins/Kaleidoscope-OneShotMetaKeys/README.md b/plugins/Kaleidoscope-OneShotMetaKeys/README.md new file mode 100644 index 00000000..9b192e8e --- /dev/null +++ b/plugins/Kaleidoscope-OneShotMetaKeys/README.md @@ -0,0 +1,56 @@ +# OneShot Meta Keys + +This plugin provides support for two special OneShot keys: +`OneShot_MetaStickyKey` & `OneShot_ActiveStickyKey`, each of which can be used +to make any key on the keyboard (not just modifiers and layer shift keys) +"sticky", so that they remain active even after the key has been released. +These are both `Key` values that can be used as entries in your sketch's keymap. + +Any keys made sticky in this way can be released just like OneShot modifier +keys, by tapping them again to cancel the effect. + +## The `OneShot_MetaStickyKey` + +This special OneShot key behaves like other OneShot keys, but its affect is to +make the next key pressed sticky. Tap `OneShot_MetaStickyKey`, then tap `X`, and +`X` will become sticky. Tap `X` again to deactivate it. + +Double-tapping `OneShot_MetaStickyKey` will make it sticky, just like any other +OneShot key. A third tap will release the key. + +## The `OneShot_ActiveStickyKey` + +This special key doesn't act like a OneShot key, but instead makes any key(s) +currently held (or otherwise active) sticky. Press (and hold) `X`, tap +`OneShot_ActiveStickyKey`, then release `X`, and `X` will stay active until it +is tapped again to deactivate it. + +## Using the plugin + +To use the plugin, just include one of the two special OneShot keys somewhere in +your keymap, and add both OneShot and OneShotMetaKeys to your sketch: + +```c++ +#include +#include + +// somewhere in the keymap... +OneShot_MetaStickyKey, OneShot_ActiveStickyKey + +KALEIDOSCOPE_INIT_PLUGINS(OneShot, OneShotMetaKeys); +``` + +Important note: OneShotMetaKeys _must_ be registered after OneShot in +`KALEIDOSCOPE_INIT_PLUGINS()` in order to function properly. + +## Dependencies + +* [Kaleidoscope-OneShot](Kaleidoscope-OneShot.md) +* [Kaleidoscope-Ranges](Kaleidoscope-Ranges.md) + +## Further reading + +Starting from the [example][plugin:example] is the recommended way of getting +started with the plugin. + + [plugin:example]: /examples/Keystrokes/OneShotMetaKeys/OneShotMetaKeys.ino diff --git a/plugins/Kaleidoscope-OneShotMetaKeys/library.properties b/plugins/Kaleidoscope-OneShotMetaKeys/library.properties new file mode 100644 index 00000000..28d5cb9d --- /dev/null +++ b/plugins/Kaleidoscope-OneShotMetaKeys/library.properties @@ -0,0 +1,7 @@ +name=Kaleidoscope-OneShotMetaKeys +version=0.0.0 +sentence=OneShot_ActiveStickyKey & OneShot_MetaStickyKey +maintainer=Kaleidoscope's Developers +url=https://github.com/keyboardio/Kaleidoscope +author=Keyboardio +paragraph= diff --git a/plugins/Kaleidoscope-OneShotMetaKeys/src/Kaleidoscope-OneShotMetaKeys.h b/plugins/Kaleidoscope-OneShotMetaKeys/src/Kaleidoscope-OneShotMetaKeys.h new file mode 100644 index 00000000..5266fc62 --- /dev/null +++ b/plugins/Kaleidoscope-OneShotMetaKeys/src/Kaleidoscope-OneShotMetaKeys.h @@ -0,0 +1,20 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-OneShot -- One-shot modifiers and layers + * Copyright (C) 2021 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/plugins/Kaleidoscope-OneShotMetaKeys/src/kaleidoscope/plugin/OneShotMetaKeys.cpp b/plugins/Kaleidoscope-OneShotMetaKeys/src/kaleidoscope/plugin/OneShotMetaKeys.cpp new file mode 100644 index 00000000..e8765933 --- /dev/null +++ b/plugins/Kaleidoscope-OneShotMetaKeys/src/kaleidoscope/plugin/OneShotMetaKeys.cpp @@ -0,0 +1,94 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-OneShot -- One-shot modifiers and layers + * Copyright (C) 2021 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/KeyAddr.h" +#include "kaleidoscope/key_defs.h" +#include "kaleidoscope/KeyEvent.h" +#include "kaleidoscope/keyswitch_state.h" +#include "kaleidoscope/LiveKeys.h" + +namespace kaleidoscope { +namespace plugin { + +// ============================================================================ +// Public interface + +// ---------------------------------------------------------------------------- +// Plugin hook functions + +EventHandlerResult OneShotMetaKeys::onNameQuery() { + return ::Focus.sendName(F("OneShotMetaKeys")); +} + +EventHandlerResult OneShotMetaKeys::onKeyEvent(KeyEvent &event) { + // Ignore key release and injected events. + if (keyToggledOff(event.state) || event.state & INJECTED) + return EventHandlerResult::OK; + + // Make all held keys sticky if `OneShot_ActiveStickyKey` toggles on. + if (event.key == OneShot_ActiveStickyKey) { + // Note: we don't need to explicitly skip the key the active sticky key + // itself (i.e. `event.addr`), because its entry in `live_keys[]` has not + // yet been inserted at this point. + for (KeyAddr addr : KeyAddr::all()) { + // Get the entry from the keyboard state array. + Key key = live_keys[addr]; + // Skip idle and masked entries. + if (key == Key_Inactive || key == Key_Masked) { + continue; + } + // Make everything else sticky. + ::OneShot.setSticky(addr); + } + return EventHandlerResult::OK; + } + + // If there's an active meta-sticky key, we need to make newly-pressed keys + // sticky, unless they were already active, in which case we let OneShot + // release them from the "sticky" state. + if (isMetaStickyActive() && + live_keys[event.addr] != event.key) { + ::OneShot.setSticky(event.addr); + return EventHandlerResult::OK; + } + + // If a previously-inactive meta-sticky key was just pressed, we have OneShot + // put it in the "pending" state so it will act like a OneShot key. + if (event.key == OneShot_MetaStickyKey && + live_keys[event.addr] != OneShot_MetaStickyKey) { + ::OneShot.setPending(event.addr); + } + return EventHandlerResult::OK; +} + +bool OneShotMetaKeys::isMetaStickyActive() { + for (Key key : live_keys.all()) { + if (key == OneShot_MetaStickyKey) + return true; + } + return false; +} + +} // namespace plugin +} // namespace kaleidoscope + +kaleidoscope::plugin::OneShotMetaKeys OneShotMetaKeys; diff --git a/plugins/Kaleidoscope-OneShotMetaKeys/src/kaleidoscope/plugin/OneShotMetaKeys.h b/plugins/Kaleidoscope-OneShotMetaKeys/src/kaleidoscope/plugin/OneShotMetaKeys.h new file mode 100644 index 00000000..5f5a4f3a --- /dev/null +++ b/plugins/Kaleidoscope-OneShotMetaKeys/src/kaleidoscope/plugin/OneShotMetaKeys.h @@ -0,0 +1,52 @@ +/* -*- mode: c++ -*- + * Kaleidoscope-OneShot -- One-shot modifiers and layers + * Copyright (C) 2021 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 + +#include "kaleidoscope/event_handler_result.h" +#include "kaleidoscope/key_defs.h" +#include "kaleidoscope/KeyEvent.h" +#include "kaleidoscope/plugin.h" + +// ---------------------------------------------------------------------------- +// Key constants +constexpr Key OneShot_MetaStickyKey {kaleidoscope::ranges::OS_META_STICKY}; +constexpr Key OneShot_ActiveStickyKey {kaleidoscope::ranges::OS_ACTIVE_STICKY}; + +namespace kaleidoscope { +namespace plugin { + +class OneShotMetaKeys : public kaleidoscope::Plugin { + public: + // -------------------------------------------------------------------------- + // Plugin hook functions + + EventHandlerResult onNameQuery(); + EventHandlerResult onKeyEvent(KeyEvent &event); + + private: + static bool isMetaStickyActive(); + +}; + +} // namespace plugin +} // namespace kaleidoscope + +extern kaleidoscope::plugin::OneShotMetaKeys OneShotMetaKeys; diff --git a/tests/plugins/OneShot/meta-keys/meta-keys.ino b/tests/plugins/OneShot/meta-keys/meta-keys.ino new file mode 100644 index 00000000..56b47042 --- /dev/null +++ b/tests/plugins/OneShot/meta-keys/meta-keys.ino @@ -0,0 +1,53 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2021 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 + +// *INDENT-OFF* +KEYMAPS( + [0] = KEYMAP_STACKED + ( + OneShot_MetaStickyKey, OneShot_ActiveStickyKey, ___, ___, ___, ___, ___, + Key_A, Key_B, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___, + + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___ + ), +) +// *INDENT-ON* + +KALEIDOSCOPE_INIT_PLUGINS(OneShot, OneShotMetaKeys); + +void setup() { + Kaleidoscope.setup(); + OneShot.setTimeout(50); + OneShot.setHoldTimeout(20); + OneShot.setDoubleTapTimeout(20); +} + +void loop() { + Kaleidoscope.loop(); +} diff --git a/tests/plugins/OneShot/meta-keys/sketch.json b/tests/plugins/OneShot/meta-keys/sketch.json new file mode 100644 index 00000000..8cc86922 --- /dev/null +++ b/tests/plugins/OneShot/meta-keys/sketch.json @@ -0,0 +1,6 @@ +{ + "cpu": { + "fqbn": "keyboardio:virtual:model01", + "port": "" + } +} diff --git a/tests/plugins/OneShot/meta-keys/test.ktest b/tests/plugins/OneShot/meta-keys/test.ktest new file mode 100644 index 00000000..d8b883d8 --- /dev/null +++ b/tests/plugins/OneShot/meta-keys/test.ktest @@ -0,0 +1,325 @@ +VERSION 1 + +KEYSWITCH OS_META 0 0 +KEYSWITCH OS_ACTIVE 0 1 +KEYSWITCH A 1 0 +KEYSWITCH B 1 1 + +# ============================================================================== +NAME OneShot meta sticky + +RUN 4 ms +PRESS OS_META +RUN 1 cycle + +RUN 4 ms +RELEASE OS_META +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms + +# ============================================================================== +NAME OneShot meta sticky rollover + +RUN 4 ms +PRESS OS_META +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE OS_META +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms + +# ============================================================================== +NAME OneShot meta sticky overlap + +RUN 4 ms +PRESS OS_META +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle + +RUN 4 ms +RELEASE OS_META +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms + +# ============================================================================== +NAME OneShot meta sticky overlap to rollover + +RUN 4 ms +PRESS OS_META +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle + +RUN 4 ms +RELEASE OS_META +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms + +# ============================================================================== +NAME OneShot meta sticky sticky + +RUN 4 ms +PRESS OS_META +RUN 1 cycle + +RUN 4 ms +RELEASE OS_META +RUN 1 cycle + +RUN 4 ms +PRESS OS_META +RUN 1 cycle + +RUN 4 ms +RELEASE OS_META +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle + +RUN 4 ms +PRESS B +RUN 1 cycle +EXPECT keyboard-report Key_A Key_B + +RUN 4 ms +RELEASE B +RUN 1 cycle + +RUN 4 ms +PRESS OS_META +RUN 1 cycle + +RUN 4 ms +RELEASE OS_META +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report Key_B + +RUN 4 ms +PRESS B +RUN 1 cycle + +RUN 4 ms +RELEASE B +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms + +# ============================================================================== +NAME OneShot active sticky + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +PRESS OS_ACTIVE +RUN 1 cycle + +RUN 4 ms +RELEASE OS_ACTIVE +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms + +# ============================================================================== +NAME OneShot active sticky two keys + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +PRESS B +RUN 1 cycle +EXPECT keyboard-report Key_A Key_B + +RUN 4 ms +PRESS OS_ACTIVE +RUN 1 cycle + +RUN 4 ms +RELEASE OS_ACTIVE +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle + +RUN 4 ms +RELEASE B +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report Key_B + +RUN 4 ms +PRESS B +RUN 1 cycle + +RUN 4 ms +RELEASE B +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms From 727d0ba23ecdc1a174383e7de8efbe5156c9b62e Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sun, 13 Jun 2021 22:21:06 -0500 Subject: [PATCH 05/11] Remove OneShot meta key handling from the OneShot plugin The handling of these keys has been shifted to a separate OneShotMetaKeys plugin. Signed-off-by: Michael Richters --- examples/Keystrokes/OneShot/OneShot.ino | 4 +- plugins/Kaleidoscope-OneShot/README.md | 19 ------ .../src/kaleidoscope/plugin/OneShot.cpp | 67 ------------------- .../src/kaleidoscope/plugin/OneShot.h | 9 --- 4 files changed, 2 insertions(+), 97 deletions(-) diff --git a/examples/Keystrokes/OneShot/OneShot.ino b/examples/Keystrokes/OneShot/OneShot.ino index 82ef7092..96a249ca 100644 --- a/examples/Keystrokes/OneShot/OneShot.ino +++ b/examples/Keystrokes/OneShot/OneShot.ino @@ -28,7 +28,7 @@ enum { KEYMAPS( [0] = KEYMAP_STACKED ( - M(TOGGLE_ONESHOT), Key_1, Key_2, Key_3, Key_4, Key_5, OneShot_MetaStickyKey, + M(TOGGLE_ONESHOT), Key_1, Key_2, Key_3, Key_4, Key_5, ___, 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, @@ -36,7 +36,7 @@ KEYMAPS( OSM(LeftControl), Key_Backspace, OSM(LeftGui), OSM(LeftShift), Key_Meh, - OneShot_ActiveStickyKey, Key_6, Key_7, Key_8, Key_9, Key_0, ___, + ___, Key_6, Key_7, Key_8, Key_9, Key_0, ___, 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_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus, diff --git a/plugins/Kaleidoscope-OneShot/README.md b/plugins/Kaleidoscope-OneShot/README.md index f0e8699d..0b3e2725 100644 --- a/plugins/Kaleidoscope-OneShot/README.md +++ b/plugins/Kaleidoscope-OneShot/README.md @@ -46,25 +46,6 @@ will have a yellow LED highlight; when sticky, a red highlight. When it is in a "held" state, but will be deactivated when released like any non-one-shot key, it will have a white highlight. (These colors are configurable.) -## Special OneShot keys - -OneShot also comes with two special keys that can make any key on your keyboard -sticky: `OneShot_MetaStickyKey` & `OneShot_ActiveStickyKey`. These are both -`Key` values that can be used as entries in your sketch's keymap. - -### `OneShot_MetaStickyKey` - -This special OneShot key behaves like other OneShot keys, but its affect is to -make the next key pressed sticky. Tap `OneShot_MetaStickyKey`, then tap `X`, and -`X` will become sticky. Tap `X` again to deactivate it. - -### `OneShot_ActiveStickyKey` - -This special key doesn't act like a OneShot key, but instead makes any key(s) -currently held (or otherwise active) sticky. Press (and hold) `X`, tap -`OneShot_ActiveStickyKey`, then release `X`, and `X` will stay active until it -is tapped again to deactivate it. - ## Using the plugin After adding one-shot keys to the keymap, all one needs to do, is enable the diff --git a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp index aaf4dda1..e0d4fbcb 100644 --- a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp +++ b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp @@ -52,10 +52,6 @@ KeyAddrBitfield OneShot::glue_addrs_; uint16_t OneShot::start_time_ = 0; KeyAddr OneShot::prev_key_addr_ = OneShot::invalid_key_addr; -#ifndef ONESHOT_WITHOUT_METASTICKY -KeyAddr OneShot::meta_sticky_key_addr_ {KeyAddr::invalid_state}; -#endif - // ============================================================================ // Public interface @@ -133,10 +129,6 @@ bool OneShot::isStickableDefault(Key key) { if (n < oneshot_key_count) { return bitRead(stickable_keys_, n); } -#ifndef ONESHOT_WITHOUT_METASTICKY - } else if (key == OneShot_MetaStickyKey) { - return true; -#endif } return true; } @@ -224,27 +216,6 @@ EventHandlerResult OneShot::onKeyEvent(KeyEvent& event) { if (keyToggledOn(event.state)) { - // Make all held keys sticky if `OneShot_ActiveStickyKey` toggles on. - if (event.key == OneShot_ActiveStickyKey) { - // Skip the stickify key itself - for (KeyAddr entry_addr : KeyAddr::all()) { - if (entry_addr == event.addr) { - continue; - } - // Get the entry from the keyboard state array - Key entry_key = live_keys[entry_addr]; - // Skip empty entries - if (entry_key == Key_Transparent || entry_key == Key_NoKey) { - continue; - } - // Make everything else sticky - temp_addrs_.clear(entry_addr); - glue_addrs_.set(entry_addr); - } - prev_key_addr_ = event.addr; - return EventHandlerResult::OK; - } - if (!temp && !glue) { // The key is in the "normal" state. The first thing we need to do is // convert OneShot keys to their equivalent values, and record the fact @@ -256,34 +227,6 @@ EventHandlerResult OneShot::onKeyEvent(KeyEvent& event) { is_oneshot = true; } -#ifndef ONESHOT_WITHOUT_METASTICKY - bool is_meta_sticky_key_active = meta_sticky_key_addr_.isValid(); - if (is_meta_sticky_key_active) { - // If the meta key isn't sticky, release it - bool ms_temp = temp_addrs_.read(meta_sticky_key_addr_); - bool ms_glue = glue_addrs_.read(meta_sticky_key_addr_); - if (ms_temp) { - if (ms_glue) { - // The meta key is in the "one-shot" state; release it immediately. - releaseKey(meta_sticky_key_addr_); - } else { - // The meta key is in the "pending" state; cancel that, and let it - // deactivate on release. - temp_addrs_.clear(meta_sticky_key_addr_); - } - } - glue_addrs_.set(event.addr); - } else if (event.key == OneShot_MetaStickyKey) { - meta_sticky_key_addr_ = event.addr; - temp_addrs_.set(event.addr); - } - if (is_meta_sticky_key_active || (event.key == OneShot_MetaStickyKey)) { - prev_key_addr_ = event.addr; - start_time_ = Runtime.millisAtCycleStart(); - return EventHandlerResult::OK; - } -#endif - if (is_oneshot || (auto_modifiers_ && event.key.isKeyboardModifier()) || (auto_layers_ && event.key.isLayerShift())) { @@ -343,11 +286,6 @@ EventHandlerResult OneShot::onKeyEvent(KeyEvent& event) { // stop that event from sending a report, and instead send a "hold" // event. This is handled in the `beforeReportingState()` hook below. return EventHandlerResult::ABORT; -#ifndef ONESHOT_WITHOUT_METASTICKY - } else if (event.key == OneShot_MetaStickyKey) { - // Turn off the meta key if it's released in its "normal" state. - meta_sticky_key_addr_ = KeyAddr::none(); -#endif } } @@ -468,11 +406,6 @@ void OneShot::releaseKey(KeyAddr key_addr) { glue_addrs_.clear(key_addr); temp_addrs_.clear(key_addr); -#ifndef ONESHOT_WITHOUT_METASTICKY - if (live_keys[key_addr] == OneShot_MetaStickyKey) - meta_sticky_key_addr_ = KeyAddr::none(); -#endif - KeyEvent event{key_addr, WAS_PRESSED | INJECTED}; Runtime.handleKeyEvent(event); } diff --git a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h index 768fb553..034dec5b 100644 --- a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h +++ b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.h @@ -68,11 +68,6 @@ #define OSM(kc) Key(kaleidoscope::ranges::OSM_FIRST + (Key_ ## kc).getKeyCode() - Key_LeftControl.getKeyCode()) #define OSL(n) Key(kaleidoscope::ranges::OSL_FIRST + n) -// ---------------------------------------------------------------------------- -// Key constants -constexpr Key OneShot_MetaStickyKey {kaleidoscope::ranges::OS_META_STICKY}; -constexpr Key OneShot_ActiveStickyKey {kaleidoscope::ranges::OS_ACTIVE_STICKY}; - namespace kaleidoscope { namespace plugin { @@ -299,10 +294,6 @@ class OneShot : public kaleidoscope::Plugin { static uint16_t start_time_; static KeyAddr prev_key_addr_; -#ifndef ONESHOT_WITHOUT_METASTICKY - static KeyAddr meta_sticky_key_addr_; -#endif - // -------------------------------------------------------------------------- // Internal utility functions static bool hasTimedOut(uint16_t ttl) { From 301acac9ad45832721136d519c2955ac6b02b5ac Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Mon, 14 Jun 2021 12:01:05 -0500 Subject: [PATCH 06/11] Add NEWS and UPGRADING entries for OneShotMetaKeys Signed-off-by: Michael Richters --- docs/NEWS.md | 23 +++++++++++++++++++++++ docs/UPGRADING.md | 5 +++++ 2 files changed, 28 insertions(+) diff --git a/docs/NEWS.md b/docs/NEWS.md index c28fefdd..5efee04f 100644 --- a/docs/NEWS.md +++ b/docs/NEWS.md @@ -12,6 +12,29 @@ See [UPGRADING.md](UPGRADING.md) for more detailed instructions about upgrading ## New features +### OneShot public functions + +The OneShot plugin now allows other plugins to control the OneShot state of +individual keys, by calling one of the following: + +- `OneShot.setPending(key_addr)`: Put the key at `key_addr` in the "pending" + OneShot state. This will make that key act like any other OneShot key until + it is cancelled by a subsequent keypress. Once a key is in this state, + OneShot will manage it from that point on, including making the key "sticky" + if it is double-tapped. +- `OneShot.setSticky(key_addr)`: Put the key at `key_addr` in the "sticky" + OneShot state. The key will be released by OneShot when it is tapped again. +- `OneShot.setOneShot(key_addr)`: Put the key at `key_addr` in the "one-shot" + state. This is normally the state OneShot key will be in after it has been + tapped. Calling `setPending()` is more likely to be useful. +- `OneShot.clear(key_addr)`: Clear the OneShot state of the key at `key_addr`. + +Note: Any plugin that calls one of these OneShot methods must either be +registered in `KALEIDOSCOPE_INIT_PLUGINS()` after OneShot, or it must add the +`INJECTED` bit to the keyswitch state of the event (i.e. `event.state |= +INJECTED`) to prevent OneShot from prematurely advancing keys to the next +OneShot state. + ### SpaceCadet "no-delay" mode SpaceCadet can now be enabled in "no-delay" mode, wherein the primary (modifier) diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index 49b21c38..25b98358 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -16,6 +16,7 @@ If any of this does not make sense to you, or you have trouble updating your .in - [Bidirectional communication for plugins](#bidirectional-communication-for-plugins) - [Consistent timing](#consistent-timing) + [Breaking changes](#breaking-changes) + - [OneShot meta keys](#oneshot-meta-keys) - [git checkouts aren't compatible with Arduino IDE (GUI)]([#repository-rearchitecture) - [Layer system switched to activation-order](#layer-system-switched-to-activation-order) - [The `RxCy` macros and peeking into the keyswitch state](#the-rxcy-macros-and-peeking-into-the-keyswitch-state) @@ -434,6 +435,10 @@ As a developer, one can continue using `millis()`, but migrating to `Kaleidoscop ## Breaking changes +### OneShot meta keys + +The special OneShot keys `OneShot_MetaStickyKey` & `OneShot_ActiveStickyKey` are no longer handled by the OneShot plugin directly, but instead by a separate OneShotMetaKeys plugin. If you use these keys in your sketch, you will need to add the new plugin, and register it after OneShot in `KALEIDOSCOPE_INIT_PLUGINS()` for those keys to work properly. + ### Repository rearchitecture To improve build times and to better highlight Kaleidoscope's many plugins, plugins have been move into directories inside the Kaleidoscope directory. From c78ff257ba6c00840b23d2c8a2b3ca1468a2bfa7 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Mon, 14 Jun 2021 13:59:28 -0500 Subject: [PATCH 07/11] Include OneShotMetaKeys in the headers for ActiveModColor Signed-off-by: Michael Richters --- plugins/Kaleidoscope-LED-ActiveModColor/README.md | 5 +++++ .../src/kaleidoscope/plugin/LED-ActiveModColor.cpp | 1 + 2 files changed, 6 insertions(+) diff --git a/plugins/Kaleidoscope-LED-ActiveModColor/README.md b/plugins/Kaleidoscope-LED-ActiveModColor/README.md index e2a2c709..c5e9fb56 100644 --- a/plugins/Kaleidoscope-LED-ActiveModColor/README.md +++ b/plugins/Kaleidoscope-LED-ActiveModColor/README.md @@ -63,6 +63,11 @@ The `ActiveModColorEffect` object provides the following methods: * [Kaleidoscope-LEDControl](Kaleidoscope-LEDControl.md) * [Kaleidoscope-OneShot](Kaleidoscope-OneShot.md) +* [Kaleidoscope-OneShotMetaKeys](Kaleidoscope-OneShotMetaKeys.md) + +The `ActiveModColorEffect` plugin doesn't require that either OneShot or +OneShotMetaKeys plugins are registered with `KALEIDOSCOPE_INIT_PLUGINS()` in +order to work, but it does depend on their header files. ## Further reading diff --git a/plugins/Kaleidoscope-LED-ActiveModColor/src/kaleidoscope/plugin/LED-ActiveModColor.cpp b/plugins/Kaleidoscope-LED-ActiveModColor/src/kaleidoscope/plugin/LED-ActiveModColor.cpp index ab127bfd..ce3e231d 100644 --- a/plugins/Kaleidoscope-LED-ActiveModColor/src/kaleidoscope/plugin/LED-ActiveModColor.cpp +++ b/plugins/Kaleidoscope-LED-ActiveModColor/src/kaleidoscope/plugin/LED-ActiveModColor.cpp @@ -17,6 +17,7 @@ #include #include +#include #include "kaleidoscope/LiveKeys.h" #include "kaleidoscope/layers.h" #include "kaleidoscope/keyswitch_state.h" From 03c086f34f82839806833e59bd9d2d2ed67b8da8 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Mon, 14 Jun 2021 14:00:12 -0500 Subject: [PATCH 08/11] Update references to inactive and masked keys Signed-off-by: Michael Richters --- .../src/kaleidoscope/plugin/LED-ActiveModColor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Kaleidoscope-LED-ActiveModColor/src/kaleidoscope/plugin/LED-ActiveModColor.cpp b/plugins/Kaleidoscope-LED-ActiveModColor/src/kaleidoscope/plugin/LED-ActiveModColor.cpp index ce3e231d..ac1e55a8 100644 --- a/plugins/Kaleidoscope-LED-ActiveModColor/src/kaleidoscope/plugin/LED-ActiveModColor.cpp +++ b/plugins/Kaleidoscope-LED-ActiveModColor/src/kaleidoscope/plugin/LED-ActiveModColor.cpp @@ -55,7 +55,7 @@ EventHandlerResult ActiveModColorEffect::onKeyEvent(KeyEvent &event) { // Get the entry from the live keys array Key entry_key = live_keys[entry_addr]; // Skip empty entries - if (entry_key == Key_Transparent || entry_key == Key_NoKey) { + if (entry_key == Key_Inactive || entry_key == Key_Masked) { continue; } // Highlight everything else From 25c975eae7422a7908cb0ef2d5cc01f83c1d4ac6 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Mon, 14 Jun 2021 19:49:16 -0500 Subject: [PATCH 09/11] Add testcase for issue 1061 This is a demonstration that another plugin can use the new public OneShot methods to turn a non-OneShot key into a OneShot. Signed-off-by: Michael Richters --- tests/issues/1061/1061.ino | 70 ++++++++++++++++++++++++ tests/issues/1061/sketch.json | 6 ++ tests/issues/1061/test.ktest | 100 ++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 tests/issues/1061/1061.ino create mode 100644 tests/issues/1061/sketch.json create mode 100644 tests/issues/1061/test.ktest diff --git a/tests/issues/1061/1061.ino b/tests/issues/1061/1061.ino new file mode 100644 index 00000000..f9d8b275 --- /dev/null +++ b/tests/issues/1061/1061.ino @@ -0,0 +1,70 @@ +/* -*- mode: c++ -*- + * Copyright (C) 2021 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 + +// *INDENT-OFF* +KEYMAPS( + [0] = KEYMAP_STACKED + ( + Key_Insert, ___, ___, ___, ___, ___, ___, + Key_A, Key_B, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___, + + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, ___, ___, ___, + ___, ___, ___, ___, + ___ + ), +) +// *INDENT-ON* + +namespace kaleidoscope { +namespace plugin { + +class OneShotInsert : public Plugin { + public: + EventHandlerResult onKeyEvent(KeyEvent &event) { + if (keyToggledOn(event.state) && (event.state & INJECTED) == 0 && + event.key == Key_Insert && live_keys[event.addr] != event.key) + ::OneShot.setPending(event.addr); + return EventHandlerResult::OK; + } +}; + +} // namespace plugin +} // namespace kaleidoscope + +kaleidoscope::plugin::OneShotInsert OneShotInsert; + +KALEIDOSCOPE_INIT_PLUGINS(OneShot, OneShotInsert); + +void setup() { + Kaleidoscope.setup(); + OneShot.setTimeout(50); + OneShot.setHoldTimeout(20); + OneShot.setDoubleTapTimeout(20); +} + +void loop() { + Kaleidoscope.loop(); +} diff --git a/tests/issues/1061/sketch.json b/tests/issues/1061/sketch.json new file mode 100644 index 00000000..8cc86922 --- /dev/null +++ b/tests/issues/1061/sketch.json @@ -0,0 +1,6 @@ +{ + "cpu": { + "fqbn": "keyboardio:virtual:model01", + "port": "" + } +} diff --git a/tests/issues/1061/test.ktest b/tests/issues/1061/test.ktest new file mode 100644 index 00000000..1d72c372 --- /dev/null +++ b/tests/issues/1061/test.ktest @@ -0,0 +1,100 @@ +VERSION 1 + +KEYSWITCH INSERT 0 0 +KEYSWITCH A 1 0 +KEYSWITCH B 1 1 + +# ============================================================================== +NAME OneShot insert timeout + +RUN 4 ms +PRESS INSERT +RUN 1 cycle +EXPECT keyboard-report Key_Insert + +RUN 4 ms +RELEASE INSERT +RUN 1 cycle + +RUN 45 ms +EXPECT keyboard-report empty + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms + +# ============================================================================== +NAME OneShot insert interrupt + +RUN 4 ms +PRESS INSERT +RUN 1 cycle +EXPECT keyboard-report Key_Insert + +RUN 4 ms +RELEASE INSERT +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_Insert Key_A +EXPECT keyboard-report Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms + +# ============================================================================== +NAME OneShot insert sticky + +RUN 4 ms +PRESS INSERT +RUN 1 cycle +EXPECT keyboard-report Key_Insert + +RUN 4 ms +RELEASE INSERT +RUN 1 cycle + +RUN 4 ms +PRESS INSERT +RUN 1 cycle + +RUN 4 ms +RELEASE INSERT +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_Insert Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report Key_Insert + +RUN 100 ms + +RUN 4 ms +PRESS INSERT +RUN 1 cycle + +RUN 4 ms +RELEASE INSERT +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms From 9f65e808c0c24f656a3ad77ea4d85adafa99c64c Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Tue, 15 Jun 2021 00:19:49 -0500 Subject: [PATCH 10/11] Add override of OneShot.isStickable() to testcase Signed-off-by: Michael Richters --- tests/issues/1061/1061.ino | 8 ++++- tests/issues/1061/test.ktest | 68 ++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/tests/issues/1061/1061.ino b/tests/issues/1061/1061.ino index f9d8b275..df2c20cd 100644 --- a/tests/issues/1061/1061.ino +++ b/tests/issues/1061/1061.ino @@ -21,7 +21,7 @@ KEYMAPS( [0] = KEYMAP_STACKED ( - Key_Insert, ___, ___, ___, ___, ___, ___, + Key_Insert, OSM(LeftAlt), OSM(RightAlt), ___, ___, ___, ___, Key_A, Key_B, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, @@ -51,6 +51,12 @@ class OneShotInsert : public Plugin { } }; +bool OneShot::isStickable(Key key) { + if (key == Key_LeftAlt) + return false; + return OneShot::isStickableDefault(key); +} + } // namespace plugin } // namespace kaleidoscope diff --git a/tests/issues/1061/test.ktest b/tests/issues/1061/test.ktest index 1d72c372..ee4aecd9 100644 --- a/tests/issues/1061/test.ktest +++ b/tests/issues/1061/test.ktest @@ -1,6 +1,8 @@ VERSION 1 KEYSWITCH INSERT 0 0 +KEYSWITCH LALT 0 1 +KEYSWITCH RALT 0 2 KEYSWITCH A 1 0 KEYSWITCH B 1 1 @@ -98,3 +100,69 @@ RUN 1 cycle EXPECT keyboard-report empty RUN 5 ms + +# ============================================================================== +NAME OneShot left alt not sticky + +RUN 4 ms +PRESS LALT +RUN 1 cycle +EXPECT keyboard-report Key_LeftAlt + +RUN 4 ms +RELEASE LALT +RUN 1 cycle + +RUN 4 ms +PRESS LALT +RUN 1 cycle + +RUN 4 ms +RELEASE LALT +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms + +# ============================================================================== +NAME OneShot right alt sticky + +RUN 4 ms +PRESS RALT +RUN 1 cycle +EXPECT keyboard-report Key_RightAlt + +RUN 4 ms +RELEASE RALT +RUN 1 cycle + +RUN 4 ms +PRESS RALT +RUN 1 cycle + +RUN 4 ms +RELEASE RALT +RUN 1 cycle + +RUN 4 ms +PRESS A +RUN 1 cycle +EXPECT keyboard-report Key_RightAlt Key_A + +RUN 4 ms +RELEASE A +RUN 1 cycle +EXPECT keyboard-report Key_RightAlt + +RUN 100 ms + +RUN 4 ms +PRESS RALT +RUN 1 cycle + +RUN 4 ms +RELEASE RALT +RUN 1 cycle +EXPECT keyboard-report empty + +RUN 5 ms From 55af2fd0319013cc1e1ad5c30fb2a7bd0acc0dc9 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Wed, 16 Jun 2021 15:31:27 -0500 Subject: [PATCH 11/11] Comment `isStickableDefault()` to explain default stickability Signed-off-by: Michael Richters --- .../src/kaleidoscope/plugin/OneShot.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp index e0d4fbcb..1ab16ba7 100644 --- a/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp +++ b/plugins/Kaleidoscope-OneShot/src/kaleidoscope/plugin/OneShot.cpp @@ -121,15 +121,22 @@ bool OneShot::isStickable(Key key) { bool OneShot::isStickableDefault(Key key) { int8_t n; + // If the key is either a keyboard modifier or a layer shift, we check to see + // if it has been set to be non-stickable. if (key.isKeyboardModifier()) { n = key.getKeyCode() - Key_LeftControl.getKeyCode(); return bitRead(stickable_keys_, n); } else if (key.isLayerShift()) { n = oneshot_mod_count + key.getKeyCode() - LAYER_SHIFT_OFFSET; + // We only keep track of the stickability of the first 8 layers. if (n < oneshot_key_count) { return bitRead(stickable_keys_, n); } } + // The default is for all keys to be "stickable"; if the default was false, + // any user code or other plugin that uses `setPending()` to turn a key into a + // OneShot would need to override `isStickable()` in order to make that key + // stickable (the default `OSM()` behaviour). return true; }