Merge pull request #1036 from gedankenexperimenter/plugin/autoshift

Add AutoShift plugin
pull/1045/head
Gergely Nagy 3 years ago committed by GitHub
commit 72d4ac8124
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -215,6 +215,10 @@ To make it easier to port Kaleidoscope, we introduced the `ATMegaKeyboard` base
## New plugins
### 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.
### DynamicMacros
The [DynamicMacros](plugins/Kaleidoscope-DynamicMacros.md) plugin provides a way to use and update macros via the Focus API, through Chrysalis.

@ -0,0 +1,75 @@
// -*- mode: c++ -*-
#include <Kaleidoscope.h>
#include <Kaleidoscope-AutoShift.h>
#include <Kaleidoscope-EEPROM-Settings.h>
#include <Kaleidoscope-EEPROM-Keymap.h>
#include <Kaleidoscope-FocusSerial.h>
#include <Kaleidoscope-Macros.h>
enum {
TOGGLE_AUTOSHIFT,
};
// *INDENT-OFF*
KEYMAPS(
[0] = KEYMAP_STACKED
(
Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
XXX,
M(TOGGLE_AUTOSHIFT), Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
XXX
),
)
// *INDENT-ON*
// Defining a macro (on the "any" key: see above) to turn AutoShift on and off
const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
switch (macro_id) {
case TOGGLE_AUTOSHIFT:
if (keyToggledOn(event.state))
AutoShift.toggle();
break;
}
return MACRO_NONE;
}
KALEIDOSCOPE_INIT_PLUGINS(
EEPROMSettings, // for AutoShiftConfig
EEPROMKeymap, // for AutoShiftConfig
Focus, // for AutoShiftConfig
FocusEEPROMCommand, // for AutoShiftConfig
FocusSettingsCommand, // for AutoShiftConfig
AutoShift,
AutoShiftConfig, // for AutoShiftConfig
Macros // for toggle AutoShift Macro
);
void setup() {
// Enable AutoShift for letter keys and number keys only:
AutoShift.setEnabled(AutoShift.letterKeys() | AutoShift.numberKeys());
// Add symbol keys to the enabled categories:
AutoShift.enable(AutoShift.symbolKeys());
// Set the AutoShift long-press time to 150ms:
AutoShift.setTimeout(150);
// Start with AutoShift turned off:
AutoShift.disable();
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

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

@ -0,0 +1,86 @@
# AutoShift
AutoShift allows you to type shifted characters by long-pressing a key, rather
than chording it with a modifier key.
## 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-AutoShift.h>
KALEIDOSCOPE_INIT_PLUGINS(AutoShift);
```
With AutoShift enabled, when you first press a key that AutoShift acts on, its
output will be delayed. If you hold the key down long enough, you will see the
shifted symbol appear in the output. If you release the key before the timeout,
the output will be unshifted.
## Turning AutoShift on and off
The `AutoShift` object provides three methods for turning itself on and off:
- To turn the plugin off, call `AutoShift.enable()`.
- To turn the plugin on, call `AutoShift.disable()`.
- To toggle the plugin's state, call `AutoShift.toggle()`.
Note: Disabling the AutoShift plugin does not affect which `Key` categories it
will affect when it is re-enabled.
## Setting the AutoShift long-press delay
To set the length of time AutoShift will wait before adding the `shift` modifier
to the key's output, use `AutoShift.setTimeout(t)`, where `t` is a number of
milliseconds.
## Configuring which keys get auto-shifted
AutoShift provides a set of key categories that can be independently added or
removed from the set of keys that will be auto-shifted when long-pressed:
- `AutoShift.letterKeys()`: Letter keys
- `AutoShift.numberKeys()`: Number keys (number row, not numeric keypad)
- `AutoShift.symbolKeys()`: Other printable symbols
- `AutoShift.arrowKeys()`: Navigational arrow keys
- `AutoShift.functionKeys()`: All function keys (F1-F24)
- `AutoShift.printableKeys()`: Letters, numbers, and symbols
- `AutoShift.allKeys()`: All non-modifier USB Keyboard keys
These categories are restricted to USB Keyboard-type keys, and any modifier
flags attached to the key is ignored when determining if it will be
auto-shifted. Any of the above expressions can be used as the `category` parameter in the functions described below.
- To include a category in the set that will be auto-shifted, call `AutoShift.enable(category)`
- To remove a category from the set that will be auto-shifted, call `AutoShift.disable(category)`
- To set the full list of categories that will be auto-shifted, call `AutoShift.setEnabled(categories)`, where `categories` can be either a single category from the above list, or list of categories combined using the `|` (bitwise-or) operator (e.g. `AutoShift.setEnabled(AutoShift.letterKeys() | AutoShift.numberKeys())`).
## Advanced customization of which keys get auto-shifted
If the above categories are not sufficient for your auto-shifting needs, it is
possible to get even finer-grained control of which keys are affected by
AutoShift, by overriding the `isAutoShiftable()` method in your sketch. For
example, to make AutoShift only act on keys `A` and `Z`, include the following
code in your sketch:
```c++
bool AutoShift::isAutoShiftable(Key key) {
if (key == Key_A || key == key_Z)
return true;
return false;
}
```
As you can see, this method takes a `Key` as its input and returns either `true`
(for keys eligible to be auto-shifted) or `false` (for keys AutoShift will leave
alone).
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting
started with the plugin.
[plugin:example]: /examples/Keystrokes/AutoShift/AutoShift.ino

@ -0,0 +1,7 @@
name=Kaleidoscope-AutoShift
version=0.0.0
sentence=Automatic shift on long press
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-AutoShift -- Automatic shift on long press
* 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/AutoShift.h>

@ -0,0 +1,212 @@
/* -*- mode: c++ -*-
* Kaleidoscope-AutoShift -- Automatic shift on long press
* 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/AutoShift.h"
#include "kaleidoscope/KeyAddr.h"
#include "kaleidoscope/key_defs.h"
#include "kaleidoscope/KeyEvent.h"
#include "kaleidoscope/keyswitch_state.h"
#include "kaleidoscope/Runtime.h"
namespace kaleidoscope {
namespace plugin {
// =============================================================================
// AutoShift static class variables
// Configuration settings that can be saved to persistent storage.
AutoShift::Settings AutoShift::settings_ = {
.enabled = true,
.timeout = 175,
.enabled_categories = AutoShift::Categories::printableKeys(),
};
// The event tracker ensures that the `onKeyswitchEvent()` handler will follow
// the rules in order to avoid interference with other plugins and prevent
// processing the same event more than once.
KeyEventTracker AutoShift::event_tracker_;
// If there's a delayed keypress from AutoShift, this stored event will contain
// a valid `KeyAddr`. The default constructor produces an event addr of
// `KeyAddr::none()`, so the plugin will start in an inactive state.
KeyEvent pending_event_;
// =============================================================================
// AutoShift functions
void AutoShift::disable() {
settings_.enabled = false;
if (pending_event_.addr.isValid()) {
Runtime.handleKeyswitchEvent(pending_event_);
}
}
// -----------------------------------------------------------------------------
// Test for whether or not to apply AutoShift to a given `Key`. This function
// can be overridden from the user sketch.
__attribute__((weak))
bool AutoShift::isAutoShiftable(Key key) {
return enabledForKey(key);
}
// The default method that determines whether a particular key is an auto-shift
// candidate. Used by `isAutoShiftable()`, separate to allow re-use when the
// caller is overridden.
bool AutoShift::enabledForKey(Key key) {
// We only support auto-shifting keyboard keys. We could also explicitly
// ignore modifier keys, but there's no need to do so, as none of the code
// below matches modifiers.
if (!key.isKeyboardKey())
return false;
// We compare only the keycode, and disregard any modifier flags applied to
// the key. This simplifies the comparison, and also allows AutoShift to
// apply to keys like `RALT(Key_E)`.
uint8_t keycode = key.getKeyCode();
if (isEnabled(Categories::allKeys())) {
if (keycode < HID_KEYBOARD_FIRST_MODIFIER)
return true;
}
if (isEnabled(Categories::letterKeys())) {
if (keycode >= Key_A.getKeyCode() && keycode <= Key_Z.getKeyCode())
return true;
}
if (isEnabled(Categories::numberKeys())) {
if (keycode >= Key_1.getKeyCode() && keycode <= Key_0.getKeyCode())
return true;
}
if (isEnabled(Categories::symbolKeys())) {
if ((keycode >= Key_Minus.getKeyCode() && keycode <= Key_Slash.getKeyCode()) ||
(keycode == Key_NonUsBackslashAndPipe.getKeyCode()))
return true;
}
if (isEnabled(Categories::arrowKeys())) {
if (keycode >= Key_RightArrow.getKeyCode() &&
keycode <= Key_LeftArrow.getKeyCode())
return true;
}
if (isEnabled(Categories::functionKeys())) {
if ((keycode >= Key_F1.getKeyCode() && keycode <= Key_F12.getKeyCode()) ||
(keycode >= Key_F13.getKeyCode() && keycode <= Key_F24.getKeyCode()))
return true;
}
return false;
}
// =============================================================================
// Event handler hook functions
// -----------------------------------------------------------------------------
EventHandlerResult AutoShift::onKeyswitchEvent(KeyEvent &event) {
// If AutoShift has already processed and released this event, ignore it.
// There's no need to update the event tracker in this one case.
if (event_tracker_.shouldIgnore(event)) {
// We should never get an event that's in our queue here, but just in case
// some other plugin sends one, abort.
if (queue_.shouldAbort(event))
return EventHandlerResult::ABORT;
return EventHandlerResult::OK;
}
// If event.addr is not a physical key, ignore it; some other plugin injected
// it. This check should be unnecessary.
if (!event.addr.isValid() || (event.state & INJECTED) != 0) {
return EventHandlerResult::OK;
}
// Do nothing if disabled.
if (!settings_.enabled)
return EventHandlerResult::OK;
if (!queue_.isEmpty()) {
// There's an unresolved AutoShift key press.
if (queue_.isFull()) {
flushQueue();
} else if (event.addr == queue_.addr(0)) {
flushEvent(false);
flushQueue();
}
if (queue_.isEmpty())
return EventHandlerResult::OK;
queue_.append(event);
return EventHandlerResult::ABORT;
}
if (keyToggledOn(event.state) && isAutoShiftable(event.key)) {
queue_.append(event);
return EventHandlerResult::ABORT;
}
return EventHandlerResult::OK;
}
// -----------------------------------------------------------------------------
EventHandlerResult AutoShift::afterEachCycle() {
// If there's a pending AutoShift event, and it has timed out, we need to
// release the event with the `shift` flag applied.
if (!queue_.isEmpty() &&
Runtime.hasTimeExpired(queue_.timestamp(0), settings_.timeout)) {
// Toggle the state of the `SHIFT_HELD` bit in the modifier flags for the
// key for the pending event.
flushEvent(true);
flushQueue();
}
return EventHandlerResult::OK;
}
void AutoShift::flushQueue() {
while (!queue_.isEmpty()) {
if (queue_.isRelease(0) || checkForRelease()) {
flushEvent(false);
} else {
return;
}
}
}
bool AutoShift::checkForRelease() const {
KeyAddr queue_head_addr = queue_.addr(0);
for (uint8_t i = 1; i < queue_.length(); ++i) {
if (queue_.addr(i) == queue_head_addr) {
// This key's release is also in the queue
return true;
}
}
return false;
}
void AutoShift::flushEvent(bool is_long_press) {
if (queue_.isEmpty())
return;
KeyEvent event = queue_.event(0);
if (is_long_press) {
event.key = Runtime.lookupKey(event.addr);
uint8_t flags = event.key.getFlags();
flags ^= SHIFT_HELD;
event.key.setFlags(flags);
}
queue_.shift();
Runtime.handleKeyswitchEvent(event);
}
} // namespace plugin
} // namespace kaleidoscope
kaleidoscope::plugin::AutoShift AutoShift;

@ -0,0 +1,278 @@
/* -*- mode: c++ -*-
* Kaleidoscope-AutoShift -- Automatic shift on long press
* 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/KeyEventTracker.h"
#include "kaleidoscope/KeyAddrEventQueue.h"
namespace kaleidoscope {
namespace plugin {
// =============================================================================
/// Kaleidoscope plugin for long-press auto-shift keys
///
/// This plugin allows the user to "long-press" keys to automatically apply the
/// `shift` modifier to the keypress. By enabling AutoShift, it's possible to
/// produce capital letters (for example) without holding a separate modifier
/// key first.
class AutoShift : public Plugin {
public:
// ---------------------------------------------------------------------------
// Inner class for `Key` categories that can be configured to be auto-shifted
// by long-pressing. Most of this class is purely internal, but user code
// that enables or disables these auto-shift categories might use the
// following as constants:
//
// - `AutoShift::Categories::letterKeys()`
// - `AutoShift::Categories::numberKeys()`
// - `AutoShift::Categories::symbolKeys()`
// - `AutoShift::Categories::arrowKeys()`
// - `AutoShift::Categories::functionKeys()`
// - `AutoShift::Categories::printableKeys()`
// - `AutoShift::Categories::allKeys()`
//
// The first two ("letter keys" and "number keys") are self-explanatory. The
// third ("symbol keys") includes keys that produce symbols other than letters
// and numbers, but not whitespace characters, modifiers, et cetera. We could
// perhaps add another category for function keys.
class Categories {
private:
// raw bitfield data
uint8_t raw_bits_{0};
// constants for bits in the `raw_bits_` bitfield
static constexpr uint8_t LETTERS = 1 << 0;
static constexpr uint8_t NUMBERS = 1 << 1;
static constexpr uint8_t SYMBOLS = 1 << 2;
static constexpr uint8_t ARROWS = 1 << 3;
static constexpr uint8_t FUNCTIONS = 1 << 4;
static constexpr uint8_t ALL = 1 << 7;
public:
// Basic un-checked constructor
constexpr Categories(uint8_t raw_bits) : raw_bits_(raw_bits) {}
static constexpr Categories letterKeys() {
return Categories(LETTERS);
}
static constexpr Categories numberKeys() {
return Categories(NUMBERS);
}
static constexpr Categories symbolKeys() {
return Categories(SYMBOLS);
}
static constexpr Categories arrowKeys() {
return Categories(ARROWS);
}
static constexpr Categories functionKeys() {
return Categories(FUNCTIONS);
}
static constexpr Categories printableKeys() {
return Categories(LETTERS | NUMBERS | SYMBOLS);
}
static constexpr Categories allKeys() {
return Categories(ALL);
}
constexpr void set(uint8_t raw_bits) {
raw_bits_ = raw_bits;
}
constexpr void add(Categories categories) {
this->raw_bits_ |= categories.raw_bits_;
}
constexpr void remove(Categories categories) {
this->raw_bits_ &= ~(categories.raw_bits_);
}
constexpr bool contains(Categories categories) const {
return (this->raw_bits_ & categories.raw_bits_) != 0;
// More correct test:
// return (~(this->raw_bits_) & categories.raw_bits_) == 0;
}
// Shorthand for combining categories:
// e.g. `Categories::letterKeys() | Categories::numberKeys()`
constexpr Categories operator|(Categories other) const {
return Categories(this->raw_bits_ | other.raw_bits_);
}
// A conversion to integer is provided for the sake of interactions with the
// Focus plugin.
explicit constexpr operator uint8_t() {
return raw_bits_;
}
};
// ---------------------------------------------------------------------------
// This lets the AutoShiftConfig plugin access the internal config variables
// directly. Mainly useful for calls to `Runtime.storage.get()`.
friend class AutoShiftConfig;
// ---------------------------------------------------------------------------
// Configuration functions
/// Returns `true` if AutoShift is active, `false` otherwise
static bool enabled() {
return settings_.enabled;
}
/// Activates the AutoShift plugin (held keys will trigger auto-shift)
static void enable() {
settings_.enabled = true;
}
/// Deactivates the AutoShift plugin (held keys will not trigger auto-shift)
static void disable();
/// Turns AutoShift on if it's off, and vice versa
static void toggle() {
if (settings_.enabled) {
disable();
} else {
enable();
}
}
/// Returns the hold time required to trigger auto-shift (in ms)
static uint16_t timeout() {
return settings_.timeout;
}
/// Sets the hold time required to trigger auto-shift (in ms)
static void setTimeout(uint16_t new_timeout) {
settings_.timeout = new_timeout;
}
/// Returns the set of categories currently eligible for auto-shift
static Categories enabledCategories() {
return settings_.enabled_categories;
}
/// Adds `category` to the set eligible for auto-shift
///
/// Possible values for `category` are:
/// - `AutoShift::Categories::letterKeys()`
/// - `AutoShift::Categories::numberKeys()`
/// - `AutoShift::Categories::symbolKeys()`
/// - `AutoShift::Categories::arrowKeys()`
/// - `AutoShift::Categories::functionKeys()`
/// - `AutoShift::Categories::printableKeys()`
/// - `AutoShift::Categories::allKeys()`
static void enable(Categories category) {
settings_.enabled_categories.add(category);
}
/// Removes a `Key` category from the set eligible for auto-shift
static void disable(Categories category) {
settings_.enabled_categories.remove(category);
}
/// Replaces the list of `Key` categories eligible for auto-shift
static void setEnabled(Categories categories) {
settings_.enabled_categories = categories;
}
/// Returns `true` if the given category is eligible for auto-shift
static bool isEnabled(Categories category) {
return settings_.enabled_categories.contains(category);
}
/// The category representing letter keys
static constexpr Categories letterKeys() {
return Categories::letterKeys();
}
/// The category representing number keys (on the number row)
static constexpr Categories numberKeys() {
return Categories::numberKeys();
}
/// The category representing other printable symbol keys
static constexpr Categories symbolKeys() {
return Categories::symbolKeys();
}
/// The category representing arrow keys
static constexpr Categories arrowKeys() {
return Categories::arrowKeys();
}
/// The category representing function keys
static constexpr Categories functionKeys() {
return Categories::functionKeys();
}
/// Letters, numbers, and other symbols
static constexpr Categories printableKeys() {
return Categories::printableKeys();
}
/// All non-modifier keyboard keys
static constexpr Categories allKeys() {
return Categories::allKeys();
}
// ---------------------------------------------------------------------------
/// Determines which keys will trigger auto-shift if held long enough
///
/// This function can be overridden by the user sketch to configure which keys
/// can trigger auto-shift.
static bool isAutoShiftable(Key key);
// ---------------------------------------------------------------------------
// Event handlers
EventHandlerResult onKeyswitchEvent(KeyEvent &event);
EventHandlerResult afterEachCycle();
private:
// ---------------------------------------------------------------------------
/// A container for AutoShift configuration settings
struct Settings {
/// The overall state of the plugin (on/off)
bool enabled;
/// The length of time (ms) a key must be held to trigger auto-shift
uint16_t timeout;
/// The set of `Key` categories eligible to be auto-shifted
Categories enabled_categories;
};
static Settings settings_;
// ---------------------------------------------------------------------------
// Key event queue state variables
// A device for processing only new events
static KeyEventTracker event_tracker_;
// The maximum number of events in the queue at a time.
static constexpr uint8_t queue_capacity_{4};
// The event queue stores a series of press and release events.
KeyAddrEventQueue<queue_capacity_> queue_;
void flushQueue();
void flushEvent(bool is_long_press = false);
bool checkForRelease() const;
/// The default function for `isAutoShiftable()`
static bool enabledForKey(Key key);
};
// =============================================================================
/// Configuration plugin for persistent storage of settings
class AutoShiftConfig : public Plugin {
public:
EventHandlerResult onSetup();
EventHandlerResult onFocusEvent(const char *command);
private:
// The base address in persistent storage for configuration data
static uint16_t settings_base_;
};
} // namespace plugin
} // namespace kaleidoscope
extern kaleidoscope::plugin::AutoShift AutoShift;
extern kaleidoscope::plugin::AutoShiftConfig AutoShiftConfig;

@ -0,0 +1,121 @@
/* -*- mode: c++ -*-
* Kaleidoscope-AutoShift -- Automatic shift on long press
* 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/AutoShift.h"
#include <Kaleidoscope-EEPROM-Settings.h>
#include <Kaleidoscope-FocusSerial.h>
#include "kaleidoscope/Runtime.h"
namespace kaleidoscope {
namespace plugin {
// =============================================================================
// AutoShift configurator
uint16_t AutoShiftConfig::settings_base_;
EventHandlerResult AutoShiftConfig::onSetup() {
settings_base_ = ::EEPROMSettings.requestSlice(sizeof(AutoShift::settings_));
uint32_t checker;
Runtime.storage().get(settings_base_, checker);
// Check if we have an empty eeprom...
if (checker == 0xffffffff) {
// ...if the eeprom was empty, store the default settings.
Runtime.storage().put(settings_base_, AutoShift::settings_);
Runtime.storage().commit();
}
Runtime.storage().get(settings_base_, AutoShift::settings_);
return EventHandlerResult::OK;
}
EventHandlerResult AutoShiftConfig::onFocusEvent(const char *command) {
enum {
ENABLED,
TIMEOUT,
CATEGORIES,
} subCommand;
if (::Focus.handleHelp(command, PSTR("autoshift.enabled\n"
"autoshift.timeout\n"
"autoshift.categories")))
return EventHandlerResult::OK;
if (strncmp_P(command, PSTR("autoshift."), 10) != 0)
return EventHandlerResult::OK;
if (strcmp_P(command + 10, PSTR("enabled")) == 0)
subCommand = ENABLED;
else if (strcmp_P(command + 10, PSTR("timeout")) == 0)
subCommand = TIMEOUT;
else if (strcmp_P(command + 10, PSTR("categories")) == 0)
subCommand = CATEGORIES;
else
return EventHandlerResult::OK;
switch (subCommand) {
case ENABLED:
if (::Focus.isEOL()) {
::Focus.send(::AutoShift.enabled());
} else {
uint8_t v;
::Focus.read(v);
// if (::Focus.readUint8() != 0) {
if (v != 0) {
::AutoShift.enable();
} else {
::AutoShift.disable();
}
}
break;
case TIMEOUT:
if (::Focus.isEOL()) {
::Focus.send(::AutoShift.timeout());
} else {
uint16_t t;
::Focus.read(t);
// auto t = ::Focus.readUint16();
::AutoShift.setTimeout(t);
}
break;
case CATEGORIES:
if (::Focus.isEOL()) {
::Focus.send(uint8_t(::AutoShift.enabledCategories()));
} else {
uint8_t v;
::Focus.read(v);
auto categories = AutoShift::Categories(v);
// auto categories = AutoShift::Categories(::Focus.readUint8());
::AutoShift.setEnabled(categories);
}
break;
}
Runtime.storage().put(settings_base_, AutoShift::settings_);
Runtime.storage().commit();
return EventHandlerResult::EVENT_CONSUMED;
}
} // namespace plugin
} // namespace kaleidoscope
kaleidoscope::plugin::AutoShiftConfig AutoShiftConfig;

@ -0,0 +1,50 @@
/* -*- 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-AutoShift.h>
// *INDENT-OFF*
KEYMAPS(
[0] = KEYMAP_STACKED
(
Key_LeftShift, Key_RightShift, ___, ___, ___, ___, ___,
Key_A, Key_B, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___,
___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___,
___
),
)
// *INDENT-ON*
KALEIDOSCOPE_INIT_PLUGINS(AutoShift);
void setup() {
Kaleidoscope.setup();
AutoShift.setTimeout(20);
}
void loop() {
Kaleidoscope.loop();
}

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

@ -0,0 +1,41 @@
VERSION 1
KEYSWITCH LSHIFT 0 0
KEYSWITCH RSHIFT 0 1
KEYSWITCH A 1 0
KEYSWITCH B 1 1
# ==============================================================================
NAME AutoShift tap
RUN 4 ms
PRESS A
RUN 1 cycle
RUN 4 ms
RELEASE A
RUN 1 cycle
EXPECT keyboard-report Key_A # report: { 4 }
EXPECT keyboard-report empty
RUN 5 ms
# ==============================================================================
NAME AutoShift long press
RUN 4 ms
PRESS A
RUN 1 cycle
# Timeout is 20ms
RUN 20 ms
EXPECT keyboard-report Key_LeftShift # report: { e1 }
EXPECT keyboard-report Key_LeftShift Key_A # report: { 4 e1 }
RUN 4 ms
RELEASE A
RUN 1 cycle
EXPECT keyboard-report Key_LeftShift # report: { e1 }
EXPECT keyboard-report empty
RUN 5 ms
Loading…
Cancel
Save