Compare commits

..

No commits in common. 'main' and 'f/handleHelp-varargs' have entirely different histories.

1
.gitignore vendored

@ -13,4 +13,3 @@
/results/ /results/
generated-testcase.cpp generated-testcase.cpp
.arduino .arduino
/bin/arduino-cli

@ -5,7 +5,7 @@ Flexible firmware for Arduino-powered keyboards.
This package contains the "core" of Kaleidoscope and a number of [example firmware "Sketches"](https://github.com/keyboardio/Kaleidoscope/tree/master/examples). This package contains the "core" of Kaleidoscope and a number of [example firmware "Sketches"](https://github.com/keyboardio/Kaleidoscope/tree/master/examples).
If you're just getting started with the Keyboardio Model 01, the [introductory docs are here](https://github.com/keyboardio/Kaleidoscope/wiki/Keyboardio-Model-01-Introduction) and the source for the basic firmware package is here: https://github.com/keyboardio/Model01-Firmware. It's probably a good idea to start there, learn how to modify your keymap and maybe turn some modules on or off, and then come back to the full repository when you have more complex changes in mind. (The firmware for all other devices is inside examples/Devices in this Kaleidoscope repo.) If you're just getting started with the Keyboardio Model 01, the [introductory docs are here](https://github.com/keyboardio/Kaleidoscope/wiki/Keyboardio-Model-01-Introduction) and the source for the basic firmware package is here: https://github.com/keyboardio/Model01-Firmware. It's probably a good idea to start there, learn how to modify your keymap and maybe turn some modules on or off, and then come back to the full repository when you have more complex changes in mind.
# Getting Started # Getting Started

@ -14,5 +14,3 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2300", SYMLINK+="
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2301", SYMLINK+="model01", ENV{ID_MM_DEVICE_IGNORE}:="1", ENV{ID_MM_CANDIDATE}:="0", TAG+="uaccess", TAG+="seat" SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2301", SYMLINK+="model01", ENV{ID_MM_DEVICE_IGNORE}:="1", ENV{ID_MM_CANDIDATE}:="0", TAG+="uaccess", TAG+="seat"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2302", SYMLINK+="Atreus2", ENV{ID_MM_DEVICE_IGNORE}:="1", ENV{ID_MM_CANDIDATE}:="0", TAG+="uaccess", TAG+="seat" SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2302", SYMLINK+="Atreus2", ENV{ID_MM_DEVICE_IGNORE}:="1", ENV{ID_MM_CANDIDATE}:="0", TAG+="uaccess", TAG+="seat"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2303", SYMLINK+="Atreus2", ENV{ID_MM_DEVICE_IGNORE}:="1", ENV{ID_MM_CANDIDATE}:="0", TAG+="uaccess", TAG+="seat" SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2303", SYMLINK+="Atreus2", ENV{ID_MM_DEVICE_IGNORE}:="1", ENV{ID_MM_CANDIDATE}:="0", TAG+="uaccess", TAG+="seat"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="3496", ATTRS{idProduct}=="0005", SYMLINK+="model100", ENV{ID_MM_DEVICE_IGNORE}:="1", ENV{ID_MM_CANDIDATE}:="0", TAG+="uaccess", TAG+="seat"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="3496", ATTRS{idProduct}=="0006", SYMLINK+="model100", ENV{ID_MM_DEVICE_IGNORE}:="1", ENV{ID_MM_CANDIDATE}:="0", TAG+="uaccess", TAG+="seat"

@ -164,7 +164,7 @@ endif
compile: kaleidoscope-hardware-configured compile: kaleidoscope-hardware-configured
-$(QUIET) install -d "${OUTPUT_PATH}" $(QUIET) install -d "${OUTPUT_PATH}"
$(QUIET) $(ARDUINO_CLI) compile --fqbn "${FQBN}" ${ARDUINO_VERBOSE} ${ccache_wrapper_property} ${local_cflags_property} \ $(QUIET) $(ARDUINO_CLI) compile --fqbn "${FQBN}" ${ARDUINO_VERBOSE} ${ccache_wrapper_property} ${local_cflags_property} \
${_arduino_local_libraries_prop} ${_ARDUINO_CLI_COMPILE_CUSTOM_FLAGS} \ ${_arduino_local_libraries_prop} ${_ARDUINO_CLI_COMPILE_CUSTOM_FLAGS} \
--library "${KALEIDOSCOPE_DIR}" \ --library "${KALEIDOSCOPE_DIR}" \
@ -191,9 +191,10 @@ endif
#TODO (arduino team) I'd love to do this with their json output #TODO (arduino team) I'd love to do this with their json output
#but it's short some of the data we kind of need #but it's short some of the data we kind of need
flashing_instructions = $(call _arduino_prop,build.flashing_instructions) flashing_instructions = $(call _arduino_prop,build.flashing_instructions)
_device_port = $(shell $(ARDUINO_CLI) board list --format=text | grep $(FQBN) |cut -d' ' -f 1)
flash: ${HEX_FILE_PATH} flash: ${HEX_FILE_PATH}
ifneq ($(flashing_instructions),) ifneq ($(flashing_instructions),)
$(info $(shell printf $(flashing_instructions))) $(info $(shell printf $(flashing_instructions)))
@ -204,11 +205,11 @@ endif
$(info When you're ready to proceed, press 'Enter'.) $(info When you're ready to proceed, press 'Enter'.)
$(info ) $(info )
@$(shell read _) @$(shell read _)
# If we have a device serial port available, try to trigger a Kaliedoscope reset # If we have a device serial port available, try to trigger a Kaliedoscope reset
-$(QUIET) export DEVICE=$(shell $(ARDUINO_CLI) board list --format=text | grep $(FQBN) |cut -d' ' -f 1) && \ ifneq ($(_device_port),)
[ -e "$$DEVICE" ] && \ -$(QUIET) DEVICE=$(_device_port) $(KALEIDOSCOPE_DIR)/bin/focus-send "device.reset"
$(KALEIDOSCOPE_DIR)/bin/focus-send "device.reset" && \ sleep 2
sleep 2 endif
$(QUIET) $(ARDUINO_CLI) upload --fqbn $(FQBN) \ $(QUIET) $(ARDUINO_CLI) upload --fqbn $(FQBN) \
$(shell $(ARDUINO_CLI) board list --format=text | grep $(FQBN) |cut -d' ' -f 1 | xargs -n 1 echo "--port" ) \ $(shell $(ARDUINO_CLI) board list --format=text | grep $(FQBN) |cut -d' ' -f 1 | xargs -n 1 echo "--port" ) \
--input-dir "${OUTPUT_PATH}" \ --input-dir "${OUTPUT_PATH}" \

@ -21,7 +21,7 @@
#include "Kaleidoscope-FirmwareVersion.h" #include "Kaleidoscope-FirmwareVersion.h"
// Support for keys that move the mouse // Support for keys that move the mouse
// #include "Kaleidoscope-MouseKeys.h" #include "Kaleidoscope-MouseKeys.h"
// Support for macros // Support for macros
#include "Kaleidoscope-Macros.h" #include "Kaleidoscope-Macros.h"
@ -30,7 +30,7 @@
#include "Kaleidoscope-LEDControl.h" #include "Kaleidoscope-LEDControl.h"
// Support for "Numpad" mode, which is mostly just the Numpad specific LED mode // Support for "Numpad" mode, which is mostly just the Numpad specific LED mode
// #include "Kaleidoscope-NumPad.h" #include "Kaleidoscope-NumPad.h"
// Support for the "Boot greeting" effect, which pulses the 'LED' button for 10s // Support for the "Boot greeting" effect, which pulses the 'LED' button for 10s
// when the keyboard is connected to a computer (or that computer is powered on) // when the keyboard is connected to a computer (or that computer is powered on)
@ -95,7 +95,7 @@
#include "Kaleidoscope-LayerNames.h" #include "Kaleidoscope-LayerNames.h"
// Support for the GeminiPR Stenography protocol // Support for the GeminiPR Stenography protocol
// #include "Kaleidoscope-Steno.h" #include "Kaleidoscope-Steno.h"
/** This 'enum' is a list of all the macros used by the Model 100's firmware /** This 'enum' is a list of all the macros used by the Model 100's firmware
* The names aren't particularly important. What is important is that each * The names aren't particularly important. What is important is that each
@ -166,9 +166,8 @@ enum {
enum { enum {
PRIMARY, PRIMARY,
// NUMPAD, NUMPAD,
FUNCTION, FUNCTION,
ETC,
}; // layers }; // layers
@ -185,10 +184,10 @@ enum {
* *
*/ */
// #define PRIMARY_KEYMAP_QWERTY #define PRIMARY_KEYMAP_QWERTY
// #define PRIMARY_KEYMAP_DVORAK // #define PRIMARY_KEYMAP_DVORAK
// #define PRIMARY_KEYMAP_COLEMAK // #define PRIMARY_KEYMAP_COLEMAK
#define PRIMARY_KEYMAP_CUSTOM // #define PRIMARY_KEYMAP_CUSTOM
/* This comment temporarily turns off astyle's indent enforcement /* This comment temporarily turns off astyle's indent enforcement
@ -198,37 +197,82 @@ enum {
KEYMAPS( KEYMAPS(
#if defined (PRIMARY_KEYMAP_QWERTY)
[PRIMARY] = KEYMAP_STACKED [PRIMARY] = KEYMAP_STACKED
(___, ___, ___, ___, ___, ___, Key_LEDEffectNext, (___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
___, Key_Q, Key_W, Key_D, Key_F, Key_K, Key_Tab, Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
___, Key_A, Key_S, Key_E, Key_T, Key_G, Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_Backtick, Key_Z, Key_X, Key_C, Key_V, Key_B, LCTRL(LALT(Key_LeftGui)), Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
GUI_T(Tab), ALT_T(Backspace), CTL_T(Escape), Key_LeftShift, Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
ShiftToLayer(FUNCTION), ShiftToLayer(FUNCTION),
M(MACRO_ANY), ___, Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, ___, M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Consumer_VolumeIncrement, Key_J, Key_U, Key_R, Key_L, Key_Semicolon, Key_Backslash, Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_Y, Key_N, Key_I, Key_O, Key_H, Key_Quote, Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Consumer_VolumeDecrement, Key_P, Key_M, Key_Comma, Key_Period, Key_Slash, ___, Key_RightAlt, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, ALT_T(Enter), Key_Spacebar, GUI_T(Tab), Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
ShiftToLayer(FUNCTION)), ShiftToLayer(FUNCTION)),
[FUNCTION] = KEYMAP_STACKED #elif defined (PRIMARY_KEYMAP_DVORAK)
(___, Key_F1, Key_F2, Key_F3, Key_F4, Key_F5, ___,
___, LSHIFT(Key_1), LSHIFT(Key_2), LSHIFT(Key_LeftBracket), LSHIFT(Key_RightBracket), LSHIFT(Key_Backslash), ___,
LSHIFT(Key_7), LSHIFT(Key_3), LSHIFT(Key_4), LSHIFT(Key_9), LSHIFT(Key_0), Key_Backslash,
LSHIFT(Key_Backtick), LSHIFT(Key_5), LSHIFT(Key_6), Key_LeftBracket, Key_RightBracket, LSHIFT(Key_8), ___,
___, Key_Delete, ___, ___,
___,
___, Key_F6, Key_F7, Key_F8, Key_F9, Key_F10, Key_F11, [PRIMARY] = KEYMAP_STACKED
___, Key_Equals, Key_7, Key_8, Key_9, LSHIFT(Key_Equals), Key_F12, (___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
Key_Minus, Key_4, Key_5, Key_6, Key_Quote, ___, Key_Backtick, Key_Quote, Key_Comma, Key_Period, Key_P, Key_Y, Key_Tab,
___, LSHIFT(Key_Minus), Key_1, Key_2, Key_3, LSHIFT(Key_Quote), ___, Key_PageUp, Key_A, Key_O, Key_E, Key_U, Key_I,
___, ___, Key_Enter, Key_0, Key_PageDown, Key_Semicolon, Key_Q, Key_J, Key_K, Key_X, Key_Escape,
___), Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
ShiftToLayer(FUNCTION),
M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_F, Key_G, Key_C, Key_R, Key_L, Key_Slash,
Key_D, Key_H, Key_T, Key_N, Key_S, Key_Minus,
Key_RightAlt, Key_B, Key_M, Key_W, Key_V, Key_Z, Key_Equals,
Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
ShiftToLayer(FUNCTION)),
[ETC] = KEYMAP_STACKED #elif defined (PRIMARY_KEYMAP_COLEMAK)
[PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
Key_Backtick, Key_Q, Key_W, Key_F, Key_P, Key_B, Key_Tab,
Key_PageUp, Key_A, Key_R, Key_S, Key_T, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_D, Key_V, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
ShiftToLayer(FUNCTION),
M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_J, Key_L, Key_U, Key_Y, Key_Semicolon, Key_Equals,
Key_M, Key_N, Key_E, Key_I, Key_O, Key_Quote,
Key_RightAlt, Key_K, Key_H, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
ShiftToLayer(FUNCTION)),
#elif defined (PRIMARY_KEYMAP_CUSTOM)
// Edit this keymap to make a custom layout
[PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
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,
ShiftToLayer(FUNCTION),
M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
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_RightAlt, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
ShiftToLayer(FUNCTION)),
#else
#error "No default keymap defined. You should make sure that you have a line like '#define PRIMARY_KEYMAP_QWERTY' in your sketch"
#endif
[NUMPAD] = KEYMAP_STACKED
(___, ___, ___, ___, ___, ___, ___, (___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___,
@ -236,13 +280,27 @@ KEYMAPS(
___, ___, ___, ___, ___, ___, ___, ___,
___, ___,
___, ___, ___, ___, ___, ___, ___, M(MACRO_VERSION_INFO), ___, Key_7, Key_8, Key_9, Key_KeypadSubtract, ___,
___, ___, Key_F7, Key_F8, Key_F9, Key_Home, ___, ___, ___, Key_4, Key_5, Key_6, Key_KeypadAdd, ___,
___, Key_F4, Key_F5, Key_F6, Key_End, ___, ___, Key_1, Key_2, Key_3, Key_Equals, ___,
___, ___, Key_F1, Key_F2, Key_F3, Key_Insert, ___, ___, ___, Key_0, Key_Period, Key_KeypadMultiply, Key_KeypadDivide, Key_Enter,
___, ___, ___, ___, ___, ___, ___, ___,
___) ___),
[FUNCTION] = KEYMAP_STACKED
(___, Key_F1, Key_F2, Key_F3, Key_F4, Key_F5, Key_CapsLock,
Key_Tab, ___, Key_mouseUp, ___, Key_mouseBtnR, Key_mouseWarpEnd, Key_mouseWarpNE,
Key_Home, Key_mouseL, Key_mouseDn, Key_mouseR, Key_mouseBtnL, Key_mouseWarpNW,
Key_End, Key_PrintScreen, Key_Insert, ___, Key_mouseBtnM, Key_mouseWarpSW, Key_mouseWarpSE,
___, Key_Delete, ___, ___,
___,
Consumer_ScanPreviousTrack, Key_F6, Key_F7, Key_F8, Key_F9, Key_F10, Key_F11,
Consumer_PlaySlashPause, Consumer_ScanNextTrack, Key_LeftCurlyBracket, Key_RightCurlyBracket, Key_LeftBracket, Key_RightBracket, Key_F12,
Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, ___, ___,
Key_PcApplication, Consumer_Mute, Consumer_VolumeDecrement, Consumer_VolumeIncrement, ___, Key_Backslash, Key_Pipe,
___, ___, Key_Enter, ___,
___)
) // KEYMAPS( ) // KEYMAPS(
/* Re-enable astyle's indent enforcement */ /* Re-enable astyle's indent enforcement */
@ -409,8 +467,8 @@ KALEIDOSCOPE_INIT_PLUGINS(
// SpaceCadet can turn your shifts into parens on tap, while keeping them as // SpaceCadet can turn your shifts into parens on tap, while keeping them as
// Shifts when held. SpaceCadetConfig lets Chrysalis configure some aspects of // Shifts when held. SpaceCadetConfig lets Chrysalis configure some aspects of
// the plugin. // the plugin.
// SpaceCadet, SpaceCadet,
// SpaceCadetConfig, SpaceCadetConfig,
// Focus allows bi-directional communication with the host, and is the // Focus allows bi-directional communication with the host, and is the
// interface through which the keymap in EEPROM can be edited. // interface through which the keymap in EEPROM can be edited.
@ -479,13 +537,13 @@ KALEIDOSCOPE_INIT_PLUGINS(
// The numpad plugin is responsible for lighting up the 'numpad' mode // The numpad plugin is responsible for lighting up the 'numpad' mode
// with a custom LED effect // with a custom LED effect
// NumPad, NumPad,
// The macros plugin adds support for macros // The macros plugin adds support for macros
Macros, Macros,
// The MouseKeys plugin lets you add keys to your keymap which move the mouse. // The MouseKeys plugin lets you add keys to your keymap which move the mouse.
// MouseKeys, MouseKeys,
// The HostPowerManagement plugin allows us to turn LEDs off when then host // The HostPowerManagement plugin allows us to turn LEDs off when then host
// goes to sleep, and resume them when it wakes up. // goes to sleep, and resume them when it wakes up.
@ -530,12 +588,11 @@ KALEIDOSCOPE_INIT_PLUGINS(
// Enables setting, saving (via Chrysalis), and restoring (on boot) the // Enables setting, saving (via Chrysalis), and restoring (on boot) the
// default LED mode. // default LED mode.
DefaultLEDModeConfig DefaultLEDModeConfig,
// Enables the GeminiPR Stenography protocol. Unused by default, but with the // Enables the GeminiPR Stenography protocol. Unused by default, but with the
// plugin enabled, it becomes configurable - and then usable - via Chrysalis. // plugin enabled, it becomes configurable - and then usable - via Chrysalis.
//GeminiPR GeminiPR);
);
/** The 'setup' function is one of the two standard Arduino sketch functions. /** The 'setup' function is one of the two standard Arduino sketch functions.
* It's called when your keyboard first powers up. This is where you set up * It's called when your keyboard first powers up. This is where you set up
@ -551,7 +608,7 @@ void setup() {
// While we hope to improve this in the future, the NumPad plugin // While we hope to improve this in the future, the NumPad plugin
// needs to be explicitly told which keymap layer is your numpad layer // needs to be explicitly told which keymap layer is your numpad layer
// NumPad.numPadLayer = NUMPAD; NumPad.numPadLayer = NUMPAD;
// We configure the AlphaSquare effect to use RED letters // We configure the AlphaSquare effect to use RED letters
AlphaSquare.color = CRGB(255, 0, 0); AlphaSquare.color = CRGB(255, 0, 0);
@ -592,8 +649,7 @@ void setup() {
// To avoid any surprises, SpaceCadet is turned off by default. However, it // To avoid any surprises, SpaceCadet is turned off by default. However, it
// can be permanently enabled via Chrysalis, so we should only disable it if // can be permanently enabled via Chrysalis, so we should only disable it if
// no configuration exists. // no configuration exists.
// SpaceCadetConfig.disableSpaceCadetIfUnconfigured(); SpaceCadetConfig.disableSpaceCadetIfUnconfigured();
// SpaceCadet.disable();
// Editable layer names are stored in EEPROM too, and we reserve 16 bytes per // Editable layer names are stored in EEPROM too, and we reserve 16 bytes per
// layer for them. We need one extra byte per layer for bookkeeping, so we // layer for them. We need one extra byte per layer for bookkeeping, so we

@ -214,7 +214,6 @@ void Model100Side::sendLEDData() {
} }
} }
auto constexpr gamma8 = kaleidoscope::driver::color::gamma_correction;
void Model100Side::sendLEDBank(uint8_t bank) { void Model100Side::sendLEDBank(uint8_t bank) {
uint8_t data[LED_BYTES_PER_BANK + 1]; uint8_t data[LED_BYTES_PER_BANK + 1];
@ -230,25 +229,25 @@ void Model100Side::sendLEDBank(uint8_t bank) {
else else
c = 0; c = 0;
data[i + 1] = pgm_read_byte(&gamma8[c]); data[i + 1] = c;
} }
uint8_t result = writeData(data, ELEMENTS(data)); uint8_t result = writeData(data, ELEMENTS(data));
} }
void Model100Side::setAllLEDsTo(cRGB color) { void Model100Side::setAllLEDsTo(cRGB color) {
uint8_t data[] = {TWI_CMD_LED_SET_ALL_TO, uint8_t data[] = {TWI_CMD_LED_SET_ALL_TO,
pgm_read_byte(&gamma8[color.b]), color.b,
pgm_read_byte(&gamma8[color.g]), color.g,
pgm_read_byte(&gamma8[color.r])}; color.r};
uint8_t result = writeData(data, ELEMENTS(data)); uint8_t result = writeData(data, ELEMENTS(data));
} }
void Model100Side::setOneLEDTo(uint8_t led, cRGB color) { void Model100Side::setOneLEDTo(uint8_t led, cRGB color) {
uint8_t data[] = {TWI_CMD_LED_SET_ONE_TO, uint8_t data[] = {TWI_CMD_LED_SET_ONE_TO,
led, led,
pgm_read_byte(&gamma8[color.b]), color.b,
pgm_read_byte(&gamma8[color.g]), color.g,
pgm_read_byte(&gamma8[color.r])}; color.r};
uint8_t result = writeData(data, ELEMENTS(data)); uint8_t result = writeData(data, ELEMENTS(data));
} }

@ -20,41 +20,39 @@
#include <Arduino.h> // IWYU pragma: keep #include <Arduino.h> // IWYU pragma: keep
#include <stdint.h> // for uint8_t #include <stdint.h> // for uint8_t
#ifdef ARDUINO_ARCH_GD32
#include "USBCore.h"
#endif
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult, EventHandlerResult::OK #include "kaleidoscope/event_handler_result.h" // for EventHandlerResult, EventHandlerResult::OK
// This is a terrible hack until Arduino#6964 gets implemented.
// It makes the `_usbSuspendState` symbol available to us.
extern uint8_t _usbSuspendState;
namespace kaleidoscope { namespace kaleidoscope {
namespace plugin { namespace plugin {
bool HostPowerManagement::was_suspended_ = false; bool HostPowerManagement::was_suspended_ = false;
bool HostPowerManagement::initial_suspend_ = true;
bool HostPowerManagement::isSuspended() {
#if defined(__AVR__)
return USBDevice.isSuspended();
#elif defined(ARDUINO_ARCH_GD32)
return USBCore().isSuspended();
#else
return false;
#endif
}
EventHandlerResult HostPowerManagement::beforeEachCycle() { EventHandlerResult HostPowerManagement::beforeEachCycle() {
if (isSuspended()) {
if (!was_suspended_) { #ifdef __AVR__
was_suspended_ = true; if ((_usbSuspendState & (1 << SUSPI))) {
hostPowerManagementEventHandler(Suspend); if (!initial_suspend_) {
} else { if (!was_suspended_) {
hostPowerManagementEventHandler(Sleep); was_suspended_ = true;
hostPowerManagementEventHandler(Suspend);
} else {
hostPowerManagementEventHandler(Sleep);
}
} }
} else { } else {
if (initial_suspend_)
initial_suspend_ = false;
if (was_suspended_) { if (was_suspended_) {
was_suspended_ = false; was_suspended_ = false;
hostPowerManagementEventHandler(Resume); hostPowerManagementEventHandler(Resume);
} }
} }
#endif
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }

@ -34,8 +34,7 @@ class HostPowerManagement : public kaleidoscope::Plugin {
private: private:
static bool was_suspended_; static bool was_suspended_;
static bool initial_suspend_;
bool isSuspended();
}; };
} // namespace plugin } // namespace plugin

@ -37,23 +37,21 @@ void setup() {
The plugin provides a number of keys one can put on the keymap, that allow The plugin provides a number of keys one can put on the keymap, that allow
control of the mouse. They can be divided into a few groups: control of the mouse. They can be divided into a few groups:
### Mouse buttons
Mouse button keys are straightforward; pressing one is the same as pressing the
corresponding button on a physical mouse. You can hold a mouse button key to
perform drag gestures, as you might expect. MouseKeys supports five mouse
buttons: left, right, middle, previous, and next.
* `Key_mouseBtnL`, `Key_mouseBtnM`, `Key_mouseBtnR`, `Key_mouseBtnP`,
`Key_mouseBtnN`: The left, middle, right, previous, and next mouse buttons,
respectively.
### Cursor movement ### Cursor movement
When a cursor movement key is pressed, the mouse cursor will begin to move The simplest set of keys are the mouse cursor movement keys. These move the
slowly, then accelerate to full speed. Both the full speed and the time it cursor one direction or the other, with speed and acceleration factored in. When
takes to reach full speed are configurable. a mouse cursor movement key is held down, it will move `.speed` pixels each
`.speedDelay` milliseconds without acceleration. But when `.accelSpeed` is
non-zero (and it is not zero by default,
see [below](#accelspeed-and-acceldelay)), the speed will increase by
`.accelSpeed` every `.accelDelay` milliseconds. Thus, unless configured
otherwise, holding a direction will move that way at increasing speed.
One can hold more than one key down at the same time, and the cursor will move
towards a direction that is the combination of the keys held. For example,
holding the "mouse up" and "mouse right" keys together will move the cursor
diagonally up and right.
The cursor movement keys are as follows: The cursor movement keys are as follows:
@ -62,18 +60,26 @@ The cursor movement keys are as follows:
* `Key_mouseUpL`, `Key_mouseUpR`, `Key_mouseDnL`, `Key_mouseDnR`: Move the * `Key_mouseUpL`, `Key_mouseUpR`, `Key_mouseDnL`, `Key_mouseDnR`: Move the
cursor up-left, up-right, down-left, down-right, respectively. cursor up-left, up-right, down-left, down-right, respectively.
### Scroll wheels ### Scroll wheel
Controlling the scroll wheel is similarly simple. It does not have Controlling the scroll wheel is similarly simple. It does not have acceleration,
acceleration, but one can control the speed with the but one can control the speed with the `.wheelSpeed` and `.wheelDelay`
`MouseKeys.setScrollInterval()` function, which controls the length of time properties (see below).
between scroll events.
* `Key_mouseScrollUp`, `Key_mouseScrollDn`: Scroll the mouse wheel up or down, * `Key_mouseScrollUp`, `Key_mouseScrollDn`: Scroll the mouse wheel up or down,
respectively. respectively.
* `Key_mouseScrollL`, `Key_mouseScrollR`: Scroll the mouse wheel left or right, * `Key_mouseScrollL`, `Key_mouseScrollR`: Scroll the mouse wheel left or right,
respectively. respectively.
### Buttons
Buttons are even simpler than movement: there is no movement speed, nor
acceleration involved. One just presses them.
* `Key_mouseBtnL`, `Key_mouseBtnM`, `Key_mouseBtnR`, `Key_mouseBtnP`,
`Key_mouseBtnN`: The left, middle, right, previous, and next mouse buttons,
respectively.
## Warping ## Warping
Warping is one of the most interesting features of the plugin, and is a feature Warping is one of the most interesting features of the plugin, and is a feature
@ -204,32 +210,37 @@ the following additions:
The plugin provides a `MouseKeys` object, with the following methods and The plugin provides a `MouseKeys` object, with the following methods and
properties available: properties available:
### `.setCursorInitSpeed(speed)`/`.getCursorInitSpeed()` ### `.speed` and `.speedDelay`
> Controls (or returns) the current starting speed value for mouse cursor > These two control the speed of the mouse cursor, when a movement key is held.
> movement. When a mouse movement key is pressed, the cursor starts moving at > The former, `.speed`, controls the amount of pixels the cursor moves, when it
> this speed, then accelerates. The number is abstract, but linear, with higher > has to move, and defaults to 1. The latter, `.speedDelay` is the amount of
> numbers representing faster speeds. Default starting speed is `1`. > time - in milliseconds - to wait between two movements, and defaults to 0, no
> delay.
### `.setCursorBaseSpeed(speed)`/`.getCursorBaseSpeed()` ### `.accelSpeed` and `.accelDelay`
> Controls (or returns) the current top speed value for mouse cursor movement. > These two properties control the speed of acceleration. The former,
> When a mouse movement key is pressed, the cursor accelerates until it reaches > `.accelSpeed`, controls how much the speed shall be increased at each step,
> this speed. The number is abstract, but linear, with higher numbers > while the second, `.accelDelay`, controls how often (in milliseconds)
> representing faster speeds. Default full-speed value is `50`. > acceleration should be applied.
>
> They default to 1 pixel and 50 milliseconds, respectively.
### `.setCursorAccelDuration(duration)`/`.getCursorAccelDuration()` ### `.wheelSpeed` and `.wheelDelay`
> Controls (or returns) the current time it takes for the mouse cursor to reach > The last two properties supported by the plugin control the mouse wheel
> full speed (in milliseconds), starting from when the first movement key is > scrolling speed. The former, `.wheelSpeed`, controls the amount of ticks the
> pressed. Default value is `800` ms. > wheel shall scroll, and defaults to 1. The second, `.wheelDelay`, controls the
> delay between two scroll events, and defaults to 50 milliseconds.
### `.setScrollInterval(interval)`/`.getScrollInterval()` ### `.setSpeedLimit`
> Controls (or returns) the current scrolling speed, by setting the time between > This method sets the maximum speed after which acceleration stops.
> mouse scroll reports (in milliseconds). Default value is `50` ms. > The default is 127, and the minimum value is 16 (things will not work
> properly below 16).
### `.setWarpGridSize(size)` ### `.setWarpGridSize`
> This method changes the size of the grid used for [warping](#warping). The > This method changes the size of the grid used for [warping](#warping). The
> following are valid sizes: `MOUSE_WARP_GRID_2X2`, `MOUSE_WARP_GRID_3X3` > following are valid sizes: `MOUSE_WARP_GRID_2X2`, `MOUSE_WARP_GRID_3X3`

@ -1,5 +1,5 @@
/* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope. /* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope.
* Copyright (C) 2017-2022 Keyboard.io, Inc. * Copyright (C) 2017-2021 Keyboard.io, Inc.
* *
* This program is free software: you can redistribute it and/or modify it under * 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 * the terms of the GNU General Public License as published by the Free Software
@ -29,14 +29,11 @@
#include "kaleidoscope/key_defs.h" // for Key, SYNTHETIC #include "kaleidoscope/key_defs.h" // for Key, SYNTHETIC
#include "kaleidoscope/keyswitch_state.h" // for keyToggledOn #include "kaleidoscope/keyswitch_state.h" // for keyToggledOn
#include "kaleidoscope/plugin/mousekeys/MouseKeyDefs.h" // for KEY_MOUSE_BUTTON, KEY_MOUS... #include "kaleidoscope/plugin/mousekeys/MouseKeyDefs.h" // for KEY_MOUSE_BUTTON, KEY_MOUS...
#include "kaleidoscope/plugin/mousekeys/MouseWrapper.h" // for MouseWrapper, WARP_DOWN #include "kaleidoscope/plugin/mousekeys/MouseWrapper.h" // for MouseWrapper, wrapper, WAR...
namespace kaleidoscope { namespace kaleidoscope {
namespace plugin { namespace plugin {
#ifndef NDEPRECATED
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
uint8_t MouseKeys::speed = 1; uint8_t MouseKeys::speed = 1;
uint16_t MouseKeys::speedDelay = 1; uint16_t MouseKeys::speedDelay = 1;
@ -45,14 +42,16 @@ uint16_t MouseKeys::accelDelay = 64;
uint8_t MouseKeys::wheelSpeed = 1; uint8_t MouseKeys::wheelSpeed = 1;
uint16_t MouseKeys::wheelDelay = 50; uint16_t MouseKeys::wheelDelay = 50;
#pragma GCC diagnostic pop
#endif
// ============================================================================= // =============================================================================
// Configuration functions // Configuration functions
void MouseKeys::setWarpGridSize(uint8_t grid_size) { void MouseKeys::setWarpGridSize(uint8_t grid_size) {
MouseWrapper.warp_grid_size = grid_size; mousekeys::wrapper.warp_grid_size = grid_size;
}
void MouseKeys::setSpeedLimit(uint8_t speed_limit) {
mousekeys::wrapper.speed_limit = speed_limit;
} }
// ============================================================================= // =============================================================================
@ -93,6 +92,7 @@ EventHandlerResult MouseKeys::onNameQuery() {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
EventHandlerResult MouseKeys::onSetup() { EventHandlerResult MouseKeys::onSetup() {
kaleidoscope::Runtime.hid().mouse().setup();
kaleidoscope::Runtime.hid().absoluteMouse().setup(); kaleidoscope::Runtime.hid().absoluteMouse().setup();
return EventHandlerResult::OK; return EventHandlerResult::OK;
@ -100,20 +100,23 @@ EventHandlerResult MouseKeys::onSetup() {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
EventHandlerResult MouseKeys::afterEachCycle() { EventHandlerResult MouseKeys::afterEachCycle() {
if (directions_ == 0) // Check timeout for accel update interval.
return EventHandlerResult::OK; if (Runtime.hasTimeExpired(accel_start_time_, accelDelay)) {
accel_start_time_ = Runtime.millisAtCycleStart();
// `accel_step` determines the movement speed of the mouse pointer, and gets
// reset to zero when no mouse movement keys is pressed (see below).
if (mousekeys::wrapper.accel_step < 255 - accelSpeed) {
mousekeys::wrapper.accel_step += accelSpeed;
}
}
// Check timeout for position update interval. // Check timeout for position update interval.
if (Runtime.hasTimeExpired(last_cursor_update_time_, cursor_update_interval_)) { if (Runtime.hasTimeExpired(move_start_time_, speedDelay))
sendMouseMoveReport(); sendMouseMoveReport();
last_cursor_update_time_ += cursor_update_interval_;
}
// Check timeout for scroll report interval. // Check timeout for scroll report interval.
if (Runtime.hasTimeExpired(last_wheel_update_time_, settings_.wheel_update_interval)) { if (Runtime.hasTimeExpired(wheel_start_time_, wheelDelay))
sendMouseWheelReport(); sendMouseWheelReport();
last_wheel_update_time_ += settings_.wheel_update_interval;
}
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
@ -129,15 +132,10 @@ EventHandlerResult MouseKeys::onKeyEvent(KeyEvent &event) {
// Clear button state; it will be repopulated by `onAddToReport()`, and the // Clear button state; it will be repopulated by `onAddToReport()`, and the
// report will be sent by `afterReportingState()`. // report will be sent by `afterReportingState()`.
buttons_ = 0; buttons_ = 0;
}
if (keyToggledOn(event.state)) { } else if (isMouseWarpKey(event.key)) {
if (isMouseWarpKey(event.key)) { if (keyToggledOn(event.state)) {
// If a mouse warp key toggles on, we immediately send the warp report.
sendMouseWarpReport(event); sendMouseWarpReport(event);
} else {
// If any non-warp mouse key toggles on, we cancel warping.
MouseWrapper.endWarping();
} }
} }
@ -159,27 +157,20 @@ EventHandlerResult MouseKeys::afterReportingState(const KeyEvent &event) {
sendMouseButtonReport(); sendMouseButtonReport();
} }
// If no mouse move keys were active before this event, and a mouse movement
// key toggled on, we need to set the move start time so that acceleration can
// begin correctly.
if ((directions_ & cursor_mask_) == 0) {
cursor_start_time_ = Runtime.millisAtCycleStart();
}
// A mouse key event has been successfully registered, and we have now // A mouse key event has been successfully registered, and we have now
// gathered all the information on held mouse movement and wheel keys, so it's // gathered all the information on held mouse movement and wheel keys, so it's
// safe to update the direction information. // safe to update the direction information.
directions_ = pending_directions_; directions_ = pending_directions_;
pending_directions_ = 0; pending_directions_ = 0;
if (keyToggledOn(event.state)) { if (isMouseMoveKey(event.key)) {
if (isMouseMoveKey(event.key)) { // When a cursor movement key toggles on, set the acceleration start time in
sendMouseMoveReport(); // order to get consistent behavior.
last_cursor_update_time_ = Runtime.millisAtCycleStart(); accel_start_time_ = Runtime.millisAtCycleStart();
} else if (isMouseWheelKey(event.key)) { sendMouseMoveReport();
sendMouseWheelReport();
last_wheel_update_time_ = Runtime.millisAtCycleStart(); } else if (isMouseWheelKey(event.key)) {
} sendMouseWheelReport();
} }
return EventHandlerResult::OK; return EventHandlerResult::OK;
@ -219,7 +210,7 @@ void MouseKeys::sendMouseButtonReport() const {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MouseKeys::sendMouseWarpReport(const KeyEvent &event) const { void MouseKeys::sendMouseWarpReport(const KeyEvent &event) const {
MouseWrapper.warp( mousekeys::wrapper.warp(
((event.key.getKeyCode() & KEY_MOUSE_WARP_END) ? WARP_END : 0x00) | ((event.key.getKeyCode() & KEY_MOUSE_WARP_END) ? WARP_END : 0x00) |
((event.key.getKeyCode() & KEY_MOUSE_UP) ? WARP_UP : 0x00) | ((event.key.getKeyCode() & KEY_MOUSE_UP) ? WARP_UP : 0x00) |
((event.key.getKeyCode() & KEY_MOUSE_DOWN) ? WARP_DOWN : 0x00) | ((event.key.getKeyCode() & KEY_MOUSE_DOWN) ? WARP_DOWN : 0x00) |
@ -228,148 +219,57 @@ void MouseKeys::sendMouseWarpReport(const KeyEvent &event) const {
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void MouseKeys::sendMouseMoveReport() const { void MouseKeys::sendMouseMoveReport() {
int8_t dx = 0; move_start_time_ = Runtime.millisAtCycleStart();
int8_t dy = 0;
uint8_t direction = directions_ & cursor_mask_; int8_t vx = 0;
int8_t vy = 0;
uint8_t direction = directions_ & move_mask_;
if (direction != 0) { if (direction == 0) {
// Calculate // If there are no mouse movement keys held, reset speed to zero.
uint8_t delta = cursorDelta(); mousekeys::wrapper.accel_step = 0;
// For each active direction, add the move update interval value to } else {
// normalize speed of motion regardless of the frequency of updates. // For each active direction, add the mouse movement speed.
if (direction & KEY_MOUSE_LEFT) if (direction & KEY_MOUSE_LEFT)
dx -= delta; vx -= speed;
if (direction & KEY_MOUSE_RIGHT) if (direction & KEY_MOUSE_RIGHT)
dx += delta; vx += speed;
if (direction & KEY_MOUSE_UP) if (direction & KEY_MOUSE_UP)
dy -= delta; vy -= speed;
if (direction & KEY_MOUSE_DOWN) if (direction & KEY_MOUSE_DOWN)
dy += delta; vy += speed;
// Prepare the mouse report.
mousekeys::wrapper.move(vx, vy);
// Send the report. // Send the report.
Runtime.hid().mouse().move(dx, dy, 0, 0);
Runtime.hid().mouse().sendReport(); Runtime.hid().mouse().sendReport();
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Get the current point on the acceleration curve's x axis, translating time void MouseKeys::sendMouseWheelReport() {
// elapsed since mouse movement started to a value between 0 and 255. wheel_start_time_ = Runtime.millisAtCycleStart();
uint8_t MouseKeys::accelStep() const {
uint16_t elapsed_time = Runtime.millisAtCycleStart() - cursor_start_time_;
uint16_t accel_duration = settings_.cursor_accel_duration;
if (elapsed_time > accel_duration)
return 255;
uint16_t accel_step = (uint32_t(elapsed_time) * 256) / accel_duration;
return uint8_t(accel_step);
}
// -----------------------------------------------------------------------------
// Compute the acceleration factor for mouse movement. When a movement key is
// first pressed, the cursor starts out slow then accelerates to full speed.
// The speed during acceleration follows an approximation of a sigmoid function,
// using two parabolas for simplicity.
uint8_t accelFactor(uint8_t accel_step) {
if (accel_step < 128) {
uint16_t y = accel_step * accel_step;
return 1 + (y >> 7);
} else {
uint16_t remaining_steps = 256 - accel_step;
uint16_t y = remaining_steps * remaining_steps;
return 255 - (y >> 7);
}
}
// -----------------------------------------------------------------------------
// Compute the distance the mouse cursor should move in subpixels, return the
// number of pixels the mouse should move (in active directions), and store the
// remaining subpixels for the next move.
uint8_t MouseKeys::cursorDelta() const {
// When the cursor speed is slow, it can be moving less than one pixel per
// update, so we need to calculate movement in "subpixels" and store the
// remaining subpixels to add to the next update's movement.
static uint8_t subpixel_remainder{0};
// First, we calculate where we are on the "time" axis of the acceleration
// curve, based on the time passed since the first cursor movement key was
// pressed.
uint8_t accel_step = accelStep();
// Next, we translate that into a speed scaling factor (from 1-255). If we
// had an FPU, we would do this in floating point, with a scale between 0 and
// 1, so this is how we emulate that using only integer (i.e. fixed-point)
// arithmetic.
uint8_t accel_factor = accelFactor(accel_step);
// We want the cursor to start out with some minimum speed, otherwise the user
// presses a movement key and then waits for a while before the cursor moves
// even one pixel. We need to multiply our speed-scaling factor by the
// difference between the starting speed and the full speed, then add the
// starting speed (multiplied by the full value of the scaling factor) to get
// the current speed.
uint8_t max_speed = settings_.cursor_base_speed;
uint8_t min_speed = settings_.cursor_init_speed;
uint8_t speed_range = max_speed - min_speed;
uint16_t subpixel_speed = (speed_range * accel_factor);
subpixel_speed += (min_speed * 256);
// We want to end up with small numbers of pixels, otherwise the speed will be
// too fast to be useful. But we also want to be able to make fine
// adjustments to the speed, so `settings_.cursor_base_speed` should be
// allowed to have a reasonbly high value, using all eight bits. This means
// that "decimal point" needs to be somewhere in the high byte of this 16-bit
// value. In order to store only eight bits of subpixel remainder, we need to
// do a shift first. This amount is arbitrary, but seems like a reasonable
// compromise.
subpixel_speed >>= 4;
// `max_speed` and `accel_factor` can both be up to 255. So we can't
// just multiply by `cursor_update_interval_ without risk of overflow. The
// update interval should be some low number, anyway (8 or less, I think), and
// should probably be fixed as a constexpr, so we could just leave it out.
subpixel_speed *= cursor_update_interval_;
// There's no risk of overflow here: (255 * 255) + 255 = 65535
subpixel_speed += subpixel_remainder;
// Set minimum speed
subpixel_speed += 64;
// This shift should be more than eight pixels; a single update of 100 pixels
// is a huge jump. See above.
uint8_t pixel_speed = subpixel_speed >> 8;
// Truncate to get only lower 8 bits.
subpixel_remainder = subpixel_speed;
//subpixel_remainder = subpixel_speed - (uint16_t(pixel_speed) << 8);
return pixel_speed;
}
// -----------------------------------------------------------------------------
// Wheel speed should be controlled by changing the update interval, not by
// setting `wheel_speed_`.
void MouseKeys::sendMouseWheelReport() const {
int8_t dh = 0;
int8_t dv = 0;
int8_t vx = 0;
int8_t vy = 0;
uint8_t direction = directions_ >> wheel_offset_; uint8_t direction = directions_ >> wheel_offset_;
if (direction != 0) { if (direction != 0) {
// Horizontal scroll wheel: // Horizontal scroll wheel:
if (direction & KEY_MOUSE_LEFT) if (direction & KEY_MOUSE_LEFT)
dh -= 1; vx -= wheelSpeed;
if (direction & KEY_MOUSE_RIGHT) if (direction & KEY_MOUSE_RIGHT)
dh += 1; vx += wheelSpeed;
// Vertical scroll wheel (note coordinates are opposite movement): // Vertical scroll wheel (note coordinates are opposite movement):
if (direction & KEY_MOUSE_UP) if (direction & KEY_MOUSE_UP)
dv += 1; vy += wheelSpeed;
if (direction & KEY_MOUSE_DOWN) if (direction & KEY_MOUSE_DOWN)
dv -= 1; vy -= wheelSpeed;
// Add scroll wheel changes to HID report.
Runtime.hid().mouse().move(0, 0, vy, vx);
// Send the report. // Send the report.
Runtime.hid().mouse().move(0, 0, dv, dh);
Runtime.hid().mouse().sendReport(); Runtime.hid().mouse().sendReport();
} }
} }

@ -1,5 +1,5 @@
/* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope. /* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope.
* Copyright (C) 2017-2022 Keyboard.io, Inc. * Copyright (C) 2017-2021 Keyboard.io, Inc.
* *
* This program is free software: you can redistribute it and/or modify it under * 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 * the terms of the GNU General Public License as published by the Free Software
@ -22,113 +22,20 @@
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult #include "kaleidoscope/event_handler_result.h" // for EventHandlerResult
#include "kaleidoscope/key_defs.h" // for Key #include "kaleidoscope/key_defs.h" // for Key
#include "kaleidoscope/plugin.h" // for Plugin #include "kaleidoscope/plugin.h" // for Plugin
// =============================================================================
// Deprecated MousKeys code
#include "kaleidoscope_internal/deprecations.h" // for DEPRECATED
#define _DEPRECATED_MESSAGE_MOUSEKEYS_SET_SPEED_LIMIT \
"The `MouseKeys.setSpeedLimit()` function is deprecated. It no longer has\n" \
"any function, and can be safely removed."
#define _DEPRECATED_MESSAGE_MOUSEKEYS_SPEED \
"Direct access to the `MouseKeys.speed` variable has been deprecated.\n" \
"Please refer to the MouseKeys documentation for instructions on how to\n" \
"configure the plugin.\n"
#define _DEPRECATED_MESSAGE_MOUSEKEYS_SPEED_DELAY \
"Direct access to the `MouseKeys.speedDelay` variable has been deprecated.\n" \
"Please refer to the MouseKeys documentation for instructions on how to\n" \
"configure the plugin.\n"
#define _DEPRECATED_MESSAGE_MOUSEKEYS_ACCEL_SPEED \
"Direct access to the `MouseKeys.accelSpeed` variable has been deprecated.\n" \
"Please refer to the MouseKeys documentation for instructions on how to\n" \
"configure the plugin.\n"
#define _DEPRECATED_MESSAGE_MOUSEKEYS_ACCEL_DELAY \
"Direct access to the `MouseKeys.accelDelay` variable has been deprecated.\n" \
"Please refer to the MouseKeys documentation for instructions on how to\n" \
"configure the plugin.\n"
#define _DEPRECATED_MESSAGE_MOUSEKEYS_WHEEL_SPEED \
"Direct access to the `MouseKeys.wheelSpeed` variable has been deprecated.\n" \
"Please refer to the MouseKeys documentation for instructions on how to\n" \
"configure the plugin.\n"
#define _DEPRECATED_MESSAGE_MOUSEKEYS_WHEEL_DELAY \
"Direct access to the `MouseKeys.wheelDelay` variable has been deprecated.\n" \
"Please refer to the MouseKeys documentation for instructions on how to\n" \
"configure the plugin.\n"
namespace kaleidoscope { namespace kaleidoscope {
namespace plugin { namespace plugin {
class MouseKeys : public kaleidoscope::Plugin { class MouseKeys : public kaleidoscope::Plugin {
public: public:
#ifndef NDEPRECATED
DEPRECATED(MOUSEKEYS_SPEED)
static uint8_t speed; static uint8_t speed;
DEPRECATED(MOUSEKEYS_SPEED_DELAY)
static uint16_t speedDelay; static uint16_t speedDelay;
DEPRECATED(MOUSEKEYS_ACCEL_SPEED)
static uint8_t accelSpeed; static uint8_t accelSpeed;
DEPRECATED(MOUSEKEYS_ACCEL_DELAY)
static uint16_t accelDelay; static uint16_t accelDelay;
DEPRECATED(MOUSEKEYS_WHEEL_SPEED)
static uint8_t wheelSpeed; static uint8_t wheelSpeed;
DEPRECATED(MOUSEKEYS_WHEEL_DELAY)
static uint16_t wheelDelay; static uint16_t wheelDelay;
DEPRECATED(MOUSEKEYS_SET_SPEED_LIMIT) static void setWarpGridSize(uint8_t grid_size);
static void setSpeedLimit(uint8_t speed_limit) {} static void setSpeedLimit(uint8_t speed_limit);
#endif
void setWarpGridSize(uint8_t grid_size);
/// Get the current mouse (full) speed setting
///
/// This returns the value for full-speed mouse movement (after the initial
/// acceleration period), not the current speed of the mouse cursor on screen.
/// The value does not have straightforward units, but it is linear.
uint8_t getCursorBaseSpeed() const {
return settings_.cursor_base_speed;
}
/// Set the full-speed mouse movement value
void setCursorBaseSpeed(uint8_t speed) {
settings_.cursor_base_speed = speed;
}
/// Get the initial mouse cursor movement speed setting
uint8_t getCursorInitSpeed() const {
return settings_.cursor_init_speed;
}
/// Set the initial mouse cursor movement speed
void setCursorInitSpeed(uint8_t speed) {
settings_.cursor_init_speed = speed;
}
/// Get the current acceleration window duration
uint16_t getCursorAccelDuration() const {
return settings_.cursor_accel_duration;
}
/// Set the acceleration window duration
void setCursorAccelDuration(uint16_t duration) {
settings_.cursor_accel_duration = duration;
}
/// Get the current mouse wheel update interval
///
/// Returns the interval (in milliseconds) between mouse wheel updates while a
/// mouse wheel key is active (held).
uint8_t getScrollInterval() const {
return settings_.wheel_update_interval;
}
/// Set the current mouse wheel update interval
///
/// Sets the wheel update interval to the specified number of milliseconds.
void setScrollInterval(uint8_t interval) {
settings_.wheel_update_interval = interval;
}
EventHandlerResult onSetup(); EventHandlerResult onSetup();
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();
@ -137,39 +44,20 @@ class MouseKeys : public kaleidoscope::Plugin {
EventHandlerResult onAddToReport(Key key); EventHandlerResult onAddToReport(Key key);
EventHandlerResult afterReportingState(const KeyEvent &event); EventHandlerResult afterReportingState(const KeyEvent &event);
// ---------------------------------------------------------------------------
// Structure for storing all user-configurable settings.
struct Settings {
uint8_t wheel_update_interval = 50;
uint8_t cursor_init_speed = 1;
uint8_t cursor_base_speed = 50;
uint16_t cursor_accel_duration = 1000;
};
// ---------------------------------------------------------------------------
// This lets the MouseKeysConfig plugin access the internal config variables
// directly. Mainly useful for calls to `Runtime.storage.get()`/`.put()`.
friend class MouseKeysConfig;
private: private:
static constexpr uint8_t cursor_update_interval_ = 4; uint16_t move_start_time_ = 0;
uint16_t accel_start_time_ = 0;
Settings settings_; uint16_t wheel_start_time_ = 0;
uint16_t cursor_start_time_ = 0;
uint8_t last_cursor_update_time_ = 0;
uint8_t last_wheel_update_time_ = 0;
// Mouse cursor and wheel movement directions are stored in a single bitfield // Mouse cursor and wheel movement directions are stored in a single bitfield
// to save space. The low four bits are for cursor movement, and the high // to save space. The low four bits are for cursor movement, and the high
// four are for wheel movement. // four are for wheel movement.
static constexpr uint8_t wheel_offset_ = 4; static constexpr uint8_t wheel_offset_ = 4;
static constexpr uint8_t wheel_mask_ = 0b11110000; static constexpr uint8_t wheel_mask_ = 0b11110000;
static constexpr uint8_t cursor_mask_ = 0b00001111; static constexpr uint8_t move_mask_ = 0b00001111;
uint8_t directions_ = 0;
uint8_t directions_ = 0; uint8_t pending_directions_ = 0;
uint8_t pending_directions_ = 0; uint8_t buttons_ = 0;
uint8_t buttons_ = 0;
bool isMouseKey(const Key &key) const; bool isMouseKey(const Key &key) const;
bool isMouseButtonKey(const Key &key) const; bool isMouseButtonKey(const Key &key) const;
@ -179,28 +67,11 @@ class MouseKeys : public kaleidoscope::Plugin {
void sendMouseButtonReport() const; void sendMouseButtonReport() const;
void sendMouseWarpReport(const KeyEvent &event) const; void sendMouseWarpReport(const KeyEvent &event) const;
void sendMouseMoveReport() const; void sendMouseMoveReport();
void sendMouseWheelReport() const; void sendMouseWheelReport();
uint8_t accelStep() const;
uint8_t cursorDelta() const;
};
// =============================================================================
// Plugin for configuration of MouseKeys via Focus and persistent storage of
// settins in EEPROM (i.e. Chrysalis).
class MouseKeysConfig : public Plugin {
public:
EventHandlerResult onSetup();
EventHandlerResult onFocusEvent(const char *command);
private:
// The base address in persistent storage for configuration data:
uint16_t settings_addr_;
}; };
} // namespace plugin } // namespace plugin
} // namespace kaleidoscope } // namespace kaleidoscope
extern kaleidoscope::plugin::MouseKeys MouseKeys; extern kaleidoscope::plugin::MouseKeys MouseKeys;
extern kaleidoscope::plugin::MouseKeysConfig MouseKeysConfig;

@ -1,144 +0,0 @@
/* -*- mode: c++ -*-
* Kaleidoscope-MouseKeys -- Mouse keys for Kaleidoscope.
* Copyright (C) 2022 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/MouseKeys.h" // IWYU pragma: associated
#include <Arduino.h> // for PSTR, strcmp_P, strncmp_P
#include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint16_t, uint32_t, uint8_t
#include "kaleidoscope/Runtime.h" // for Runtime, Runtime_
#include "kaleidoscope/device/device.h" // for VirtualProps::Storage, Base<>::Storage
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult, EventHandlerResult::OK
namespace kaleidoscope {
namespace plugin {
// =============================================================================
// MouseKeys configurator
EventHandlerResult MouseKeysConfig::onSetup() {
settings_addr_ = ::EEPROMSettings.requestSlice(sizeof(MouseKeys::Settings));
uint32_t checker;
Runtime.storage().get(settings_addr_, checker);
// If the EEPROM is empty, storre the default settings.
if (checker == 0xffffffff) {
Runtime.storage().put(settings_addr_, ::MouseKeys.settings_);
Runtime.storage().commit();
}
Runtime.storage().get(settings_addr_, ::MouseKeys.settings_);
return EventHandlerResult::OK;
}
// -----------------------------------------------------------------------------
EventHandlerResult MouseKeysConfig::onFocusEvent(const char *command) {
// If the focus command is a request for help, provide the list of valid
// commands.
if (::Focus.handleHelp(command, PSTR("mousekeys.scroll_interval\n"
"mousekeys.init_speed\n"
"mousekeys.base_speed\n"
"mousekeys.accel_duration")))
return EventHandlerResult::OK;
// The length of the string `mousekeys.`:
constexpr uint8_t base_cmd_len = 10;
// If this is not a MouseKeys command, do nothing.
if (strncmp_P(command, PSTR("mousekeys."), base_cmd_len) != 0)
return EventHandlerResult::OK;
// Otherwise, advance the pointer to the subcommand.
command += base_cmd_len;
enum Command : uint8_t {
SCROLL_INTERVAL,
INIT_SPEED,
BASE_SPEED,
ACCEL_DURATION,
};
Command cmd;
// Parse the (sub)command. If it's not a valid command, abort.
if (strcmp_P(command, PSTR("scroll_interval")) == 0)
cmd = Command::SCROLL_INTERVAL;
else if (strcmp_P(command, PSTR("init_speed")) == 0)
cmd = Command::INIT_SPEED;
else if (strcmp_P(command, PSTR("base_speed")) == 0)
cmd = Command::BASE_SPEED;
else if (strcmp_P(command, PSTR("accel_duration")) == 0)
cmd = Command::ACCEL_DURATION;
else
return EventHandlerResult::ABORT;
if (::Focus.isEOL()) {
// If there is no argument given, we send back the current value of the
// setting that was requested.
uint16_t val;
switch (cmd) {
case Command::SCROLL_INTERVAL:
val = ::MouseKeys.getScrollInterval();
break;
case Command::INIT_SPEED:
val = ::MouseKeys.getCursorInitSpeed();
break;
case Command::BASE_SPEED:
val = ::MouseKeys.getCursorBaseSpeed();
break;
case Command::ACCEL_DURATION:
val = ::MouseKeys.getCursorAccelDuration();
break;
default:
return EventHandlerResult::ABORT;
}
::Focus.send(val);
return EventHandlerResult::EVENT_CONSUMED;
} else {
// If there is an argument, we read it, then pass it to the corresponding
// setter method of MouseKeys.
uint16_t arg;
::Focus.read(arg);
switch (cmd) {
case Command::SCROLL_INTERVAL:
::MouseKeys.setScrollInterval(arg);
break;
case Command::INIT_SPEED:
::MouseKeys.setCursorInitSpeed(arg);
break;
case Command::BASE_SPEED:
::MouseKeys.setCursorBaseSpeed(arg);
break;
case Command::ACCEL_DURATION:
::MouseKeys.setCursorAccelDuration(arg);
break;
}
}
// Update settings stored in EEPROM, and indicate that this Focus event has
// been handled successfully.
Runtime.storage().put(settings_addr_, ::MouseKeys.settings_);
Runtime.storage().commit();
return EventHandlerResult::EVENT_CONSUMED;
}
} // namespace plugin
} // namespace kaleidoscope
kaleidoscope::plugin::MouseKeysConfig MouseKeysConfig;

@ -1,5 +1,5 @@
/* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope. /* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope.
* Copyright (C) 2017-2022 Keyboard.io, Inc. * Copyright (C) 2017-2018 Keyboard.io, Inc.
* *
* This program is free software: you can redistribute it and/or modify it under * 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 * the terms of the GNU General Public License as published by the Free Software
@ -16,22 +16,27 @@
#include "kaleidoscope/plugin/mousekeys/MouseWrapper.h" #include "kaleidoscope/plugin/mousekeys/MouseWrapper.h"
#include <stdint.h> // for uint16_t, uint8_t #include <stdint.h> // for uint16_t, uint8_t, int8_t
#include "kaleidoscope/Runtime.h" // for Runtime, Runtime_ #include "kaleidoscope/Runtime.h" // for Runtime, Runtime_
#include "kaleidoscope/device/device.h" // for Base<>::HID, VirtualProps:... #include "kaleidoscope/device/device.h" // for Base<>::HID, VirtualProps:...
#include "kaleidoscope/driver/hid/keyboardio/AbsoluteMouse.h" // for AbsoluteMouse #include "kaleidoscope/driver/hid/keyboardio/AbsoluteMouse.h" // for AbsoluteMouse
#include "kaleidoscope/driver/hid/keyboardio/Mouse.h" // for Mouse
#include "kaleidoscope/plugin/mousekeys/MouseWarpModes.h" // for MOUSE_WARP_GRID_2X2
namespace kaleidoscope { namespace kaleidoscope {
namespace plugin { namespace plugin {
namespace mousekeys { namespace mousekeys {
// uint8_t MouseWrapper::warp_grid_size = MOUSE_WARP_GRID_2X2; uint8_t MouseWrapper::warp_grid_size = MOUSE_WARP_GRID_2X2;
// uint16_t MouseWrapper::next_width; uint16_t MouseWrapper::next_width;
// uint16_t MouseWrapper::next_height; uint16_t MouseWrapper::next_height;
// uint16_t MouseWrapper::section_top; uint16_t MouseWrapper::section_top;
// uint16_t MouseWrapper::section_left; uint16_t MouseWrapper::section_left;
// bool MouseWrapper::is_warping; bool MouseWrapper::is_warping;
uint8_t MouseWrapper::accel_step;
uint8_t MouseWrapper::speed_limit = 127;
void MouseWrapper::warpJump(uint16_t left, uint16_t top, uint16_t height, uint16_t width) { void MouseWrapper::warpJump(uint16_t left, uint16_t top, uint16_t height, uint16_t width) {
uint16_t x_center = left + width / 2; uint16_t x_center = left + width / 2;
@ -95,9 +100,52 @@ void MouseWrapper::warp(uint8_t warp_cmd) {
warpJump(section_left, section_top, next_height, next_width); warpJump(section_left, section_top, next_height, next_width);
} }
} // namespace mousekeys // To approximate a sine wave, this uses two parabolas. Acceleration begins
// slowly, grows rapidly in the middle, and slows again near the top.
uint8_t MouseWrapper::acceleration(uint8_t cycles) {
if (cycles < 128) {
uint16_t c2 = cycles * cycles;
return 1 + (c2 >> 7);
} else {
uint16_t remaining_cycles = 256 - cycles;
uint16_t c2 = remaining_cycles * remaining_cycles;
return 255 - (c2 >> 7);
}
}
mousekeys::MouseWrapper MouseWrapper; void MouseWrapper::move(int8_t x, int8_t y) {
int16_t moveX = 0;
int16_t moveY = 0;
static int8_t remainderX = 0;
static int8_t remainderY = 0;
int16_t effectiveSpeedLimit = speed_limit;
if (x != 0) {
moveX = remainderX + (x * acceleration(accel_step));
if (moveX > effectiveSpeedLimit)
moveX = effectiveSpeedLimit;
else if (moveX < -effectiveSpeedLimit)
moveX = -effectiveSpeedLimit;
}
if (y != 0) {
moveY = remainderY + (y * acceleration(accel_step));
if (moveY > effectiveSpeedLimit)
moveY = effectiveSpeedLimit;
else if (moveY < -effectiveSpeedLimit)
moveY = -effectiveSpeedLimit;
}
endWarping();
// move by whole pixels, not subpixels
Runtime.hid().mouse().move(moveX / subpixels_per_pixel, moveY / subpixels_per_pixel);
// save leftover subpixel movements for later
remainderX = moveX - moveX / subpixels_per_pixel * subpixels_per_pixel;
remainderY = moveY - moveY / subpixels_per_pixel * subpixels_per_pixel;
}
MouseWrapper wrapper;
} // namespace mousekeys
} // namespace plugin } // namespace plugin
} // namespace kaleidoscope } // namespace kaleidoscope

@ -1,5 +1,5 @@
/* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope. /* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope.
* Copyright (C) 2017-2022 Keyboard.io, Inc. * Copyright (C) 2017-2018 Keyboard.io, Inc.
* *
* This program is free software: you can redistribute it and/or modify it under * 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 * the terms of the GNU General Public License as published by the Free Software
@ -16,56 +16,58 @@
#pragma once #pragma once
#include <stdint.h> // for uint16_t, uint8_t #include <stdint.h> // for uint16_t, uint8_t, int8_t
#include "kaleidoscope/plugin/mousekeys/MouseWarpModes.h" // for MOUSE_WARP_GRID_2X2
// Mouse acceleration
namespace kaleidoscope {
namespace plugin {
// Warping commands // Warping commands
constexpr uint8_t WARP_END = 1 << 0; #define WARP_END 1
constexpr uint8_t WARP_UP = 1 << 1; #define WARP_UP 2
constexpr uint8_t WARP_DOWN = 1 << 2; #define WARP_DOWN 4
constexpr uint8_t WARP_LEFT = 1 << 3; #define WARP_LEFT 8
constexpr uint8_t WARP_RIGHT = 1 << 4; #define WARP_RIGHT 16
// apparently, the mac discards 15% of the value space for mouse movement. // apparently, the mac discards 15% of the value space for mouse movement.
// need to test this on other platforms // need to test this on other platforms
constexpr uint16_t MAX_WARP_WIDTH = 32767; #define MAX_WARP_WIDTH 32767
constexpr uint16_t MAX_WARP_HEIGHT = 32767; #define MAX_WARP_HEIGHT 32767
constexpr uint8_t WARP_ABS_TOP = 0; #define WARP_ABS_TOP 0
constexpr uint8_t WARP_ABS_LEFT = 0; #define WARP_ABS_LEFT 0
// Mouse acceleration
namespace kaleidoscope {
namespace plugin {
namespace mousekeys { namespace mousekeys {
class MouseWrapper { class MouseWrapper {
public: public:
void warp(uint8_t warp_cmd); static void move(int8_t x, int8_t y);
void endWarping(); static void warp(uint8_t warp_cmd);
uint8_t warp_grid_size = MOUSE_WARP_GRID_2X2; static uint8_t accel_step;
static uint8_t speed_limit;
static constexpr uint8_t subpixels_per_pixel = 16;
static uint8_t warp_grid_size;
private: private:
uint16_t next_width; static uint16_t next_width;
uint16_t next_height; static uint16_t next_height;
uint16_t section_top; static uint16_t section_top;
uint16_t section_left; static uint16_t section_left;
bool is_warping = false; static bool is_warping;
void beginWarping(); static uint8_t acceleration(uint8_t cycles);
void resetWarping();
void warpJump(uint16_t left, uint16_t top, uint16_t height, uint16_t width); static void beginWarping();
static void endWarping();
static void resetWarping();
static void warpJump(uint16_t left, uint16_t top, uint16_t height, uint16_t width);
}; };
} // namespace mousekeys extern MouseWrapper wrapper;
extern mousekeys::MouseWrapper MouseWrapper;
} // namespace mousekeys
} // namespace plugin } // namespace plugin
} // namespace kaleidoscope } // namespace kaleidoscope

@ -193,7 +193,7 @@ void SpaceCadet::flushEvent(bool is_tap) {
event.key = map_[pending_map_index_].output; event.key = map_[pending_map_index_].output;
} }
event_queue_.shift(); event_queue_.shift();
Runtime.handleKeyEvent(event); Runtime.handleKeyswitchEvent(event);
} }
} // namespace plugin } // namespace plugin

@ -96,18 +96,6 @@ properties. All times are in seconds.
> Get or set the `.settings.right_hand_max_keys` property. > Get or set the `.settings.right_hand_max_keys` property.
### `typingbreaks.leftKeys`
> Get the current counter of keys pressed on the left half of the keyboard.
### `typingbreaks.rightKeys`
> Get the current counter of keys pressed on the right half of the keyboard.
### `typingbreaks.lockSecsRemaining`
> Get the duration the keyboard remains locked in seconds.
## Dependencies ## Dependencies
* [Kaleidoscope-EEPROM-Settings](Kaleidoscope-EEPROM-Settings.md) * [Kaleidoscope-EEPROM-Settings](Kaleidoscope-EEPROM-Settings.md)

@ -103,7 +103,7 @@ EventHandlerResult TypingBreaks::onKeyEvent(KeyEvent &event) {
// So it seems we did not need to lock up. In this case, lets increase key // So it seems we did not need to lock up. In this case, lets increase key
// counters if need be. // counters if need be.
if (event.addr.col() < Runtime.device().matrix_columns / 2) if (event.addr.col() <= Runtime.device().matrix_columns / 2)
left_hand_keys_++; left_hand_keys_++;
else else
right_hand_keys_++; right_hand_keys_++;
@ -132,6 +132,13 @@ EventHandlerResult TypingBreaks::onSetup() {
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
#define FOCUS_HOOK_TYPINGBREAKS FOCUS_HOOK(TypingBreaks.focusHook, \
"typingbreaks.idleTimeLimit\r\n" \
"typingbreaks.lockTimeOut\r\n" \
"typingbreaks.lockLength\r\n" \
"typingbreaks.leftMaxKeys\r\n" \
"typingbreaks.rightMaxKeys")
EventHandlerResult TypingBreaks::onFocusEvent(const char *input) { EventHandlerResult TypingBreaks::onFocusEvent(const char *input) {
enum { enum {
IDLE_TIME_LIMIT, IDLE_TIME_LIMIT,
@ -139,9 +146,6 @@ EventHandlerResult TypingBreaks::onFocusEvent(const char *input) {
LOCK_LENGTH, LOCK_LENGTH,
LEFT_MAX, LEFT_MAX,
RIGHT_MAX, RIGHT_MAX,
LEFT_COUNT,
RIGHT_COUNT,
LOCK_SECS_REMAINING,
} subCommand; } subCommand;
const char *cmd_idleTimeLimit = PSTR("typingbreaks.idleTimeLimit"); const char *cmd_idleTimeLimit = PSTR("typingbreaks.idleTimeLimit");
@ -149,18 +153,12 @@ EventHandlerResult TypingBreaks::onFocusEvent(const char *input) {
const char *cmd_lockLength = PSTR("typingbreaks.lockLength"); const char *cmd_lockLength = PSTR("typingbreaks.lockLength");
const char *cmd_leftMaxKeys = PSTR("typingbreaks.leftMaxKeys"); const char *cmd_leftMaxKeys = PSTR("typingbreaks.leftMaxKeys");
const char *cmd_rightMaxKeys = PSTR("typingbreaks.rightMaxKeys"); const char *cmd_rightMaxKeys = PSTR("typingbreaks.rightMaxKeys");
const char *cmd_leftKeys = PSTR("typingbreaks.leftKeys");
const char *cmd_rightKeys = PSTR("typingbreaks.rightKeys");
const char *cmd_lockSecsRem = PSTR("typingbreaks.lockSecsRemaining");
if (::Focus.inputMatchesHelp(input)) if (::Focus.inputMatchesHelp(input))
return ::Focus.printHelp(cmd_idleTimeLimit, return ::Focus.printHelp(cmd_idleTimeLimit,
cmd_lockTimeOut, cmd_lockTimeOut,
cmd_lockLength, cmd_lockLength,
cmd_leftMaxKeys, cmd_leftMaxKeys,
cmd_rightMaxKeys, cmd_rightMaxKeys);
cmd_leftKeys,
cmd_rightKeys,
cmd_lockSecsRem);
if (::Focus.inputMatchesCommand(input, cmd_idleTimeLimit)) if (::Focus.inputMatchesCommand(input, cmd_idleTimeLimit))
subCommand = IDLE_TIME_LIMIT; subCommand = IDLE_TIME_LIMIT;
@ -172,12 +170,6 @@ EventHandlerResult TypingBreaks::onFocusEvent(const char *input) {
subCommand = LEFT_MAX; subCommand = LEFT_MAX;
else if (::Focus.inputMatchesCommand(input, cmd_rightMaxKeys)) else if (::Focus.inputMatchesCommand(input, cmd_rightMaxKeys))
subCommand = RIGHT_MAX; subCommand = RIGHT_MAX;
else if (::Focus.inputMatchesCommand(input, cmd_leftKeys))
subCommand = LEFT_COUNT;
else if (::Focus.inputMatchesCommand(input, cmd_rightKeys))
subCommand = RIGHT_COUNT;
else if (::Focus.inputMatchesCommand(input, cmd_lockSecsRem))
subCommand = LOCK_SECS_REMAINING;
else else
return EventHandlerResult::OK; return EventHandlerResult::OK;
@ -217,21 +209,6 @@ EventHandlerResult TypingBreaks::onFocusEvent(const char *input) {
::Focus.read(settings.right_hand_max_keys); ::Focus.read(settings.right_hand_max_keys);
} }
break; break;
case LEFT_COUNT:
::Focus.send(left_hand_keys_);
return EventHandlerResult::EVENT_CONSUMED;
case RIGHT_COUNT:
::Focus.send(right_hand_keys_);
return EventHandlerResult::EVENT_CONSUMED;
case LOCK_SECS_REMAINING:
if (keyboard_locked_) {
uint16_t elapsed = Runtime.millisAtCycleStart() / 1000 - lock_start_time_ / 1000;
uint16_t remaining = settings.lock_length - elapsed;
::Focus.send(remaining);
} else {
::Focus.send(0);
}
return EventHandlerResult::EVENT_CONSUMED;
} }
Runtime.storage().put(settings_base_, settings); Runtime.storage().put(settings_base_, settings);

@ -42,8 +42,6 @@ KALEIDOSCOPE_INIT_PLUGINS(MouseKeys);
void setup() { void setup() {
Kaleidoscope.setup(); Kaleidoscope.setup();
MouseKeys.setCursorAccelDuration(200);
} }
void loop() { void loop() {

@ -21,33 +21,15 @@ RUN 3 ms
PRESS MOVE_UP PRESS MOVE_UP
RUN 1 cycle RUN 1 cycle
RUN 4 ms RUN 15 ms
EXPECT mouse-report y=-1
RUN 8 ms
EXPECT mouse-report y=-1
RUN 8 ms
EXPECT mouse-report y=-1
RUN 4 ms
EXPECT mouse-report y=-1 EXPECT mouse-report y=-1
RUN 4 ms RUN 1 cycle
EXPECT mouse-report y=-1
RUN 4 ms RUN 15 ms
EXPECT mouse-report y=-1
RUN 4 ms
EXPECT mouse-report y=-1 EXPECT mouse-report y=-1
RUN 4 ms RUN 1 cycle
EXPECT mouse-report y=-2
RUN 4 ms
EXPECT mouse-report y=-2
RUN 4 ms
EXPECT mouse-report y=-2
RUN 4 ms
EXPECT mouse-report y=-2
RUN 4 ms
EXPECT mouse-report y=-2
RUN 4 ms
EXPECT mouse-report y=-3
RUN 5 ms
RELEASE MOVE_UP RELEASE MOVE_UP
RUN 1 cycle RUN 1 cycle
EXPECT no mouse-report EXPECT no mouse-report

Loading…
Cancel
Save