Merge pull request #1040 from gedankenexperimenter/plugin/unshifter

Add CharShift plugin
pull/1073/head
Jesse Vincent 3 years ago committed by GitHub
commit 3dfb4934fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -238,6 +238,10 @@ To make it easier to port Kaleidoscope, we introduced the `ATMegaKeyboard` base
## New plugins
### CharShift
The [CharShift](plugins/Kaleidoscope-CharShift.md) plugin allows independent assignment of symbols to keys depending on whether or not a `shift` key is held.
### AutoShift
The [AutoShift](plugins/Kaleidoscope-AutoShift.md) plugin provides an alternative way to get shifted symbols, by long-pressing keys instead of using a separate `shift` key.

@ -0,0 +1,43 @@
// -*- mode: c++ -*-
#include <Kaleidoscope.h>
#include <Kaleidoscope-CharShift.h>
// *INDENT-OFF*
KEYMAPS(
[0] = KEYMAP_STACKED
(
XXX, 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,
XXX,
XXX, 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, CS(2), Key_Quote,
Key_skip, Key_N, Key_M, CS(0), CS(1), Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
XXX
),
)
// *INDENT-ON*
KALEIDOSCOPE_INIT_PLUGINS(CharShift);
void setup() {
CS_KEYS(
kaleidoscope::plugin::CharShift::KeyPair(Key_Comma, Key_Semicolon), // CS(0)
kaleidoscope::plugin::CharShift::KeyPair(Key_Period, LSHIFT(Key_Semicolon)), // CS(1)
kaleidoscope::plugin::CharShift::KeyPair(LSHIFT(Key_Comma), LSHIFT(Key_Period)), // CS(2)
);
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,6 @@
{
"cpu": {
"fqbn": "keyboardio:avr:model01",
"port": ""
}
}

@ -0,0 +1,66 @@
# CharShift
CharShift allows you to independently assign symbols to shifted and unshifted
positions of keymap entries. Either or both symbols can be ones that normally
requires the `shift` modifier, and either or both symbols can be ones normally
produced without it.
For example you can configure your keyboard so that a single key produces `,`
when pressed unshifted, but `;` when pressed with `shift` held. Or `(`
unshifted, and `[` shifted. Or `+`/`*` — all without changing your OS keyboard
layout.
## Using the plugin
Using the plugin with its defaults is as simple as including the header, and
enabling the plugin:
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-CharShift.h>
KALEIDOSCOPE_INIT_PLUGINS(CharShift);
```
Further configuration is required, of course; see below.
Note: CharShift should be registered in `KALEIDOSCOPE_INIT_PLUGINS()` after any
plugin that changes the event's `Key` value to that of an CharShift key.
## Configuring CharShift keys
To use CharShift, we must first define `KeyPair` objects, which can then be
referenced by entries in the keymap. This is easiest to do by using the
`UNKEYS()` preprocessor macro in the sketch's `setup()` function, as follows:
```c++
void setup() {
Kaleidoscope.setup();
UNKEYS(
kaleidoscope::plugin::KeyPair(Key_Comma, Key_Semicolon), // `,`/`;`
kaleidoscope::plugin::KeyPair(Key_Period, LSHIFT(Key_Semicolon)), // `.`/`:`
kaleidoscope::plugin::KeyPair(LSHIFT(Key_9), Key_LeftBracket), // `(`/`[`
kaleidoscope::plugin::KeyPair(LSHIFT(Key_Comma), LSHIFT(Key_LeftBracket)), // `<`/`{`
);
}
```
The first argument to the `KeyPair()` constructor is the value for when the key is
pressed without `shift` held, the second is what you'll get if a `shift`
modifier is being held when the key toggles on. If that second ("upper") value
doesn't have the `shift` modifier flag (i.e. `LSHIFT()`) applied to it, the held
`shift` modifier will be suppressed when the key is pressed, allowing the
"unshifted" symbol to be produced.
These `KeyPair`s can be referred to in the sketch's keymap by using the `UK()`
preprocessor macro, which takes an integer argument, referring to items in the
`UNKEYS()` array, starting with zero. With the example above, an entry of
`UK(2)` will output `(` when pressed without `shift`, and `[` if `shift` is
being held.
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting
started with the plugin.
[plugin:example]: /examples/Keystrokes/CharShift/CharShift.ino

@ -0,0 +1,7 @@
name=Kaleidoscope-CharShift
version=0.0.0
sentence=Independent assignment of symbols to keys based on shift state
maintainer=Kaleidoscope's Developers <jesse@keyboard.io>
url=https://github.com/keyboardio/Kaleidoscope
author=Michael Richters <gedankenexperimenter@gmail.com>
paragraph=

@ -0,0 +1,20 @@
/* -*- mode: c++ -*-
* Kaleidoscope-CharShift -- Independently assign shifted and unshifted symbols
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <kaleidoscope/plugin/CharShift.h>

@ -0,0 +1,149 @@
/* -*- mode: c++ -*-
* Kaleidoscope-CharShift -- Independently assign shifted and unshifted symbols
* 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 <http://www.gnu.org/licenses/>.
*/
#include "kaleidoscope/plugin/CharShift.h"
#include <Kaleidoscope-Ranges.h>
#include <Kaleidoscope-FocusSerial.h>
#include "kaleidoscope/KeyAddr.h"
#include "kaleidoscope/key_defs.h"
#include "kaleidoscope/KeyEvent.h"
#include "kaleidoscope/keyswitch_state.h"
#include "kaleidoscope/progmem_helpers.h"
#include "kaleidoscope/Runtime.h"
namespace kaleidoscope {
namespace plugin {
// =============================================================================
// CharShift class variables
CharShift::KeyPair const * CharShift::progmem_keypairs_{nullptr};
uint8_t CharShift::num_keypairs_{0};
bool CharShift::reverse_shift_state_{false};
// =============================================================================
// Event handlers
// -----------------------------------------------------------------------------
EventHandlerResult CharShift::onNameQuery() {
return ::Focus.sendName(F("CharShift"));
}
// -----------------------------------------------------------------------------
EventHandlerResult CharShift::onKeyEvent(KeyEvent &event) {
// If the event is for anything other than an CharShift key, we ignore it.
if (!isCharShiftKey(event.key)) {
// If this event is for a Keyboard key, we need to stop
// `beforeReportingState()` from suppressing `shift` keys.
if (event.key.isKeyboardKey())
reverse_shift_state_ = false;
return EventHandlerResult::OK;
}
// Default to not suppressing `shift` modifiers.
reverse_shift_state_ = false;
// It shouldn't be possible for an CharShift key to toggle off, because it
// will get replaced by on of its `KeyPair` values when it toggles on, but just
// in case, we exit early if that happens.
if (keyToggledOff(event.state))
return EventHandlerResult::OK;
// Next, we get the `KeyPair` values corresponding to the event key.
KeyPair keypair = decodeCharShiftKey(event.key);
// Determine if a shift key is being held.
bool shift_held = false;
for (Key key : live_keys.all()) {
if (key.isKeyboardShift()) {
shift_held = true;
break;
}
}
if (!shift_held) {
// No shift key is held; just use the base value of the `KeyPair`.
event.key = keypair.lower;
} else {
// At least one shift key is held; use the shifted value.
event.key = keypair.upper;
// Check for a shift modifier flag.
if (event.key.isKeyboardKey() &&
(event.key.getFlags() & SHIFT_HELD) == 0) {
// The upper key doesn't have the `shift` modifier flag; we need to
// suppress `shift` in `beforeReportingState()`.
reverse_shift_state_ = true;
}
}
return EventHandlerResult::OK;
}
// -----------------------------------------------------------------------------
EventHandlerResult CharShift::beforeReportingState(const KeyEvent &event) {
// If `onKeyEvent()` has signalled that `shift` should be suppressed, this is
// the time to do it. We can't do it in `onKeyEvent()`, because the new
// Keyboard HID report hasn't been prepared yet there.
if (reverse_shift_state_) {
Runtime.hid().keyboard().releaseKey(Key_LeftShift);
Runtime.hid().keyboard().releaseKey(Key_RightShift);
}
return EventHandlerResult::OK;
}
// =============================================================================
// Support functions
bool CharShift::isCharShiftKey(Key key) {
return (key >= ranges::CS_FIRST && key <= ranges::CS_LAST);
}
CharShift::KeyPair CharShift::decodeCharShiftKey(Key key) {
uint8_t i = key.getRaw() - ranges::CS_FIRST;
if (i < numKeyPairs()) {
return readKeyPair(i);
}
return {Key_NoKey, Key_NoKey};
}
// This should be overridden if the KeyPairs array is stored in EEPROM
__attribute__((weak))
uint8_t CharShift::numKeyPairs() {
return numProgmemKeyPairs();
}
// This should be overridden if the KeyPairs array is stored in EEPROM
__attribute__((weak))
CharShift::KeyPair CharShift::readKeyPair(uint8_t n) {
return readKeyPairFromProgmem(n);
}
uint8_t CharShift::numProgmemKeyPairs() {
return num_keypairs_;
}
CharShift::KeyPair CharShift::readKeyPairFromProgmem(uint8_t n) {
return cloneFromProgmem(progmem_keypairs_[n]);
}
} // namespace plugin
} // namespace kaleidoscope
kaleidoscope::plugin::CharShift CharShift;

@ -0,0 +1,137 @@
/* -*- mode: c++ -*-
* Kaleidoscope-CharShift -- Independently assign shifted and unshifted symbols
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "kaleidoscope/Runtime.h"
#include <Kaleidoscope-Ranges.h>
namespace kaleidoscope {
namespace plugin {
// =============================================================================
/// Kaleidoscope plugin for independently assigning shifted symbols
///
/// This plugin provides a way to define keys that, when `shift` is held, will
/// produce different symbols than they normally would. Either, both, or
/// neither of the symbols assigned to a key in this way can be ones that are
/// normally produced with the `shift` modifier. Crucially, when `shift` is
/// held, and the `Key` to be output does not have the `shift` modifier flag
/// applied to it, the held `shift` modifier will be suppressed.
class CharShift : public Plugin {
public:
EventHandlerResult onNameQuery();
EventHandlerResult onKeyEvent(KeyEvent &event);
EventHandlerResult beforeReportingState(const KeyEvent &event);
// ---------------------------------------------------------------------------
/// A structure that stores CharShift key pair values
///
/// This structure stores two separate `Key` values: `lower` (to be used when
/// a key is pressed without `shift` held), and `upper` (to be used when
/// `shift` is held).
struct KeyPair {
Key lower;
Key upper;
/// Constructor for use in PROGMEM
///
/// This constructor is used when defining an array of `KeyPair` objects in
/// PROGMEM (though it can also be used elsewhere).
constexpr KeyPair(Key lower, Key upper) : lower(lower), upper(upper) {}
/// Constructor for reading from PROGMEM
///
/// This constructor is used by the helper function that copies values from
/// PROGMEM so that they can be used normally.
KeyPair() = default;
};
/// Configure the KeyPairs array in PROGMEM
///
/// This function configures the PROGMEM array of `KeyPair` objects,
/// automatically setting the internal count variable from the size of the
/// `keypairs` array given, which must be a fixed-sized array, not a pointer.
/// Generally, it will be called via the `KEYPAIRS()` preprocessor macro, not
/// directly by user code.
template <uint8_t _num_keypairs>
static void setProgmemKeyPairs(KeyPair const(&keypairs)[_num_keypairs]) {
progmem_keypairs_ = keypairs;
num_keypairs_ = _num_keypairs;
}
private:
// A pointer to an array of `KeyPair` objects in PROGMEM
static KeyPair const * progmem_keypairs_;
// The size of the PROGMEM array of `KeyPair` objects
static uint8_t num_keypairs_;
// If a `shift` key needs to be suppressed in `beforeReportingState()`
static bool reverse_shift_state_;
/// Test for keys that should be handled by CharShift
static bool isCharShiftKey(Key key);
/// Look up the `KeyPair` specified by the given keymap entry
static KeyPair decodeCharShiftKey(Key key);
/// Get the total number of KeyPairs defined
///
/// This function can be overridden in order to store the `KeyPair` array in
/// EEPROM instead of PROGMEM.
static uint8_t numKeyPairs();
/// Get the `KeyPair` at the specified index from the defined `KeyPair` array
///
/// This function can be overridden in order to store the `KeyPair` array in
/// EEPROM instead of PROGMEM.
static KeyPair readKeyPair(uint8_t n);
// Default for `keypairsCount()`: size of the PROGMEM array
static uint8_t numProgmemKeyPairs();
// Default for `readKeypair(i)`: fetch the value from PROGMEM
static KeyPair readKeyPairFromProgmem(uint8_t n);
};
} // namespace plugin
} // namespace kaleidoscope
extern kaleidoscope::plugin::CharShift CharShift;
/// Define an array of `KeyPair` objects in PROGMEM
///
/// This preprocessor macro takes a list of `KeyPair` objects as arguments, and
/// defines them as an array in PROGMEM, and configures `CharShift` to use that
/// array, automatically setting the count correctly to prevent out-of-bounds
/// lookups.
#define CS_KEYS(keypairs...) { \
static kaleidoscope::plugin::CharShift::KeyPair const kp_table[] PROGMEM = { \
keypairs \
}; \
CharShift.setProgmemKeyPairs(kp_table); \
}
/// Define an `KeyPair` entry in a keymap
///
/// This defines a `Key` object that will be handled by the CharShift plugin.
/// The argument `n` is the index number of the `KeyPair` in the array (starting
/// at zero).
constexpr kaleidoscope::Key CS(uint8_t n) {
return kaleidoscope::Key(kaleidoscope::ranges::CS_FIRST + n);
}

@ -41,6 +41,8 @@ namespace ranges {
// important for compatibility with existing Chrysalis keymaps, despite the fact
// that it makes the code more obtuse here.
constexpr uint8_t MAX_CS_KEYS = 64;
enum : uint16_t {
// Macro ranges pre-date Kaleidoscope-Ranges, so they're coming before
// ranges::FIRST, because we want to keep the keycodes backwards compatible.
@ -83,6 +85,8 @@ enum : uint16_t {
OS_META_STICKY,
OS_ACTIVE_STICKY,
OS_CANCEL,
CS_FIRST,
CS_LAST = CS_FIRST + MAX_CS_KEYS,
SAFE_START,
KALEIDOSCOPE_SAFE_START = SAFE_START

@ -25,6 +25,9 @@ namespace testing {
class Issue1010 : public ::testing::Test {
public:
static constexpr uint8_t MAX_CS_KEYS = 64;
enum : uint16_t {
MACRO_FIRST = (SYNTHETIC | 0b00100000) << 8,
MACRO_LAST = MACRO_FIRST + 255,
@ -62,6 +65,8 @@ class Issue1010 : public ::testing::Test {
OS_META_STICKY,
OS_ACTIVE_STICKY,
OS_CANCEL,
CS_FIRST,
CS_LAST = CS_FIRST + MAX_CS_KEYS,
SAFE_START,
KALEIDOSCOPE_SAFE_START = SAFE_START
@ -140,6 +145,11 @@ TEST_F(Issue1010, RangesHaveNotChanged) {
uint16_t(kaleidoscope::ranges::OS_ACTIVE_STICKY));
ASSERT_EQ(uint16_t(Issue1010::OS_CANCEL),
uint16_t(kaleidoscope::ranges::OS_CANCEL));
ASSERT_EQ(uint16_t(Issue1010::CS_FIRST),
uint16_t(kaleidoscope::ranges::CS_FIRST));
ASSERT_EQ(uint16_t(Issue1010::CS_LAST),
uint16_t(kaleidoscope::ranges::CS_LAST));
ASSERT_EQ(uint16_t(Issue1010::SAFE_START),
uint16_t(kaleidoscope::ranges::SAFE_START));
ASSERT_EQ(uint16_t(Issue1010::KALEIDOSCOPE_SAFE_START),

@ -0,0 +1,55 @@
/* -*- 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 <http://www.gnu.org/licenses/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-CharShift.h>
// *INDENT-OFF*
KEYMAPS(
[0] = KEYMAP_STACKED
(
Key_LeftShift, Key_RightShift, ___, ___, ___, ___, ___,
Key_X, LSHIFT(Key_Y), ___, ___, ___, ___, ___,
CS(0), CS(1), CS(2), CS(3), ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___,
___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___,
___
),
)
// *INDENT-ON*
KALEIDOSCOPE_INIT_PLUGINS(CharShift);
void setup() {
Kaleidoscope.setup();
CS_KEYS(
kaleidoscope::plugin::CharShift::KeyPair(Key_A, Key_B),
kaleidoscope::plugin::CharShift::KeyPair(Key_C, LSHIFT(Key_D)),
kaleidoscope::plugin::CharShift::KeyPair(LSHIFT(Key_E), Key_F),
kaleidoscope::plugin::CharShift::KeyPair(LSHIFT(Key_G), LSHIFT(Key_H)),
);
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,6 @@
{
"cpu": {
"fqbn": "keyboardio:virtual:model01",
"port": ""
}
}

@ -0,0 +1,212 @@
VERSION 1
KEYSWITCH LSHIFT 0 0
KEYSWITCH RSHIFT 0 1
KEYSWITCH x 1 0
KEYSWITCH Y 1 1
KEYSWITCH CS_ab 2 0
KEYSWITCH CS_cD 2 1
KEYSWITCH CS_Ef 2 2
KEYSWITCH CS_GH 2 3
# ==============================================================================
NAME CharShift lower lower
RUN 4 ms
PRESS CS_ab
RUN 1 cycle
EXPECT keyboard-report Key_A # report: { 4 }
RUN 4 ms
RELEASE CS_ab
RUN 1 cycle
EXPECT keyboard-report empty
RUN 4 ms
PRESS LSHIFT
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
RUN 4 ms
PRESS CS_ab
RUN 1 cycle
EXPECT keyboard-report empty
EXPECT keyboard-report Key_B # report: { 5 }
RUN 4 ms
RELEASE CS_ab
RUN 1 cycle
EXPECT keyboard-report empty
EXPECT keyboard-report Key_LeftShift # report: { e1 }
RUN 4 ms
RELEASE LSHIFT
RUN 1 cycle
EXPECT keyboard-report empty
RUN 5 ms
# ==============================================================================
NAME CharShift lower upper
RUN 4 ms
PRESS CS_cD
RUN 1 cycle
EXPECT keyboard-report Key_C # report: { 6 }
RUN 4 ms
RELEASE CS_cD
RUN 1 cycle
EXPECT keyboard-report empty
RUN 4 ms
PRESS LSHIFT
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
RUN 4 ms
PRESS CS_cD
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift Key_D # report: { e1 7 }
RUN 4 ms
RELEASE CS_cD
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
RUN 4 ms
RELEASE LSHIFT
RUN 1 cycle
EXPECT keyboard-report empty
RUN 5 ms
# ==============================================================================
NAME CharShift upper lower
RUN 4 ms
PRESS CS_Ef
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
EXPECT keyboard-report Key_LeftShift Key_E # report: { e1 8 }
RUN 4 ms
RELEASE CS_Ef
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
EXPECT keyboard-report empty
RUN 4 ms
PRESS LSHIFT
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
RUN 4 ms
PRESS CS_Ef
RUN 1 cycle
EXPECT keyboard-report empty
EXPECT keyboard-report Key_F # report: { 9 }
RUN 4 ms
RELEASE CS_Ef
RUN 1 cycle
EXPECT keyboard-report empty
EXPECT keyboard-report Key_LeftShift # report: { e1 }
RUN 4 ms
RELEASE LSHIFT
RUN 1 cycle
EXPECT keyboard-report empty
RUN 5 ms
# ==============================================================================
NAME CharShift upper upper
RUN 4 ms
PRESS CS_GH
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
EXPECT keyboard-report Key_LeftShift Key_G # report: { e1 10 }
RUN 4 ms
RELEASE CS_GH
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
EXPECT keyboard-report empty
RUN 4 ms
PRESS LSHIFT
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
RUN 4 ms
PRESS CS_GH
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift Key_H # report: { e1 11 }
RUN 4 ms
RELEASE CS_GH
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
RUN 4 ms
RELEASE LSHIFT
RUN 1 cycle
EXPECT keyboard-report empty
RUN 5 ms
# ==============================================================================
NAME Rollover from normal to CharShift upper
RUN 4 ms
PRESS x
RUN 1 cycle
EXPECT keyboard-report Key_X
RUN 4 ms
PRESS CS_GH
RUN 1 cycle
EXPECT keyboard-report Key_X Key_LeftShift # report: { e1 }
EXPECT keyboard-report Key_X Key_LeftShift Key_G # report: { e1 10 }
RUN 4 ms
RELEASE x
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift Key_G # report: { e1 10 }
RUN 4 ms
RELEASE CS_GH
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
EXPECT keyboard-report empty
RUN 5 ms
# ==============================================================================
NAME Rollover from shifted to CharShift lower
RUN 4 ms
PRESS Y
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
EXPECT keyboard-report Key_LeftShift Key_Y
RUN 4 ms
PRESS CS_ab
RUN 1 cycle
EXPECT keyboard-report Key_Y
EXPECT keyboard-report Key_Y Key_A
RUN 4 ms
RELEASE Y
RUN 1 cycle
EXPECT keyboard-report Key_A
RUN 4 ms
RELEASE CS_ab
RUN 1 cycle
EXPECT keyboard-report empty
RUN 5 ms
Loading…
Cancel
Save