From e6deb09e88ef02429e6b4c685c956aa975f5d5a8 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Thu, 17 Jun 2021 18:14:28 -0500 Subject: [PATCH] Add builtin modifier/layer-shift combo keys Signed-off-by: Michael Richters --- src/kaleidoscope/Runtime.cpp | 13 ++++++++-- src/kaleidoscope/key_defs.h | 38 +++++++++++++++++++++++------ src/kaleidoscope/key_defs/keymaps.h | 3 +++ src/kaleidoscope/layers.cpp | 5 ++++ 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/kaleidoscope/Runtime.cpp b/src/kaleidoscope/Runtime.cpp index 1a9bd414..08375ec5 100644 --- a/src/kaleidoscope/Runtime.cpp +++ b/src/kaleidoscope/Runtime.cpp @@ -157,9 +157,13 @@ void Runtime_::handleKeyEvent(KeyEvent event) { event.key == Key_Transparent) return; - // If it's a built-in Layer key, we handle it here, and skip sending report(s) - if (event.key.isLayerKey()) { + // Built-in layer change keys are handled by the Layer object. + if (event.key.isLayerKey() || event.key.isModLayerKey()) { Layer.handleLayerKeyEvent(event); + } + // If the event is for a layer change key, there's no need to send a HID + // report, so we return early. + if (event.key.isLayerKey()) { return; } @@ -226,6 +230,11 @@ void Runtime_::addToReport(Key key) { if (result == EventHandlerResult::ABORT) return; + if (key.isModLayerKey()) { + uint8_t mod = key.getKeyCode() % 8; + key = Key(Key_LeftControl.getRaw() + mod); + } + if (key.isKeyboardKey()) { // The only incidental Keyboard modifiers that are allowed are the ones on // the key that generated the event, so we strip any others before adding diff --git a/src/kaleidoscope/key_defs.h b/src/kaleidoscope/key_defs.h index 8f5801ee..14a07b50 100644 --- a/src/kaleidoscope/key_defs.h +++ b/src/kaleidoscope/key_defs.h @@ -53,6 +53,12 @@ #define SWITCH_TO_KEYMAP 0b00000100 #define IS_CONSUMER 0b00001000 +// consumer: 01..1... +// sysctl: 01..0001 +// layer: 01000100 +// modlayer: 01000110 +// macros: 01100000 + // HID Usage Types: Because these constants, like the ones above, are // used in the flags byte of the Key class, they can't overlap any of // the above bits. Nor can we use `SYNTHETIC` and `RESERVED` to encode @@ -180,6 +186,9 @@ class Key { constexpr bool isLayerKey() const { return (flags_ == (SYNTHETIC | SWITCH_TO_KEYMAP)); } + constexpr bool isModLayerKey() const { + return (flags_ == (SYNTHETIC | SWITCH_TO_KEYMAP | IS_INTERNAL)); + } // --------------------------------------------------------------------------- // Additional utility functions for builtin `Key` variants @@ -206,19 +215,26 @@ class Key { // used in a conceptually different way: to get a different symbol in the // output. We don't normally think "type `shift`+`1`"; we think "type `!`". constexpr bool isKeyboardShift() const { - return (isKeyboardModifier() && - ((keyCode_ == HID_KEYBOARD_LEFT_SHIFT || - keyCode_ == HID_KEYBOARD_RIGHT_SHIFT) || - ((flags_ & SHIFT_HELD) != 0))); + return ((isKeyboardModifier() && + ((keyCode_ == HID_KEYBOARD_LEFT_SHIFT || + keyCode_ == HID_KEYBOARD_RIGHT_SHIFT) || + ((flags_ & SHIFT_HELD) != 0))) || + (isModLayerKey() && + (keyCode_ % 8) % 4 == 1)); } // Layer shift keys are conceptually similar to Keyboard modifier keys in that // they are used chorded to change the result of typing those other // keys. They're even more similar to `shift` keys. For both reasons, it's // worth singling them out. constexpr bool __attribute__((always_inline)) isLayerShift() const { - return (isLayerKey() && - keyCode_ >= LAYER_SHIFT_OFFSET && - keyCode_ < LAYER_MOVE_OFFSET); + return ((isLayerKey() && + keyCode_ >= LAYER_SHIFT_OFFSET && + keyCode_ < LAYER_MOVE_OFFSET) || + isModLayerKey()); + } + + constexpr bool isMomentary() const { + return (isKeyboardModifier() || isLayerShift() || isModLayerKey()); } private: @@ -254,6 +270,14 @@ constexpr Key addFlags(Key k, uint8_t add_flags) { return Key(k.getKeyCode(), k.getFlags() | add_flags); } +// ============================================================================= +/// Generate a ModLayer key (unchecked) +constexpr Key modLayerKey(Key modifier, uint8_t layer) { + uint8_t mod = modifier.getRaw() - Key_LeftControl.getRaw(); + uint8_t code = mod + (layer * 8); + return Key(code, SYNTHETIC | SWITCH_TO_KEYMAP | IS_INTERNAL); +} + } // namespace kaleidoscope // Redefine this macro to enable using alternative char-string to Key diff --git a/src/kaleidoscope/key_defs/keymaps.h b/src/kaleidoscope/key_defs/keymaps.h index 9039607c..5c29a63e 100644 --- a/src/kaleidoscope/key_defs/keymaps.h +++ b/src/kaleidoscope/key_defs/keymaps.h @@ -80,3 +80,6 @@ static const uint8_t LAYER_MOVE_OFFSET = LAYER_SHIFT_OFFSET + LAYER_OP_OFFSET; * this is a one-way operation. */ #define MoveToLayer(n) Key(n + LAYER_MOVE_OFFSET, KEY_FLAGS | SYNTHETIC | SWITCH_TO_KEYMAP) + +// Shorthand for keymap entry (e.g. `ML(LeftAlt, 3)`) +#define ML(mod, layer) kaleidoscope::modLayerKey(Key_##mod, layer) diff --git a/src/kaleidoscope/layers.cpp b/src/kaleidoscope/layers.cpp index 9a98fd85..38f3a69c 100644 --- a/src/kaleidoscope/layers.cpp +++ b/src/kaleidoscope/layers.cpp @@ -62,6 +62,11 @@ void Layer_::handleLayerKeyEvent(const KeyEvent &event) { // The caller is responsible for checking that this is a Layer `Key`, so we // skip checking for it here. uint8_t key_code = event.key.getKeyCode(); + + // If this is a ModLayer key, we need to convert it into a layer shift first. + if (event.key.isModLayerKey()) + key_code = (key_code / 8) + LAYER_SHIFT_OFFSET; + uint8_t target_layer; if (key_code >= LAYER_MOVE_OFFSET) {