Compare commits

..

17 Commits

Author SHA1 Message Date
Gergely Nagy b2d4b8b367
ci
3 years ago
Gergely Nagy 0d92977882
ci fix
3 years ago
Gergely Nagy d4b9e8758c
CI: disable the build workflow for this branch, for now
3 years ago
Gergely Nagy bf0dc00174
CI: wip workflow
3 years ago
Gergely Nagy acd312c94c
Makefile: Add plugins/*/examples/* as SMOKE_SKETCHES candidates
3 years ago
Gergely Nagy 4b9a9c2b14
Model100: Replace the custom NumPad plugin with a default colormap
3 years ago
Gergely Nagy ba764a6f47
Model100: Enable a few more plugins for the Model100
3 years ago
Gergely Nagy a5d043b2b3
Update some of the factory firmware sketches to include more plugins
3 years ago
Gergely Nagy 6aef9b99bb
docs: Add a document describing what we expect from Chrysalis-enabled firmware
3 years ago
Gergely Nagy e857491953
Reformat the factory firmware sketches with clang-format
3 years ago
Gergely Nagy 87c360716a
OG Atreus: Replace the example firmware with a Chrysalis-enabled one
3 years ago
Gergely Nagy 510c8bf800
ErgoDox: Replace the example sketch with a Chrysalis-enabled one
3 years ago
Gergely Nagy 76f5b3ca1d
Splitography: Replace the example firmware
3 years ago
Gergely Nagy 883883e99c
Atreus: Move the Keyboardio Atreus factory firmware to the plugin dir
3 years ago
Gergely Nagy 4993ce4c7d
Model100: Move the factory firmware to the plugin directory
3 years ago
Gergely Nagy c6699ad080
examples: Replace the Model01 example with the factory firmware
3 years ago
Gergely Nagy 93f37b71de
Model100: Correct the name & sentence of the Model100's library.properties
3 years ago

@ -1,6 +1,10 @@
name: Build name: Build
on: [push, pull_request] on:
push:
branches-ignore:
- examples/factory-firmware
pull_request:
env: env:
LC_ALL: C LC_ALL: C

@ -0,0 +1,24 @@
name: Build firmware for Chrysalis
on:
push:
branches:
- examples/factory-firmware
env:
LC_ALL: C
ARDUINO_DIRECTORIES_USER: ${{ github.workspace }}/.arduino/user
ARDUINO_DIRECTORIES_DATA: ${{ github.workspace }}/.arduino/data
jobs:
compile-chrysalis-firmware:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Cache arduino dep downloads
uses: actions/cache@v2
with:
path: ${{ github.workspace}}/.arduino/downloads
key: ${{ runner.os }}-arduino-downloads
- run: make setup
- run: bin/arduino-cli core list
- run: git rev-parse HEAD

1
.gitignore vendored

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

@ -145,7 +145,7 @@ cpplint:
shellcheck: shellcheck:
bin/check-shell-scripts.sh bin/check-shell-scripts.sh
SMOKE_SKETCHES := $(sort $(shell if [ -d ./examples ]; then find ./examples -type f -name \*ino | xargs -n 1 dirname; fi)) SMOKE_SKETCHES := $(sort $(shell if [ -d ./examples ]; then find ./examples -type f -name \*ino | xargs -n 1 dirname; fi; if [ -d ./plugins ]; then find ./plugins -type f -path '*/examples/*/*.ino' | xargs -n 1 dirname; fi))
smoke-sketches: $(SMOKE_SKETCHES) smoke-sketches: $(SMOKE_SKETCHES)
@echo "Smoke-tested all the sketches" @echo "Smoke-tested all the sketches"

@ -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

@ -1,63 +0,0 @@
#!/usr/bin/env bash
# focus-send - Trivial Focus testing tool
# Copyright (C) 2018-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/>.
set -e
OS=$(uname -s)
# igncr absorbs CR from Focus CRLF line endings
# -echo is needed because raw doesn't turn it off on Linux
STTY_ARGS="9600 raw igncr -echo"
case ${OS} in
Linux)
DEVICE="${DEVICE:-/dev/ttyACM0}"
;;
Darwin)
# bash on macOS has a bug that randomly drops serial input
if [ -n "$BASH_VERSION" ] && [ -x /bin/dash ]; then
# Prevent loop in case someone exported it
export -n BASH_VERSION
exec /bin/dash "$0" "$@"
fi
DEVICE="${DEVICE:-/dev/cu.usbmodemCkbio01E}"
;;
*)
echo "Error Unknown OS : ${OS}" >&2
exit 1
;;
esac
# Redirect prior to running stty, because macOS sometimes resets termios
# state upon last close of a terminal device.
exec < "${DEVICE}"
# shellcheck disable=SC2086 # intentional word splitting
stty $STTY_ARGS
read_reply () {
while read -r line; do
if [ "${line}" = "." ]; then
break
fi
echo "${line}"
done
}
# Flush any invalid commands out of input buffer.
# This could happen after a failed upload.
echo ' ' > "${DEVICE}"
read_reply > /dev/null
echo "$@" >"${DEVICE}"
read_reply

@ -0,0 +1,45 @@
#!/usr/bin/env bash
# focus-test - Trivial Focus testing tool
# Copyright (C) 2018 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/>.
set -e
OS=$(uname -s)
case ${OS} in
Linux)
DEVICE="${DEVICE:-/dev/ttyACM0}"
stty -F "${DEVICE}" 9600 raw -echo
;;
Darwin)
DEVICE="${DEVICE:-/dev/cu.usbmodemCkbio01E}"
stty -f "${DEVICE}" 9600 raw -echo
;;
*)
echo "Error Unknown OS : ${OS}" >&2
exit 1
;;
esac
exec 3<"${DEVICE}"
echo "$@" >"${DEVICE}"
while read -r line <&3; do
line="$(echo -n "${line}" | tr -d '\r')"
if [ "${line}" == "." ]; then
break
fi
echo "${line}"
done

@ -273,13 +273,8 @@ class FocusExampleCommand : public Plugin {
return ::Focus.sendName(F("FocusExampleCommand")); return ::Focus.sendName(F("FocusExampleCommand"));
} }
EventHandlerResult onFocusEvent(const char *input) { EventHandlerResult onFocusEvent(const char *command) {
const char *cmd = PSTR("example"); if (strcmp_P(command, PSTR("example")) != 0)
if (::Focus.inputMatchesHelp(input))
return ::Focus.printHelp(cmd);
if (!::Focus.inputMatchesCommand(input, cmd))
return EventHandlerResult::OK; return EventHandlerResult::OK;
::Focus.send(F("This is an example response. Hello world!")); ::Focus.send(F("This is an example response. Hello world!"));
@ -353,8 +348,8 @@ class ExamplePlugin : public Plugin {
public: public:
ExamplePlugin(); ExamplePlugin();
EventHandlerResult onFocusEvent(const char *input) { EventHandlerResult onFocusEvent(const char *command) {
if (!::Focus.inputMatchesCommand(input, PSTR("example.toggle"))) if (strcmp_P(command, PSTR("example.toggle")) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
example_toggle_ = !example_toggle_; example_toggle_ = !example_toggle_;
@ -413,8 +408,8 @@ class ExampleOptionalCommand : public Plugin {
public: public:
ExampleOptionalCommand() {} ExampleOptionalCommand() {}
EventHandlerResult onFocusEvent(const char *input) { EventHandlerResult onFocusEvent(const char *command) {
if (!::Focus.inputMatchesCommand(input, PSTR("optional"))) if (strcmp_P(command, PSTR("optional")) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
::Focus.send(Layer.getLayerState()); ::Focus.send(Layer.getLayerState());

@ -175,7 +175,7 @@ struct KeypadProps : kaleidoscope::device::ATmega32U4KeyboardProps {
}; };
typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner; typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner;
typedef kaleidoscope::driver::bootloader::avr::Caterina Bootloader; typedef kaleidoscope::driver::bootloader::avr::Caterina BootLoader;
static constexpr const char *short_name = "imaginary-keypad"; static constexpr const char *short_name = "imaginary-keypad";
}; };

@ -0,0 +1,107 @@
# Chrysalis-enabled firmware
In this document, we'll go over what is required - at a minimum - to let a
sketch work with Chrysalis, assuming the hardware itself is supported by it.
## Basic requirements
Any sketch that wants to work with Chrysalis has to have at a mininum, the
[FocusSerial][plugin:focus-serial] and [EEPROM-Settings][plugin:eeprom-settings]
libraries included, and the `Focus`, `FocusEEPROMCommand`,
`FocusSettingsCommand` (provided by `FocusSerial`), and `EEPROMSettings`
(provided by `EEPROM-Settings`) plugins enabled, by listing them in
`KALEIDOSCOPE_INIT_PLUGINS()`.
To edit the keymap, the sketch will also need
[EEPROM-Keymap][plugin:eeprom-keymap] included, enabled, and configured. To have
colormap editing support, [Colormap][plugin:colormap] is also required. If
`Colormap` is enabled, its dependencies,
[LEDPaletteTheme][plugin:led-palette-theme] and [LEDControl][plugin:led-control]
must also be enabled.
These are the absolute essentials to have basic functionality in Chrysalis.
There are a lot of other plugins included in most Chrysalis-enabled firmware
that further enhance the configurability. For guidelines about what to include
in sketches that are intended to be shipped with Chrysalis, see the next
section.
## Firmware shipped with Chrysalis
Firmware we ship with Chrysalis should come with reasonable defaults, nothing
surprising, strange, or uncommon should be enabled by default, unless users of
the device can be reasonably expected to know about these features. One such
case is when Kaleidoscope is not the default on a particular device, and the
firmware we ship with Chrysalis mimics the original default firmware. Whatever
features the original firmware had, are safe to include in the
Kaleidoscope-based one too, if Kaleidoscope supports a given feature.
With that said, the recommended list of features in a Chrysalis-enabled firmware are:
### The Basics
At a minimum, we need to support the keyboard's basic features. As such, we'll
need the required plugins first: `Focus`, `FocusEEPROMCommand`, and
`FocusSettingsCommand` (provided by [FocusSerial][plugin:focus-serial]), and
`EEPROMSettings` (provided by [EEPROM-Settings][plugin:eeprom-settings]).
Because we're talking keyboards, we will also need `EEPROMKeymap`, as provided
by the [EEPROM-Keymap][plugin:eeprom-keymap] plugin.
If the device has per-key LEDs, the sketch should also include the `LEDOff` and
`LEDControl` (provided by `LEDControl`), `LEDPaletteTheme`
(provided by [LED-Palette-Theme][plugin:led-palette-theme]), `ColormapEffect`
and `DefaultColormap` plugins, provided by the [Colormap][plugin:colormap]
plugin. The latter is optional, depending on whether there's enough space on the
device to include a default palette and colormap.
The number of layers configured for `ColormapEffect` and `EEPROMKeymap` **must**
be identical, and the number of default layers should leave ample opportunity
for the end-user to customize them. They should not be restricted to the number
of layers the keyboard ships with out of the box, unless storage space
restrictions prevent us from having more. A sensible default is eight layers for
both, as that is the limit the Chrysalis-configurable secondary actions and
one-shot keys support.
If the hardware supports it, including the `HardwareTestMode` plugin is highly
recommended, likewise for [HostPowerManagement][plugin:host-power-management].
When `HostPowerManagement` is included, and the hardware has LEDs, then the
sketch should be set up so that upon suspending, the LEDs are turned off, and
they're turned back on when the host is resumed.
### Additional Features
Space permitting, the following features are recommended to be included in any
firmware we expect to ship with Chrysalis, roughly in order of importance:
- Mouse keys via the [MouseKeys][plugin:mousekeys] plugin.
- Secondary actions via [Qukeys][plugin:qukeys].
- OneShot functionality via [OneShot][plugin:oneshot] and `EscapeOneShot`, and `EscapeOneShotConfig` (provided by [EscapeOneShot][plugin:escape-oneshot]).
- Default LED mode configurability via
[DefaultLEDModeConfig][plugin:default-led-mode-config], if the device supports
LEDs.
- Automatically turning LEDs off after some time, via `IdleLEDs` and
`PersistentIdleLEDs`, provided by th [IdleLEDs][plugin:idle-leds] plugin.
- Chrysalis-editable macros via [DynamicMacros][plugins:dynamic-macros],
configured to leave a fair amount of storage space available for macros, space
permitting. Around 512 bytes is a reasonable minimum, with 4096 bytes being a
very generous amount. At this time, more than 4k storage space reserved for
macros is likely unnecessary.
All of these should be configured for sensible, not surprising behaviour.
Additional plugins on top of these may be enabled if they make sense, but the
principle of least surprise should always be kept in mind.
[plugin:focus-serial]: ../plugins/FocusSerial.md
[plugin:eeprom-settings]: ../plugins/EEPROM-Settings.md
[plugin:eeprom-keymap]: ../plugins/EEPROM-Keymap.md
[plugin:colormap]: ../plugins/Colormap.md
[plugin:led-palette-theme]: ../plugins/LED-Palette-Theme.md
[plugin:host-power-management]: ../plugins/HostPowerManagement.md
[plugin:mousekeys]: ../plugins/MouseKeys.md
[plugin:qukeys]: ../plugins/Qukeys.md
[plugin:oneshot]: ../plugins/OneShot.md
[plugin:escape-oneshot]: ../plugins/Escape-OneShot.md
[plugin:default-led-mode-config]: ../plugins/DefaultLEDModeConfig.md
[plugin:idle-leds]: ../plugins/IdleLEDs.md
[plugin:dynamic-macros]: ../plugins/DynamicMacros.md

@ -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) echo "device.reset" > $(_device_port)
$(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}" \

@ -1,57 +0,0 @@
/* -*- mode: c++ -*-
* ErgoDox -- A very basic Kaleidoscope example for the ErgoDox
* Copyright (C) 2018 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "Kaleidoscope.h"
// clang-format off
KEYMAPS(
[0] = KEYMAP_STACKED
(
// left hand
Key_Equals, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LeftArrow,
Key_Delete, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_NoKey,
Key_Backspace, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_LeftShift, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_LeftControl,
Key_Backtick, Key_Quote, Key_NoKey, Key_LeftArrow, Key_RightArrow,
Key_NoKey, Key_LeftGui,
Key_Home,
Key_Space, Key_Backspace, Key_End,
// right hand
Key_RightArrow, Key_6, Key_7, Key_8, Key_9, Key_0, Key_Minus,
Key_NoKey, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Backslash,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_RightControl, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_RightShift,
Key_UpArrow, Key_DownArrow, XXX, XXX, Key_NoKey,
Key_LeftAlt, Key_Esc,
Key_PageUp,
Key_PageDown, Key_Tab, Key_Enter
),
)
// clang-format on
void setup() {
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

@ -1,59 +0,0 @@
/* -*- mode: c++ -*-
* Splitography -- A very basic Kaleidoscope example for the SOFT/HRUF Splitography keyboard
* Copyright (C) 2018 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "Kaleidoscope.h"
#include "Kaleidoscope-Steno.h"
enum {
_STENO,
};
// clang-format off
KEYMAPS(
/* Steno (GeminiPR)
* ,-----------------------. ,-----------------------.
* | # | # | # | # | # | # | | # | # | # | # | # | # |
* |---+---+---+---+---+---| |---+---+---+---+---+---|
* | | S | T | P | H | * | | * | F | P | L | T | D |
* |---+---+---+---+---+---| |---+---+---+---+---+---|
* | | S | K | W | R | * | | * | R | B | G | S | Z |
* `-------------+---+---+-' `-+---+---+-------------'
* | A | O | | E | U |
* `-------' `-------'
*/
[_STENO] = KEYMAP(
S(N1) ,S(N2) ,S(N3) ,S(N4) ,S(N5) ,S(N6) ,S(N7) ,S(N8) ,S(N9) ,S(NA) ,S(NB) ,S(NC)
,XXX ,S(S1) ,S(TL) ,S(PL) ,S(HL) ,S(ST1) ,S(ST3) ,S(FR) ,S(PR) ,S(LR) ,S(TR) ,S(DR)
,XXX ,S(S2) ,S(KL) ,S(WL) ,S(RL) ,S(ST2) ,S(ST4) ,S(RR) ,S(BR) ,S(GR) ,S(SR) ,S(ZR)
,S(A) ,S(O) ,S(E) ,S(U)
)
);
// clang-format on
KALEIDOSCOPE_INIT_PLUGINS(GeminiPR);
void setup() {
Kaleidoscope.serialPort().begin(9600);
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

@ -44,13 +44,13 @@ class FocusTestCommand : public Plugin {
public: public:
FocusTestCommand() {} FocusTestCommand() {}
EventHandlerResult onFocusEvent(const char *input) { EventHandlerResult onFocusEvent(const char *command) {
const char *cmd = PSTR("test"); const char *cmd = PSTR("test");
if (::Focus.inputMatchesHelp(input)) if (::Focus.handleHelp(command, cmd))
return ::Focus.printHelp(cmd); return EventHandlerResult::OK;
if (::Focus.inputMatchesCommand(input, cmd)) { if (strcmp_P(command, cmd) == 0) {
::Focus.send(F("ok!")); ::Focus.send(F("ok!"));
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
@ -63,9 +63,8 @@ class FocusHelpCommand : public Plugin {
public: public:
FocusHelpCommand() {} FocusHelpCommand() {}
EventHandlerResult onFocusEvent(const char *input) { EventHandlerResult onFocusEvent(const char *command) {
if (::Focus.inputMatchesHelp(input)) ::Focus.handleHelp(command, PSTR("help"));
return ::Focus.printHelp(PSTR("help"));
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }

@ -27,7 +27,7 @@ class TestLEDMode : public kaleidoscope::plugin::LEDMode {
public: public:
TestLEDMode() {} TestLEDMode() {}
kaleidoscope::EventHandlerResult onFocusEvent(const char *input); kaleidoscope::EventHandlerResult onFocusEvent(const char *command);
protected: protected:
void setup() final; void setup() final;
@ -48,8 +48,8 @@ void TestLEDMode::update(void) {
} }
kaleidoscope::EventHandlerResult kaleidoscope::EventHandlerResult
TestLEDMode::onFocusEvent(const char *input) { TestLEDMode::onFocusEvent(const char *command) {
return LEDPaletteTheme.themeFocusEvent(input, PSTR("testLedMode.map"), map_base_, 1); return LEDPaletteTheme.themeFocusEvent(command, PSTR("testLedMode.map"), map_base_, 1);
} }
} // namespace example } // namespace example

@ -275,7 +275,7 @@ class AutoShift : public Plugin {
class AutoShiftConfig : public Plugin { class AutoShiftConfig : public Plugin {
public: public:
EventHandlerResult onSetup(); EventHandlerResult onSetup();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
private: private:
// The base address in persistent storage for configuration data // The base address in persistent storage for configuration data

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/AutoShift.h" // IWYU pragma: associated #include "kaleidoscope/plugin/AutoShift.h" // IWYU pragma: associated
#include <Arduino.h> // for PSTR #include <Arduino.h> // for PSTR, strcmp_P, strncmp_P
#include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings #include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint8_t, uint16_t #include <stdint.h> // for uint8_t, uint16_t
@ -47,25 +47,25 @@ EventHandlerResult AutoShiftConfig::onSetup() {
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
EventHandlerResult AutoShiftConfig::onFocusEvent(const char *input) { EventHandlerResult AutoShiftConfig::onFocusEvent(const char *command) {
enum { enum {
ENABLED, ENABLED,
TIMEOUT, TIMEOUT,
CATEGORIES, CATEGORIES,
} subCommand; } subCommand;
const char *cmd_enabled = PSTR("autoshift.enabled"); if (::Focus.handleHelp(command, PSTR("autoshift.enabled\n"
const char *cmd_timeout = PSTR("autoshift.timeout"); "autoshift.timeout\n"
const char *cmd_categories = PSTR("autoshift.categories"); "autoshift.categories")))
return EventHandlerResult::OK;
if (::Focus.inputMatchesHelp(input))
return ::Focus.printHelp(cmd_enabled, cmd_timeout, cmd_categories);
if (::Focus.inputMatchesCommand(input, cmd_enabled)) if (strncmp_P(command, PSTR("autoshift."), 10) != 0)
return EventHandlerResult::OK;
if (strcmp_P(command + 10, PSTR("enabled")) == 0)
subCommand = ENABLED; subCommand = ENABLED;
else if (::Focus.inputMatchesCommand(input, cmd_timeout)) else if (strcmp_P(command + 10, PSTR("timeout")) == 0)
subCommand = TIMEOUT; subCommand = TIMEOUT;
else if (::Focus.inputMatchesCommand(input, cmd_categories)) else if (strcmp_P(command + 10, PSTR("categories")) == 0)
subCommand = CATEGORIES; subCommand = CATEGORIES;
else else
return EventHandlerResult::OK; return EventHandlerResult::OK;

@ -78,8 +78,8 @@ EventHandlerResult ColormapEffect::onLayerChange() {
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
EventHandlerResult ColormapEffect::onFocusEvent(const char *input) { EventHandlerResult ColormapEffect::onFocusEvent(const char *command) {
return ::LEDPaletteTheme.themeFocusEvent(input, PSTR("colormap.map"), map_base_, max_layers_); return ::LEDPaletteTheme.themeFocusEvent(command, PSTR("colormap.map"), map_base_, max_layers_);
} }
} // namespace plugin } // namespace plugin

@ -36,7 +36,7 @@ class ColormapEffect : public Plugin,
EventHandlerResult onLayerChange(); EventHandlerResult onLayerChange();
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
static bool isUninitialized(); static bool isUninitialized();
static void updateColorIndexAtPosition(uint8_t layer, uint16_t position, uint8_t palette_index); static void updateColorIndexAtPosition(uint8_t layer, uint16_t position, uint8_t palette_index);

@ -72,16 +72,16 @@ void DefaultColormap::install() {
::LEDControl.refreshAll(); ::LEDControl.refreshAll();
} }
EventHandlerResult DefaultColormap::onFocusEvent(const char *input) { EventHandlerResult DefaultColormap::onFocusEvent(const char *command) {
if (!Runtime.has_leds) if (!Runtime.has_leds)
return EventHandlerResult::OK; return EventHandlerResult::OK;
const char *cmd = PSTR("colormap.install"); const char *cmd = PSTR("colormap.install");
if (::Focus.inputMatchesHelp(input)) if (::Focus.handleHelp(command, cmd))
return ::Focus.printHelp(cmd); return EventHandlerResult::OK;
if (!::Focus.inputMatchesCommand(input, cmd)) if (strcmp_P(command, cmd) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
install(); install();

@ -85,9 +85,11 @@ extern uint8_t colormap_layers;
class DefaultColormap : public Plugin { class DefaultColormap : public Plugin {
public: public:
static void setup(); static void setup();
static void install();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
private:
static void install();
}; };
} // namespace plugin } // namespace plugin

@ -31,7 +31,7 @@ KALEIDOSCOPE_INIT_PLUGINS(EEPROMSettings,
void setup() { void setup() {
Kaleidoscope.setup(); Kaleidoscope.setup();
DefaultLEDModeConfig.activateLEDModeIfUnconfigured( DefaultLEDModeConfig.activeLEDModeIfUnconfigured(
&LEDRainbowWaveEffect &LEDRainbowWaveEffect
); );
} }

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/DefaultLEDModeConfig.h" #include "kaleidoscope/plugin/DefaultLEDModeConfig.h"
#include <Arduino.h> // for PSTR, F, __FlashStringHelper #include <Arduino.h> // for PSTR, strcmp_P, F, __FlashStringHelper
#include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings #include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint8_t, uint16_t #include <stdint.h> // for uint8_t, uint16_t
@ -48,13 +48,13 @@ EventHandlerResult DefaultLEDModeConfig::onSetup() {
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
EventHandlerResult DefaultLEDModeConfig::onFocusEvent(const char *input) { EventHandlerResult DefaultLEDModeConfig::onFocusEvent(const char *command) {
const char *cmd = PSTR("led_mode.default"); const char *cmd = PSTR("led_mode.default");
if (::Focus.inputMatchesHelp(input)) if (::Focus.handleHelp(command, cmd))
return ::Focus.printHelp(cmd); return EventHandlerResult::OK;
if (!::Focus.inputMatchesCommand(input, cmd)) if (strcmp_P(command, cmd) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
if (::Focus.isEOL()) { if (::Focus.isEOL()) {

@ -30,7 +30,7 @@ class DefaultLEDModeConfig : public kaleidoscope::Plugin {
public: public:
EventHandlerResult onSetup(); EventHandlerResult onSetup();
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
void activateLEDModeIfUnconfigured(LEDModeInterface *plugin); void activateLEDModeIfUnconfigured(LEDModeInterface *plugin);

@ -16,7 +16,7 @@
#include "kaleidoscope/plugin/DynamicMacros.h" #include "kaleidoscope/plugin/DynamicMacros.h"
#include <Arduino.h> // for delay, PSTR, F, __FlashStri... #include <Arduino.h> // for delay, PSTR, strcmp_P, F, __FlashStri...
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <Kaleidoscope-Ranges.h> // for DYNAMIC_MACRO_FIRST, DYNAMIC_MACRO_LAST #include <Kaleidoscope-Ranges.h> // for DYNAMIC_MACRO_FIRST, DYNAMIC_MACRO_LAST
@ -214,14 +214,14 @@ EventHandlerResult DynamicMacros::onNameQuery() {
return ::Focus.sendName(F("DynamicMacros")); return ::Focus.sendName(F("DynamicMacros"));
} }
EventHandlerResult DynamicMacros::onFocusEvent(const char *input) { EventHandlerResult DynamicMacros::onFocusEvent(const char *command) {
const char *cmd_map = PSTR("macros.map"); if (::Focus.handleHelp(command, PSTR("macros.map\nmacros.trigger")))
const char *cmd_trigger = PSTR("macros.trigger"); return EventHandlerResult::OK;
if (::Focus.inputMatchesHelp(input)) if (strncmp_P(command, PSTR("macros."), 7) != 0)
return ::Focus.printHelp(cmd_map, cmd_trigger); return EventHandlerResult::OK;
if (::Focus.inputMatchesCommand(input, cmd_map)) { if (strcmp_P(command + 7, PSTR("map")) == 0) {
if (::Focus.isEOL()) { if (::Focus.isEOL()) {
for (uint16_t i = 0; i < storage_size_; i++) { for (uint16_t i = 0; i < storage_size_; i++) {
uint8_t b; uint8_t b;
@ -240,16 +240,15 @@ EventHandlerResult DynamicMacros::onFocusEvent(const char *input) {
Runtime.storage().commit(); Runtime.storage().commit();
macro_count_ = updateDynamicMacroCache(); macro_count_ = updateDynamicMacroCache();
} }
return EventHandlerResult::EVENT_CONSUMED; }
} else if (::Focus.inputMatchesCommand(input, cmd_trigger)) {
if (strcmp_P(command + 7, PSTR("trigger")) == 0) {
uint8_t id = 0; uint8_t id = 0;
::Focus.read(id); ::Focus.read(id);
play(id); play(id);
return EventHandlerResult::EVENT_CONSUMED;
} }
return EventHandlerResult::OK; return EventHandlerResult::EVENT_CONSUMED;
} }
// public // public

@ -38,7 +38,7 @@ class DynamicMacros : public kaleidoscope::Plugin {
public: public:
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();
EventHandlerResult onKeyEvent(KeyEvent &event); EventHandlerResult onKeyEvent(KeyEvent &event);
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
EventHandlerResult beforeReportingState(const KeyEvent &event) { EventHandlerResult beforeReportingState(const KeyEvent &event) {
return ::MacroSupport.beforeReportingState(event); return ::MacroSupport.beforeReportingState(event);
} }

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/DynamicTapDance.h" #include "kaleidoscope/plugin/DynamicTapDance.h"
#include <Arduino.h> // for PSTR, F, __FlashStringHelper #include <Arduino.h> // for PSTR, F, __FlashStringHelper, strcmp_P
#include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings #include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint16_t, uint8_t #include <stdint.h> // for uint16_t, uint8_t
@ -93,15 +93,14 @@ EventHandlerResult DynamicTapDance::onNameQuery() {
return ::Focus.sendName(F("DynamicTapDance")); return ::Focus.sendName(F("DynamicTapDance"));
} }
EventHandlerResult DynamicTapDance::onFocusEvent(const char *input) { EventHandlerResult DynamicTapDance::onFocusEvent(const char *command) {
const char *cmd_map = PSTR("tapdance.map"); if (::Focus.handleHelp(command, PSTR("tapdance.map")))
return EventHandlerResult::OK;
if (::Focus.inputMatchesHelp(input))
return ::Focus.printHelp(cmd_map);
if (!::Focus.inputMatchesCommand(input, cmd_map)) if (strncmp_P(command, PSTR("tapdance."), 9) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
if (strcmp_P(command + 9, PSTR("map")) == 0) {
if (::Focus.isEOL()) { if (::Focus.isEOL()) {
for (uint16_t i = 0; i < storage_size_; i += 2) { for (uint16_t i = 0; i < storage_size_; i += 2) {
Key k; Key k;
@ -121,6 +120,7 @@ EventHandlerResult DynamicTapDance::onFocusEvent(const char *input) {
Runtime.storage().commit(); Runtime.storage().commit();
updateDynamicTapDanceCache(); updateDynamicTapDanceCache();
} }
}
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }

@ -31,7 +31,7 @@ namespace plugin {
class DynamicTapDance : public kaleidoscope::Plugin { class DynamicTapDance : public kaleidoscope::Plugin {
public: public:
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
void setup(uint8_t dynamic_offset, uint16_t size); void setup(uint8_t dynamic_offset, uint16_t size);

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/EEPROM-Keymap-Programmer.h" #include "kaleidoscope/plugin/EEPROM-Keymap-Programmer.h"
#include <Arduino.h> // for PSTR #include <Arduino.h> // for PSTR, strcmp_P
#include <Kaleidoscope-EEPROM-Keymap.h> // for EEPROMKeymap #include <Kaleidoscope-EEPROM-Keymap.h> // for EEPROMKeymap
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint16_t, uint8_t #include <stdint.h> // for uint16_t, uint8_t
@ -106,13 +106,13 @@ EventHandlerResult EEPROMKeymapProgrammer::onKeyEvent(KeyEvent &event) {
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
EventHandlerResult EEPROMKeymapProgrammer::onFocusEvent(const char *input) { EventHandlerResult EEPROMKeymapProgrammer::onFocusEvent(const char *command) {
const char *cmd = PSTR("keymap.toggleProgrammer"); const char *cmd = PSTR("keymap.toggleProgrammer");
if (::Focus.inputMatchesHelp(input)) if (::Focus.handleHelp(command, cmd))
return ::Focus.printHelp(cmd); return EventHandlerResult::OK;
if (!::Focus.inputMatchesCommand(input, cmd)) if (strcmp_P(command, cmd) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
if (state_ == INACTIVE) if (state_ == INACTIVE)

@ -41,7 +41,7 @@ class EEPROMKeymapProgrammer : public kaleidoscope::Plugin {
void cancel(); void cancel();
EventHandlerResult onKeyEvent(KeyEvent &event); EventHandlerResult onKeyEvent(KeyEvent &event);
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
private: private:
typedef enum { typedef enum {

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/EEPROM-Keymap.h" #include "kaleidoscope/plugin/EEPROM-Keymap.h"
#include <Arduino.h> // for PSTR, F, __FlashStringHelper #include <Arduino.h> // for PSTR, strcmp_P, F, __FlashStringHelper
#include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings #include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint8_t, uint16_t #include <stdint.h> // for uint8_t, uint16_t
@ -101,15 +101,14 @@ void EEPROMKeymap::dumpKeymap(uint8_t layers, Key (*getkey)(uint8_t, KeyAddr)) {
} }
} }
EventHandlerResult EEPROMKeymap::onFocusEvent(const char *input) { EventHandlerResult EEPROMKeymap::onFocusEvent(const char *command) {
const char *cmd_custom = PSTR("keymap.custom"); if (::Focus.handleHelp(command, PSTR("keymap.custom\nkeymap.default\nkeymap.onlyCustom")))
const char *cmd_default = PSTR("keymap.default"); return EventHandlerResult::OK;
const char *cmd_onlyCustom = PSTR("keymap.onlyCustom");
if (::Focus.inputMatchesHelp(input)) if (strncmp_P(command, PSTR("keymap."), 7) != 0)
return ::Focus.printHelp(cmd_custom, cmd_default, cmd_onlyCustom); return EventHandlerResult::OK;
if (::Focus.inputMatchesCommand(input, cmd_onlyCustom)) { if (strcmp_P(command + 7, PSTR("onlyCustom")) == 0) {
if (::Focus.isEOL()) { if (::Focus.isEOL()) {
::Focus.send((uint8_t)::EEPROMSettings.ignoreHardcodedLayers()); ::Focus.send((uint8_t)::EEPROMSettings.ignoreHardcodedLayers());
} else { } else {
@ -129,7 +128,7 @@ EventHandlerResult EEPROMKeymap::onFocusEvent(const char *input) {
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
if (::Focus.inputMatchesCommand(input, cmd_default)) { if (strcmp_P(command + 7, PSTR("default")) == 0) {
// By using a cast to the appropriate function type, // By using a cast to the appropriate function type,
// tell the compiler which overload of getKeyFromPROGMEM // tell the compiler which overload of getKeyFromPROGMEM
// we actully want. // we actully want.
@ -139,7 +138,7 @@ EventHandlerResult EEPROMKeymap::onFocusEvent(const char *input) {
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
if (!::Focus.inputMatchesCommand(input, cmd_custom)) if (strcmp_P(command + 7, PSTR("custom")) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
if (::Focus.isEOL()) { if (::Focus.isEOL()) {

@ -35,7 +35,7 @@ class EEPROMKeymap : public kaleidoscope::Plugin {
EventHandlerResult onSetup(); EventHandlerResult onSetup();
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
static void setup(uint8_t max); static void setup(uint8_t max);

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/EEPROM-Settings.h" #include "kaleidoscope/plugin/EEPROM-Settings.h"
#include <Arduino.h> // for PSTR, F, __FlashStringHelper #include <Arduino.h> // for PSTR, strcmp_P, F, __FlashStringHelper
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint16_t, uint8_t #include <stdint.h> // for uint16_t, uint8_t
@ -156,7 +156,7 @@ void EEPROMSettings::update() {
} }
/** Focus **/ /** Focus **/
EventHandlerResult FocusSettingsCommand::onFocusEvent(const char *input) { EventHandlerResult FocusSettingsCommand::onFocusEvent(const char *command) {
enum { enum {
DEFAULT_LAYER, DEFAULT_LAYER,
IS_VALID, IS_VALID,
@ -164,21 +164,19 @@ EventHandlerResult FocusSettingsCommand::onFocusEvent(const char *input) {
GET_CRC, GET_CRC,
} sub_command; } sub_command;
const char *cmd_defaultLayer = PSTR("settings.defaultLayer"); if (::Focus.handleHelp(command, PSTR("settings.defaultLayer\nsettings.valid?\nsettings.version\nsettings.crc")))
const char *cmd_isValid = PSTR("settings.valid?"); return EventHandlerResult::OK;
const char *cmd_version = PSTR("settings.version");
const char *cmd_crc = PSTR("settings.crc");
if (::Focus.inputMatchesHelp(input)) if (strncmp_P(command, PSTR("settings."), 9) != 0)
return ::Focus.printHelp(cmd_defaultLayer, cmd_isValid, cmd_version, cmd_crc); return EventHandlerResult::OK;
if (::Focus.inputMatchesCommand(input, cmd_defaultLayer)) if (strcmp_P(command + 9, PSTR("defaultLayer")) == 0)
sub_command = DEFAULT_LAYER; sub_command = DEFAULT_LAYER;
else if (::Focus.inputMatchesCommand(input, cmd_isValid)) else if (strcmp_P(command + 9, PSTR("valid?")) == 0)
sub_command = IS_VALID; sub_command = IS_VALID;
else if (::Focus.inputMatchesCommand(input, cmd_version)) else if (strcmp_P(command + 9, PSTR("version")) == 0)
sub_command = GET_VERSION; sub_command = GET_VERSION;
else if (::Focus.inputMatchesCommand(input, cmd_crc)) else if (strcmp_P(command + 9, PSTR("crc")) == 0)
sub_command = GET_CRC; sub_command = GET_CRC;
else else
return EventHandlerResult::OK; return EventHandlerResult::OK;
@ -208,25 +206,21 @@ EventHandlerResult FocusSettingsCommand::onFocusEvent(const char *input) {
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
EventHandlerResult FocusEEPROMCommand::onFocusEvent(const char *input) { EventHandlerResult FocusEEPROMCommand::onFocusEvent(const char *command) {
enum { enum {
CONTENTS, CONTENTS,
FREE, FREE,
ERASE, ERASE,
} sub_command; } sub_command;
const char *cmd_contents = PSTR("eeprom.contents"); if (::Focus.handleHelp(command, PSTR("eeprom.contents\neeprom.free\neeprom.erase")))
const char *cmd_free = PSTR("eeprom.free"); return EventHandlerResult::OK;
const char *cmd_erase = PSTR("eeprom.erase");
if (::Focus.inputMatchesHelp(input))
return ::Focus.printHelp(cmd_contents, cmd_free, cmd_erase);
if (::Focus.inputMatchesCommand(input, cmd_contents)) if (strcmp_P(command, PSTR("eeprom.contents")) == 0)
sub_command = CONTENTS; sub_command = CONTENTS;
else if (::Focus.inputMatchesCommand(input, cmd_free)) else if (strcmp_P(command, PSTR("eeprom.free")) == 0)
sub_command = FREE; sub_command = FREE;
else if (::Focus.inputMatchesCommand(input, cmd_erase)) else if (strcmp_P(command, PSTR("eeprom.erase")) == 0)
sub_command = ERASE; sub_command = ERASE;
else else
return EventHandlerResult::OK; return EventHandlerResult::OK;

@ -86,12 +86,12 @@ class EEPROMSettings : public kaleidoscope::Plugin {
class FocusSettingsCommand : public kaleidoscope::Plugin { class FocusSettingsCommand : public kaleidoscope::Plugin {
public: public:
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
}; };
class FocusEEPROMCommand : public kaleidoscope::Plugin { class FocusEEPROMCommand : public kaleidoscope::Plugin {
public: public:
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
}; };
} // namespace plugin } // namespace plugin

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/Escape-OneShot.h" // IWYU pragma: associated #include "kaleidoscope/plugin/Escape-OneShot.h" // IWYU pragma: associated
#include <Arduino.h> // for PSTR, F, __FlashStringHelper #include <Arduino.h> // for PSTR, F, __FlashStringHelper, strcmp_P
#include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings #include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
@ -48,12 +48,11 @@ EventHandlerResult EscapeOneShotConfig::onNameQuery() {
return ::Focus.sendName(F("EscapeOneShot")); return ::Focus.sendName(F("EscapeOneShot"));
} }
EventHandlerResult EscapeOneShotConfig::onFocusEvent(const char *input) { EventHandlerResult EscapeOneShotConfig::onFocusEvent(const char *command) {
const char *cmd_cancel_key = PSTR("escape_oneshot.cancel_key"); if (::Focus.handleHelp(command, PSTR("escape_oneshot.cancel_key")))
if (::Focus.inputMatchesHelp(input)) return EventHandlerResult::OK;
return ::Focus.printHelp(cmd_cancel_key);
if (!::Focus.inputMatchesCommand(input, cmd_cancel_key)) if (strcmp_P(command, PSTR("escape_oneshot.cancel_key")) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
if (::Focus.isEOL()) { if (::Focus.isEOL()) {

@ -56,7 +56,7 @@ class EscapeOneShot : public kaleidoscope::Plugin {
class EscapeOneShotConfig : public Plugin { class EscapeOneShotConfig : public Plugin {
public: public:
EventHandlerResult onSetup(); EventHandlerResult onSetup();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();
private: private:

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/FingerPainter.h" #include "kaleidoscope/plugin/FingerPainter.h"
#include <Arduino.h> // for PSTR, F, __FlashStringHelper #include <Arduino.h> // for PSTR, strcmp_P, F, __FlashStringHelper
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <Kaleidoscope-LED-Palette-Theme.h> // for LEDPaletteTheme #include <Kaleidoscope-LED-Palette-Theme.h> // for LEDPaletteTheme
#include <stdint.h> // for uint16_t, uint8_t #include <stdint.h> // for uint16_t, uint8_t
@ -94,21 +94,21 @@ EventHandlerResult FingerPainter::onKeyEvent(KeyEvent &event) {
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
EventHandlerResult FingerPainter::onFocusEvent(const char *input) { EventHandlerResult FingerPainter::onFocusEvent(const char *command) {
enum { enum {
TOGGLE, TOGGLE,
CLEAR, CLEAR,
} sub_command; } sub_command;
const char *cmd_toggle = PSTR("fingerpainter.toggle"); if (::Focus.handleHelp(command, PSTR("fingerpainter.toggle\nfingerpainter.clear")))
const char *cmd_clear = PSTR("fingerpainter.clear"); return EventHandlerResult::OK;
if (::Focus.inputMatchesHelp(input)) if (strncmp_P(command, PSTR("fingerpainter."), 14) != 0)
return ::Focus.printHelp(cmd_toggle, cmd_clear); return EventHandlerResult::OK;
if (::Focus.inputMatchesCommand(input, cmd_toggle)) if (strcmp_P(command + 14, PSTR("toggle")) == 0)
sub_command = TOGGLE; sub_command = TOGGLE;
else if (::Focus.inputMatchesCommand(input, cmd_clear)) else if (strcmp_P(command + 14, PSTR("clear")) == 0)
sub_command = CLEAR; sub_command = CLEAR;
else else
return EventHandlerResult::OK; return EventHandlerResult::OK;

@ -36,7 +36,7 @@ class FingerPainter : public LEDMode {
void toggle(); void toggle();
EventHandlerResult onKeyEvent(KeyEvent &event); EventHandlerResult onKeyEvent(KeyEvent &event);
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
EventHandlerResult onSetup(); EventHandlerResult onSetup();
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();

@ -50,13 +50,13 @@ EventHandlerResult FirmwareDump::onSetup() {
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
EventHandlerResult FirmwareDump::onFocusEvent(const char *input) { EventHandlerResult FirmwareDump::onFocusEvent(const char *command) {
const char *cmd = PSTR("firmware.dump"); const char *cmd = PSTR("firmware.dump");
if (::Focus.inputMatchesHelp(input)) if (::Focus.handleHelp(command, cmd))
return ::Focus.printHelp(cmd); return EventHandlerResult::OK;
if (!::Focus.inputMatchesCommand(input, cmd)) if (strcmp_P(command, cmd) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
uint16_t flash_size = (FLASHEND + 1L); uint16_t flash_size = (FLASHEND + 1L);

@ -34,7 +34,7 @@ namespace plugin {
class FirmwareDump : public kaleidoscope::Plugin { class FirmwareDump : public kaleidoscope::Plugin {
public: public:
EventHandlerResult onSetup(); EventHandlerResult onSetup();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
private: private:
uint16_t bootloader_size_; uint16_t bootloader_size_;

@ -1,36 +0,0 @@
# FirmwareVersion
Implements a new focus command - version - that simply prints the version set up
at compile time.
## Using the plugin
To use the plugin, first define the version to be printed, then include the
header, and activate the plugin.
```c++
#define KALEIDOSCOPE_FIRMWARE_VERSION "0.1.2"
#include <Kaleidoscope.h>
#include <Kaleidoscope-FirmwareVersion.h>
#include <Kaleidoscope-FocusSerial.h>
KALEIDOSCOPE_INIT_PLUGINS(Focus,
FirmwareVersion);
void setup () {
Kaleidoscope.setup ();
}
```
## Focus commands
The plugin provides a single Focus command: `version`.
### `version`
> Prints the version configured at build time.
## Dependencies
* [Kaleidoscope-FocusSerial](Kaleidoscope-FocusSerial.md)

@ -1,7 +0,0 @@
name=Kaleidoscope-FirmwareVersion
version=0.0.0
sentence=Provides a Focus command to print a preconfigured version
maintainer=Kaleidoscope's Developers <jesse@keyboard.io>
url=https://github.com/keyboardio/Kaleidoscope
author=Keyboardio
paragraph=

@ -1,20 +0,0 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FirmwareVersion -- Provides a Focus command to print a version
* 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/>.
*/
#pragma once
#include "kaleidoscope/plugin/FirmwareVersion.h" // IWYU pragma: export

@ -1,56 +0,0 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FirmwareVersion -- Provides a Focus command to print a version
* 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/>.
*/
#pragma once
#ifndef KALEIDOSCOPE_FIRMWARE_VERSION
#define KALEIDOSCOPE_FIRMWARE_VERSION "0.0.0"
#endif
#include <Arduino.h> // for PSTR, F, __FlashStringHelper
#include "Kaleidoscope-FocusSerial.h" // for Focus, FocusSerial
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult
#include "kaleidoscope/plugin.h" // for Plugin
namespace kaleidoscope {
namespace plugin {
class FirmwareVersion : public Plugin {
public:
EventHandlerResult onFocusEvent(const char *input) {
const char *cmd_version = PSTR("version");
if (::Focus.inputMatchesHelp(input))
return ::Focus.printHelp(cmd_version);
if (!::Focus.inputMatchesCommand(input, cmd_version))
return EventHandlerResult::OK;
#ifdef KALEIDOSCOPE_FIRMWARE_VERSION
::Focus.send(F(KALEIDOSCOPE_FIRMWARE_VERSION));
#else
::Focus.send(F("0.0.0"));
#endif
return EventHandlerResult::OK;
}
};
} // namespace plugin
} // namespace kaleidoscope
kaleidoscope::plugin::FirmwareVersion FirmwareVersion;

@ -24,13 +24,8 @@ class FocusTestCommand : public Plugin {
return ::Focus.sendName(F("FocusTestCommand")); return ::Focus.sendName(F("FocusTestCommand"));
} }
EventHandlerResult onFocusEvent(const char *input) { EventHandlerResult onFocusEvent(const char *command) {
const char *cmd = PSTR("test"); if (strcmp_P(command, PSTR("test")) != 0)
if (::Focus.inputMatchesHelp(input))
return ::Focus.printHelp(cmd);
if (!::Focus.inputMatchesCommand(input, cmd))
return EventHandlerResult::OK; return EventHandlerResult::OK;
::Focus.send(F("Congratulations, the test command works!")); ::Focus.send(F("Congratulations, the test command works!"));
@ -52,18 +47,6 @@ void setup () {
The plugin provides the `Focus` object, with a couple of helper methods aimed at developers. Terminating the response with a dot on its own line is handled implicitly by `FocusSerial`, one does not need to do that explicitly. The plugin provides the `Focus` object, with a couple of helper methods aimed at developers. Terminating the response with a dot on its own line is handled implicitly by `FocusSerial`, one does not need to do that explicitly.
### `.inputMatchesHelp(input)`
Returns `true` if the given `input` matches the `help` command. To be used at the top of `onFocusEvent()`, followed by `.printHelp(...)`.
### `.printHelp(...)`
Given a series of strings (stored in `PROGMEM`, via `PSTR()`), prints them one per line. Assumes it is run as part of handling the `help` command. Returns `EventHandlerResult::OK`.
### `.inputMatchesCommand(input, command)`
Returns `true` if the `input` matches the expected `command`, false otherwise. A convenience function over `strcmp_P()`.
### `.send(...)` ### `.send(...)`
### `.sendRaw(...)` ### `.sendRaw(...)`

@ -33,7 +33,6 @@ namespace kaleidoscope {
namespace plugin { namespace plugin {
EventHandlerResult FocusSerial::afterEachCycle() { EventHandlerResult FocusSerial::afterEachCycle() {
int c;
// GD32 doesn't currently autoflush the very last packet. So manually flush here // GD32 doesn't currently autoflush the very last packet. So manually flush here
Runtime.serialPort().flush(); Runtime.serialPort().flush();
// If the serial buffer is empty, we don't have any work to do // If the serial buffer is empty, we don't have any work to do
@ -42,28 +41,33 @@ EventHandlerResult FocusSerial::afterEachCycle() {
} }
do { do {
// If there's a newline pending, don't read it command_[buf_cursor_++] = Runtime.serialPort().read();
if (Runtime.serialPort().peek() == NEWLINE) { } while (command_[buf_cursor_ - 1] != SEPARATOR && buf_cursor_ < sizeof(command_) && Runtime.serialPort().available() && (Runtime.serialPort().peek() != NEWLINE));
break;
}
c = Runtime.serialPort().read(); // If there was no command, there's nothing to do
// Don't store the separator; just stash it if (command_[0] == '\0') {
if (c == SEPARATOR) { buf_cursor_ = 0;
break; memset(command_, 0, sizeof(command_));
return EventHandlerResult::OK;
} }
input_[buf_cursor_++] = c;
} while (buf_cursor_ < (sizeof(input_) - 1) && Runtime.serialPort().available());
if ((c != SEPARATOR) && (Runtime.serialPort().peek() != NEWLINE) && buf_cursor_ < (sizeof(input_) - 1)) { if ((command_[buf_cursor_ - 1] != SEPARATOR) && (Runtime.serialPort().peek() != NEWLINE) && buf_cursor_ < sizeof(command_)) {
// We don't have enough command to work with yet. // We don't have enough command to work with yet.
// Let's leave the buffer around for another cycle // Let's leave the buffer around for another cycle
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
// If this was a command with a space-delimited payload,
// strip the space delimiter off
if ((command_[buf_cursor_ - 1] == SEPARATOR)) {
command_[buf_cursor_ - 1] = '\0';
}
// Then process the command // Then process the command
Runtime.onFocusEvent(input_); Runtime.onFocusEvent(command_);
while (Runtime.serialPort().available()) { while (Runtime.serialPort().available()) {
c = Runtime.serialPort().read(); char c = Runtime.serialPort().read();
if (c == NEWLINE) { if (c == NEWLINE) {
// newline serves as an end-of-command marker // newline serves as an end-of-command marker
// don't drain the buffer past there // don't drain the buffer past there
@ -73,23 +77,28 @@ EventHandlerResult FocusSerial::afterEachCycle() {
// End of command processing is signalled with a CRLF followed by a single period // End of command processing is signalled with a CRLF followed by a single period
Runtime.serialPort().println(F("\r\n.")); Runtime.serialPort().println(F("\r\n."));
buf_cursor_ = 0; buf_cursor_ = 0;
memset(input_, 0, sizeof(input_)); memset(command_, 0, sizeof(command_));
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
EventHandlerResult FocusSerial::onFocusEvent(const char *input) { bool FocusSerial::handleHelp(const char *command,
const char *cmd_help = PSTR("help"); const char *help_message) {
const char *cmd_reset = PSTR("device.reset"); if (strcmp_P(command, PSTR("help")) != 0)
const char *cmd_plugins = PSTR("plugins"); return false;
Runtime.serialPort().println((const __FlashStringHelper *)help_message);
return true;
}
if (inputMatchesHelp(input)) EventHandlerResult FocusSerial::onFocusEvent(const char *command) {
return printHelp(cmd_help, cmd_reset, cmd_plugins); if (handleHelp(command, PSTR("help\ndevice.reset\nplugins")))
return EventHandlerResult::OK;
if (inputMatchesCommand(input, cmd_reset)) { if (strcmp_P(command, PSTR("device.reset")) == 0) {
Runtime.device().rebootBootloader(); Runtime.device().rebootBootloader();
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
if (inputMatchesCommand(input, cmd_plugins)) { if (strcmp_P(command, PSTR("plugins")) == 0) {
kaleidoscope::Hooks::onNameQuery(); kaleidoscope::Hooks::onNameQuery();
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
@ -97,27 +106,10 @@ EventHandlerResult FocusSerial::onFocusEvent(const char *input) {
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
#ifndef NDEPRECATED
bool FocusSerial::handleHelp(const char *input, const char *help_message) {
if (!inputMatchesHelp(input)) return false;
printHelp(help_message);
return true;
}
#endif
void FocusSerial::printBool(bool b) { void FocusSerial::printBool(bool b) {
Runtime.serialPort().print((b) ? F("true") : F("false")); Runtime.serialPort().print((b) ? F("true") : F("false"));
} }
bool FocusSerial::inputMatchesHelp(const char *input) {
return inputMatchesCommand(input, PSTR("help"));
}
bool FocusSerial::inputMatchesCommand(const char *input, const char *expected) {
return strcmp_P(input, expected) == 0;
}
} // namespace plugin } // namespace plugin
} // namespace kaleidoscope } // namespace kaleidoscope

@ -26,15 +26,6 @@
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult, EventHandlerResult::OK #include "kaleidoscope/event_handler_result.h" // for EventHandlerResult, EventHandlerResult::OK
#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
// -----------------------------------------------------------------------------
// Deprecation warning messages
#include "kaleidoscope_internal/deprecations.h" // for DEPRECATED
#define _DEPRECATED_MESSAGE_FOCUS_HANDLEHELP \
"The `Focus.handleHelp()` method is deprecated. Please use\n" \
"`Focus.inputMatchesHelp()` and `Focus.printHelp()` instead.\n" \
"This method will be removed after 2022-12-26."
// -----------------------------------------------------------------------------
// IWYU pragma: no_include "WString.h" // IWYU pragma: no_include "WString.h"
@ -46,28 +37,13 @@ class FocusSerial : public kaleidoscope::Plugin {
static constexpr char SEPARATOR = ' '; static constexpr char SEPARATOR = ' ';
static constexpr char NEWLINE = '\n'; static constexpr char NEWLINE = '\n';
#ifndef NDEPRECATED bool handleHelp(const char *command,
DEPRECATED(FOCUS_HANDLEHELP) const char *help_message);
bool handleHelp(const char *input, const char *help_message);
#endif
bool inputMatchesHelp(const char *input);
bool inputMatchesCommand(const char *input, const char *expected);
EventHandlerResult printHelp() {
return EventHandlerResult::OK;
}
template<typename... Vars>
EventHandlerResult printHelp(const char *h1, Vars... vars) {
Runtime.serialPort().println((const __FlashStringHelper *)h1);
delayAfterPrint();
return printHelp(vars...);
}
EventHandlerResult sendName(const __FlashStringHelper *name) { EventHandlerResult sendName(const __FlashStringHelper *name) {
Runtime.serialPort().print(name); Runtime.serialPort().print(name);
delayAfterPrint(); delayAfterPrint();
Runtime.serialPort().println(); Runtime.serialPort().print(NEWLINE);
delayAfterPrint(); delayAfterPrint();
return EventHandlerResult::OK; return EventHandlerResult::OK;
} }
@ -118,9 +94,6 @@ class FocusSerial : public kaleidoscope::Plugin {
color.g = Runtime.serialPort().parseInt(); color.g = Runtime.serialPort().parseInt();
color.b = Runtime.serialPort().parseInt(); color.b = Runtime.serialPort().parseInt();
} }
void read(char &c) {
Runtime.serialPort().readBytes(&c, 1);
}
void read(uint8_t &u8) { void read(uint8_t &u8) {
u8 = Runtime.serialPort().parseInt(); u8 = Runtime.serialPort().parseInt();
} }
@ -137,10 +110,10 @@ class FocusSerial : public kaleidoscope::Plugin {
/* Hooks */ /* Hooks */
EventHandlerResult afterEachCycle(); EventHandlerResult afterEachCycle();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
private: private:
char input_[32]; char command_[32];
uint8_t buf_cursor_ = 0; uint8_t buf_cursor_ = 0;
void printBool(bool b); void printBool(bool b);

@ -170,7 +170,7 @@ struct RaiseProps : kaleidoscope::device::BaseProps {
typedef RaiseKeyScanner KeyScanner; typedef RaiseKeyScanner KeyScanner;
typedef RaiseStorageProps StorageProps; typedef RaiseStorageProps StorageProps;
typedef kaleidoscope::driver::storage::Flash<StorageProps> Storage; typedef kaleidoscope::driver::storage::Flash<StorageProps> Storage;
typedef kaleidoscope::driver::bootloader::samd::Bossac Bootloader; typedef kaleidoscope::driver::bootloader::samd::Bossac BootLoader;
typedef RaiseSideFlasherProps SideFlasherProps; typedef RaiseSideFlasherProps SideFlasherProps;
typedef kaleidoscope::util::flasher::KeyboardioI2CBootloader<SideFlasherProps> SideFlasher; typedef kaleidoscope::util::flasher::KeyboardioI2CBootloader<SideFlasherProps> SideFlasher;

@ -33,37 +33,24 @@ namespace raise {
#define RAISE_FIRMWARE_VERSION "<unknown>" #define RAISE_FIRMWARE_VERSION "<unknown>"
#endif #endif
EventHandlerResult Focus::onFocusEvent(const char *input) { EventHandlerResult Focus::onFocusEvent(const char *command) {
const char *cmd_version = PSTR("hardware.version"); if (::Focus.handleHelp(command, PSTR("hardware.version\nhardware.side_power\nhardware.side_ver\nhardware.sled_ver\nhardware.sled_current\nhardware.layout\nhardware.joint\nhardware.keyscan\nhardware.crc_errors\nhardware.firmware")))
const char *cmd_side_power = PSTR("hardware.side_power"); return EventHandlerResult::OK;
const char *cmd_side_ver = PSTR("hardware.side_ver");
const char *cmd_sled_ver = PSTR("hardware.sled_ver"); if (strncmp_P(command, PSTR("hardware."), 9) != 0)
const char *cmd_sled_current = PSTR("hardware.sled_current"); return EventHandlerResult::OK;
const char *cmd_layout = PSTR("hardware.layout");
const char *cmd_joint = PSTR("hardware.joint"); if (strcmp_P(command + 9, PSTR("version")) == 0) {
const char *cmd_keyscan = PSTR("hardware.keyscan");
const char *cmd_crc_errors = PSTR("hardware.crc_errors");
const char *cmd_firmware = PSTR("hardware.firmware");
if (::Focus.inputMatchesHelp(input))
return ::Focus.printHelp(cmd_version,
cmd_side_power,
cmd_side_ver,
cmd_sled_ver,
cmd_sled_current,
cmd_layout,
cmd_joint,
cmd_keyscan,
cmd_crc_errors,
cmd_firmware);
if (::Focus.inputMatchesCommand(input, cmd_version)) {
::Focus.send("Dygma Raise"); ::Focus.send("Dygma Raise");
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} else if (::Focus.inputMatchesCommand(input, cmd_firmware)) { }
if (strcmp_P(command + 9, PSTR("firmware")) == 0) {
::Focus.send(RAISE_FIRMWARE_VERSION); ::Focus.send(RAISE_FIRMWARE_VERSION);
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} else if (::Focus.inputMatchesCommand(input, cmd_side_power)) { }
if (strcmp_P(command + 9, PSTR("side_power")) == 0) {
if (::Focus.isEOL()) { if (::Focus.isEOL()) {
::Focus.send(Runtime.device().side.getPower()); ::Focus.send(Runtime.device().side.getPower());
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
@ -73,29 +60,37 @@ EventHandlerResult Focus::onFocusEvent(const char *input) {
Runtime.device().side.setPower(power); Runtime.device().side.setPower(power);
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
} else if (::Focus.inputMatchesCommand(input, cmd_side_ver)) { }
if (strcmp_P(command + 9, PSTR("side_ver")) == 0) {
::Focus.send("left:"); ::Focus.send("left:");
::Focus.send(Runtime.device().side.leftVersion()); ::Focus.send(Runtime.device().side.leftVersion());
::Focus.send("\r\nright:"); ::Focus.send("\nright:");
::Focus.send(Runtime.device().side.rightVersion()); ::Focus.send(Runtime.device().side.rightVersion());
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} else if (::Focus.inputMatchesCommand(input, cmd_crc_errors)) { }
if (strcmp_P(command + 9, PSTR("crc_errors")) == 0) {
::Focus.send("left:"); ::Focus.send("left:");
::Focus.send(Runtime.device().side.leftCRCErrors()); ::Focus.send(Runtime.device().side.leftCRCErrors());
::Focus.send("\r\nright:"); ::Focus.send("\nright:");
::Focus.send(Runtime.device().side.rightCRCErrors()); ::Focus.send(Runtime.device().side.rightCRCErrors());
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} else if (::Focus.inputMatchesCommand(input, cmd_sled_ver)) { }
if (strcmp_P(command + 9, PSTR("sled_ver")) == 0) {
::Focus.send("left:"); ::Focus.send("left:");
::Focus.send(Runtime.device().side.leftSLEDVersion()); ::Focus.send(Runtime.device().side.leftSLEDVersion());
::Focus.send("\r\nright:"); ::Focus.send("\nright:");
::Focus.send(Runtime.device().side.rightSLEDVersion()); ::Focus.send(Runtime.device().side.rightSLEDVersion());
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} else if (::Focus.inputMatchesCommand(input, cmd_sled_current)) { }
if (strcmp_P(command + 9, PSTR("sled_current")) == 0) {
if (::Focus.isEOL()) { if (::Focus.isEOL()) {
::Focus.send("left:"); ::Focus.send("left:");
::Focus.send(Runtime.device().side.leftSLEDCurrent()); ::Focus.send(Runtime.device().side.leftSLEDCurrent());
::Focus.send("\r\nright:"); ::Focus.send("\nright:");
::Focus.send(Runtime.device().side.rightSLEDCurrent()); ::Focus.send(Runtime.device().side.rightSLEDCurrent());
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} else { } else {
@ -104,14 +99,20 @@ EventHandlerResult Focus::onFocusEvent(const char *input) {
Runtime.device().side.setSLEDCurrent(current); Runtime.device().side.setSLEDCurrent(current);
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
} else if (::Focus.inputMatchesCommand(input, cmd_layout)) { }
if (strcmp_P(command + 9, PSTR("layout")) == 0) {
static const auto ANSI = Runtime.device().settings.Layout::ANSI; static const auto ANSI = Runtime.device().settings.Layout::ANSI;
::Focus.send(Runtime.device().settings.layout() == ANSI ? "ANSI" : "ISO"); ::Focus.send(Runtime.device().settings.layout() == ANSI ? "ANSI" : "ISO");
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} else if (::Focus.inputMatchesCommand(input, cmd_joint)) { }
if (strcmp_P(command + 9, PSTR("joint")) == 0) {
::Focus.send(Runtime.device().settings.joint()); ::Focus.send(Runtime.device().settings.joint());
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} else if (::Focus.inputMatchesCommand(input, cmd_keyscan)) { }
if (strcmp_P(command + 9, PSTR("keyscan")) == 0) {
if (::Focus.isEOL()) { if (::Focus.isEOL()) {
::Focus.send(Runtime.device().settings.keyscanInterval()); ::Focus.send(Runtime.device().settings.keyscanInterval());
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;

@ -29,7 +29,7 @@ namespace raise {
class Focus : public kaleidoscope::Plugin { class Focus : public kaleidoscope::Plugin {
public: public:
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
}; };
} // namespace raise } // namespace raise

@ -34,14 +34,12 @@ class SideFlash : public kaleidoscope::Plugin {
_Firmware firmware; _Firmware firmware;
public: public:
EventHandlerResult onFocusEvent(const char *input) { EventHandlerResult onFocusEvent(const char *command) {
const char *cmd_flash_left = PSTR("hardware.flash_left_side"); if (::Focus.handleHelp(command, PSTR("hardware.flash_left_side\nhardware.flash_right_side\nhardware.verify_left_side\nhardware.verify_right_side")))
const char *cmd_flash_right = PSTR("hardware.flash_right_side"); return EventHandlerResult::OK;
const char *cmd_verify_left = PSTR("hardware.verify_left_side");
const char *cmd_verify_right = PSTR("hardware.verify_right_side");
if (::Focus.inputMatchesHelp(input)) if (strncmp_P(command, PSTR("hardware."), 9) != 0)
return ::Focus.printHelp(cmd_flash_left, cmd_flash_right, cmd_verify_left, cmd_verify_right); return EventHandlerResult::OK;
auto sideFlasher = Runtime.device().sideFlasher(); auto sideFlasher = Runtime.device().sideFlasher();
uint8_t left_boot_address = Runtime.device().side.left_boot_address; uint8_t left_boot_address = Runtime.device().side.left_boot_address;
@ -52,16 +50,16 @@ class SideFlash : public kaleidoscope::Plugin {
} sub_command; } sub_command;
uint8_t address = 0; uint8_t address = 0;
if (::Focus.inputMatchesCommand(input, cmd_flash_left)) { if (strcmp_P(command + 9, PSTR("flash_left_side")) == 0) {
sub_command = FLASH; sub_command = FLASH;
address = left_boot_address; address = left_boot_address;
} else if (::Focus.inputMatchesCommand(input, cmd_flash_right)) { } else if (strcmp_P(command + 9, PSTR("flash_right_side")) == 0) {
sub_command = FLASH; sub_command = FLASH;
address = right_boot_address; address = right_boot_address;
} else if (::Focus.inputMatchesCommand(input, cmd_verify_left)) { } else if (strcmp_P(command + 9, PSTR("verify_left_side")) == 0) {
sub_command = VERIFY; sub_command = VERIFY;
address = left_boot_address; address = left_boot_address;
} else if (::Focus.inputMatchesCommand(input, cmd_verify_right)) { } else if (strcmp_P(command + 9, PSTR("verify_right_side")) == 0) {
sub_command = VERIFY; sub_command = VERIFY;
address = right_boot_address; address = right_boot_address;
} else { } else {

@ -0,0 +1,153 @@
/* -*- mode: c++ -*-
* ErgoDox -- Chrysalis-enabled Sketch for ErgoDox-compatible boards
* Copyright (C) 2019-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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* This is based on the QMK factory firmware the ErgoDox EZ ships with. Modeled
* after the layout in
* https://configure.ergodox-ez.com/layouts/default/latest/0, as of 2019-01-04.
*/
#include "Kaleidoscope.h"
#include "Kaleidoscope-EEPROM-Settings.h"
#include "Kaleidoscope-EEPROM-Keymap.h"
#include "Kaleidoscope-FocusSerial.h"
#include "Kaleidoscope-MouseKeys.h"
#include "Kaleidoscope-Qukeys.h"
#include "Kaleidoscope-OneShot.h"
#include "Kaleidoscope-Escape-OneShot.h"
#include "Kaleidoscope-DynamicMacros.h"
// clang-format off
KEYMAPS(
[0] = KEYMAP_STACKED
(
// left hand
Key_Equals, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LeftArrow,
Key_Delete, Key_Q, Key_W, Key_E, Key_R, Key_T, LockLayer(1),
Key_Backspace, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_LeftShift, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Hyper,
LT(1, Backtick), Key_Quote, LALT(Key_LeftShift), Key_LeftArrow, Key_RightArrow,
MT(LeftAlt, PcApplication), Key_LeftGui,
Key_Home,
Key_Space, Key_Backspace, Key_End,
// right hand
Key_RightArrow, Key_6, Key_7, Key_8, Key_9, Key_0, Key_Minus,
LockLayer(1), Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Backslash,
Key_H, Key_J, Key_K, Key_L, LT(2, Semicolon), MT(LeftGui, Quote),
Key_Meh, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_RightShift,
Key_UpArrow, Key_DownArrow, Key_LeftBracket, Key_RightBracket, ShiftToLayer(1),
Key_LeftAlt, MT(LeftControl, Esc),
Key_PageUp,
Key_PageDown, Key_Tab, Key_Enter
),
[1] = KEYMAP_STACKED
(
// left hand
Key_Esc, Key_F1, Key_F2, Key_F3, Key_F4, Key_F5, XXX,
XXX, LSHIFT(Key_1), LSHIFT(Key_2), LSHIFT(Key_LeftBracket), LSHIFT(Key_RightBracket), LSHIFT(Key_Backslash), ___,
XXX, LSHIFT(Key_3), LSHIFT(Key_4), LSHIFT(Key_9), LSHIFT(Key_0), Key_Backtick,
XXX, LSHIFT(Key_5), LSHIFT(Key_6), Key_LeftBracket, Key_RightBracket, LSHIFT(Key_Backtick), XXX,
___, XXX, XXX, XXX, XXX,
XXX, XXX,
XXX,
XXX, XXX, XXX,
// right hand
XXX, Key_F6, Key_F7, Key_F8, Key_F9, Key_F10, Key_F11,
___, Key_UpArrow, Key_7, Key_8, Key_9, LSHIFT(Key_8), Key_F12,
Key_DownArrow, Key_4, Key_5, Key_6, XXX, XXX,
XXX, LSHIFT(Key_7), Key_1, Key_2, Key_3, Key_Backslash, XXX,
XXX, Key_Period, Key_0, Key_Equals, ___,
XXX, XXX,
XXX,
XXX, XXX, XXX
),
[2] = KEYMAP_STACKED
(
// left hand
XXX, XXX, XXX, XXX, XXX, XXX, XXX,
XXX, XXX, XXX, Key_mouseUp, XXX, XXX, XXX,
XXX, XXX, Key_mouseL, Key_mouseDn, Key_mouseR, XXX,
XXX, XXX, XXX, XXX, XXX, XXX, XXX,
XXX, XXX, XXX, Key_mouseBtnL, Key_mouseBtnR,
XXX, XXX,
XXX,
XXX, XXX, XXX,
// right hand
XXX, XXX, XXX, XXX, XXX, XXX, XXX,
XXX, XXX, XXX, XXX, XXX, XXX, XXX,
XXX, XXX, XXX, XXX, ___, Consumer_PlaySlashPause,
XXX, XXX, XXX, Consumer_ScanPreviousTrack, Consumer_ScanNextTrack, XXX, XXX,
Consumer_VolumeIncrement, Consumer_VolumeDecrement, Consumer_Mute, XXX, XXX,
XXX, XXX,
XXX,
XXX, XXX, XXX
),
)
// clang-format on
KALEIDOSCOPE_INIT_PLUGINS(
EEPROMSettings,
EEPROMKeymap,
Focus,
FocusEEPROMCommand,
FocusSettingsCommand,
Qukeys,
OneShot,
EscapeOneShot,
EscapeOneShotConfig,
DynamicMacros,
MouseKeys);
void blinkAllStatusLEDs() {
for (auto i = 0; i <= 3; i++) {
Kaleidoscope.device().setStatusLED(i, false);
}
for (auto i = 1; i <= 3; i++) {
Kaleidoscope.device().setStatusLED(i, true);
_delay_ms(50);
}
for (auto i = 1; i <= 3; i++) {
Kaleidoscope.device().setStatusLED(i, false);
_delay_ms(50);
}
}
void setup() {
Kaleidoscope.setup();
EEPROMKeymap.setup(5);
DynamicMacros.reserve_storage(256);
blinkAllStatusLEDs();
}
void loop() {
Kaleidoscope.loop();
}

@ -37,7 +37,7 @@ struct EvalProps : kaleidoscope::device::BaseProps {
typedef kaleidoscope::driver::hid::KeyboardioProps HIDProps; typedef kaleidoscope::driver::hid::KeyboardioProps HIDProps;
typedef kaleidoscope::driver::hid::Keyboardio<HIDProps> HID; typedef kaleidoscope::driver::hid::Keyboardio<HIDProps> HID;
typedef kaleidoscope::driver::bootloader::gd32::Base Bootloader; typedef kaleidoscope::driver::bootloader::gd32::Base BootLoader;
typedef EvalStorageProps StorageProps; typedef EvalStorageProps StorageProps;
typedef kaleidoscope::driver::storage::GD32Flash<StorageProps> Storage; typedef kaleidoscope::driver::storage::GD32Flash<StorageProps> Storage;

@ -24,16 +24,15 @@
#include "Kaleidoscope.h" #include "Kaleidoscope.h"
#include "Kaleidoscope-EEPROM-Settings.h" #include "Kaleidoscope-EEPROM-Settings.h"
#include "Kaleidoscope-EEPROM-Keymap.h" #include "Kaleidoscope-EEPROM-Keymap.h"
#include "Kaleidoscope-Escape-OneShot.h"
#include "Kaleidoscope-FirmwareVersion.h"
#include "Kaleidoscope-FocusSerial.h" #include "Kaleidoscope-FocusSerial.h"
#include "Kaleidoscope-Macros.h" #include "Kaleidoscope-Macros.h"
#include "Kaleidoscope-MouseKeys.h" #include "Kaleidoscope-MouseKeys.h"
#include "Kaleidoscope-OneShot.h" #include "Kaleidoscope-OneShot.h"
#include "Kaleidoscope-Escape-OneShot.h"
#include "Kaleidoscope-DynamicMacros.h"
#include "Kaleidoscope-Qukeys.h" #include "Kaleidoscope-Qukeys.h"
#include "Kaleidoscope-SpaceCadet.h" #include "Kaleidoscope-SpaceCadet.h"
#include "Kaleidoscope-DynamicMacros.h"
#include "Kaleidoscope-LayerNames.h"
#define MO(n) ShiftToLayer(n) #define MO(n) ShiftToLayer(n)
#define TG(n) LockLayer(n) #define TG(n) LockLayer(n)
@ -103,7 +102,6 @@ KEYMAPS(
// clang-format on // clang-format on
KALEIDOSCOPE_INIT_PLUGINS( KALEIDOSCOPE_INIT_PLUGINS(
EscapeOneShot,
EEPROMSettings, EEPROMSettings,
EEPROMKeymap, EEPROMKeymap,
Focus, Focus,
@ -112,12 +110,11 @@ KALEIDOSCOPE_INIT_PLUGINS(
Qukeys, Qukeys,
SpaceCadet, SpaceCadet,
OneShot, OneShot,
EscapeOneShot,
EscapeOneShotConfig,
Macros, Macros,
DynamicMacros, DynamicMacros,
MouseKeys, MouseKeys);
EscapeOneShotConfig,
FirmwareVersion,
LayerNames);
const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) { const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
if (keyToggledOn(event.state)) { if (keyToggledOn(event.state)) {
@ -142,14 +139,10 @@ const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
void setup() { void setup() {
Kaleidoscope.setup(); Kaleidoscope.setup();
SpaceCadet.disable();
EEPROMKeymap.setup(9);
DynamicMacros.reserve_storage(48); SpaceCadet.disable();
EEPROMKeymap.setup(7);
LayerNames.reserve_storage(63); DynamicMacros.reserve_storage(256);
Layer.move(EEPROMSettings.default_layer());
} }
void loop() { void loop() {

@ -45,7 +45,7 @@ struct AtreusProps : kaleidoscope::device::ATmega32U4KeyboardProps {
}; };
typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner; typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner;
typedef kaleidoscope::driver::bootloader::avr::Caterina Bootloader; typedef kaleidoscope::driver::bootloader::avr::Caterina BootLoader;
static constexpr const char *short_name = "atreus"; static constexpr const char *short_name = "atreus";
}; };

@ -99,7 +99,7 @@ struct ImagoProps : kaleidoscope::device::ATmega32U4KeyboardProps {
typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner; typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner;
typedef ImagoLEDDriverProps LEDDriverProps; typedef ImagoLEDDriverProps LEDDriverProps;
typedef ImagoLEDDriver LEDDriver; typedef ImagoLEDDriver LEDDriver;
typedef kaleidoscope::driver::bootloader::avr::Caterina Bootloader; typedef kaleidoscope::driver::bootloader::avr::Caterina BootLoader;
static constexpr const char *short_name = "imago"; static constexpr const char *short_name = "imago";
}; };

@ -1,12 +1,18 @@
// -*- mode: c++ -*- // -*- mode: c++ -*-
// Copyright 2016-2022 Keyboardio, inc. <jesse@keyboard.io> // Copyright 2016 Keyboardio, inc. <jesse@keyboard.io>
// See "LICENSE" for license details // See "LICENSE" for license details
#ifndef BUILD_INFORMATION
#define BUILD_INFORMATION "locally built on " __DATE__ " at " __TIME__
#endif
/** /**
* These #include directives pull in the Kaleidoscope firmware core, * These #include directives pull in the Kaleidoscope firmware core,
* as well as the Kaleidoscope plugins we use in the Model 100's firmware * as well as the Kaleidoscope plugins we use in the Model 01's firmware
*/ */
// The Kaleidoscope core // The Kaleidoscope core
#include "Kaleidoscope.h" #include "Kaleidoscope.h"
@ -17,11 +23,8 @@
// Support for communicating with the host via a simple Serial protocol // Support for communicating with the host via a simple Serial protocol
#include "Kaleidoscope-FocusSerial.h" #include "Kaleidoscope-FocusSerial.h"
// Support for querying the firmware version via Focus
#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 +33,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)
@ -60,12 +63,6 @@
// Support for an LED mode that lets one configure per-layer color maps // Support for an LED mode that lets one configure per-layer color maps
#include "Kaleidoscope-Colormap.h" #include "Kaleidoscope-Colormap.h"
// Support for turning the LEDs off after a certain amount of time
#include "Kaleidoscope-IdleLEDs.h"
// Support for setting and saving the default LED mode
#include "Kaleidoscope-DefaultLEDModeConfig.h"
// Support for Keyboardio's internal keyboard testing mode // Support for Keyboardio's internal keyboard testing mode
#include "Kaleidoscope-HardwareTestMode.h" #include "Kaleidoscope-HardwareTestMode.h"
@ -78,26 +75,7 @@
// Support for USB quirks, like changing the key state report protocol // Support for USB quirks, like changing the key state report protocol
#include "Kaleidoscope-USB-Quirks.h" #include "Kaleidoscope-USB-Quirks.h"
// Support for secondary actions on keys /** This 'enum' is a list of all the macros used by the Model 01's firmware
#include "Kaleidoscope-Qukeys.h"
// Support for one-shot modifiers and layer keys
#include "Kaleidoscope-OneShot.h"
#include "Kaleidoscope-Escape-OneShot.h"
// Support for dynamic, Chrysalis-editable macros
#include "Kaleidoscope-DynamicMacros.h"
// Support for SpaceCadet keys
#include "Kaleidoscope-SpaceCadet.h"
// Support for editable layer names
#include "Kaleidoscope-LayerNames.h"
// Support for the GeminiPR Stenography protocol
// #include "Kaleidoscope-Steno.h"
/** 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
* is unique. * is unique.
* *
@ -110,13 +88,12 @@
* a macro key is pressed. * a macro key is pressed.
*/ */
enum { enum { MACRO_VERSION_INFO,
MACRO_VERSION_INFO, MACRO_ANY
MACRO_ANY,
}; };
/** The Model 100's key layouts are defined as 'keymaps'. By default, there are three /** The Model 01's key layouts are defined as 'keymaps'. By default, there are three
* keymaps: The standard QWERTY keymap, the "Function layer" keymap and the "Numpad" * keymaps: The standard QWERTY keymap, the "Function layer" keymap and the "Numpad"
* keymap. * keymap.
* *
@ -127,10 +104,10 @@ enum {
* defined as part of the USB HID Keyboard specification. You can find the names * defined as part of the USB HID Keyboard specification. You can find the names
* (if not yet the explanations) for all the standard `Key_` defintions offered by * (if not yet the explanations) for all the standard `Key_` defintions offered by
* Kaleidoscope in these files: * Kaleidoscope in these files:
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/keyboard.h * https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_keyboard.h
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/consumerctl.h * https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_consumerctl.h
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/sysctl.h * https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_sysctl.h
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/keymaps.h * https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_keymaps.h
* *
* Additional things that should be documented here include * Additional things that should be documented here include
* using ___ to let keypresses fall through to the previously active layer * using ___ to let keypresses fall through to the previously active layer
@ -164,12 +141,9 @@ enum {
* *
*/ */
enum { enum { PRIMARY,
PRIMARY, NUMPAD,
// NUMPAD, FUNCTION }; // layers
FUNCTION,
ETC,
}; // layers
/** /**
@ -185,10 +159,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 +172,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)),
#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_G, Key_Tab,
Key_PageUp, Key_A, Key_R, Key_S, Key_T, Key_D,
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_J, Key_L, Key_U, Key_Y, Key_Semicolon, Key_Equals,
Key_H, Key_N, Key_E, Key_I, Key_O, Key_Quote,
Key_RightAlt, Key_K, Key_M, 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),
[ETC] = KEYMAP_STACKED 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 +255,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 */
@ -255,8 +288,8 @@ KEYMAPS(
static void versionInfoMacro(uint8_t key_state) { static void versionInfoMacro(uint8_t key_state) {
if (keyToggledOn(key_state)) { if (keyToggledOn(key_state)) {
Macros.type(PSTR("Keyboardio Model 100 - Firmware version ")); Macros.type(PSTR("Keyboardio Model 01 - Kaleidoscope "));
Macros.type(PSTR(KALEIDOSCOPE_FIRMWARE_VERSION)); Macros.type(PSTR(BUILD_INFORMATION));
} }
} }
@ -305,7 +338,7 @@ const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
// These 'solid' color effect definitions define a rainbow of // These 'solid' color effect definitions define a rainbow of
// LED color modes calibrated to draw 500mA or less on the // LED color modes calibrated to draw 500mA or less on the
// Keyboardio Model 100. // Keyboardio Model 01.
static kaleidoscope::plugin::LEDSolidColor solidRed(160, 0, 0); static kaleidoscope::plugin::LEDSolidColor solidRed(160, 0, 0);
@ -340,7 +373,7 @@ void hostPowerManagementEventHandler(kaleidoscope::plugin::HostPowerManagement::
toggleLedsOnSuspendResume(event); toggleLedsOnSuspendResume(event);
} }
/** This 'enum' is a list of all the magic combos used by the Model 100's /** This 'enum' is a list of all the magic combos used by the Model 01's
* firmware The names aren't particularly important. What is important is that * firmware The names aren't particularly important. What is important is that
* each is unique. * each is unique.
* *
@ -365,17 +398,6 @@ static void toggleKeyboardProtocol(uint8_t combo_index) {
USBQuirks.toggleKeyboardProtocol(); USBQuirks.toggleKeyboardProtocol();
} }
/**
* Toggles between using the built-in keymap, and the EEPROM-stored one.
*/
static void toggleKeymapSource(uint8_t combo_index) {
if (Layer.getKey == Layer.getKeyFromPROGMEM) {
Layer.getKey = EEPROMKeymap.getKey;
} else {
Layer.getKey = Layer.getKeyFromPROGMEM;
}
}
/** /**
* This enters the hardware test mode * This enters the hardware test mode
*/ */
@ -392,10 +414,7 @@ USE_MAGIC_COMBOS({.action = toggleKeyboardProtocol,
.keys = {R3C6, R2C6, R3C7}}, .keys = {R3C6, R2C6, R3C7}},
{.action = enterHardwareTestMode, {.action = enterHardwareTestMode,
// Left Fn + Prog + LED // Left Fn + Prog + LED
.keys = {R3C6, R0C0, R0C6}}, .keys = {R3C6, R0C0, R0C6}});
{.action = toggleKeymapSource,
// Left Fn + Prog + Shift
.keys = {R3C6, R0C0, R3C7}});
// First, tell Kaleidoscope which plugins you want to use. // First, tell Kaleidoscope which plugins you want to use.
// The order can be important. For example, LED effects are // The order can be important. For example, LED effects are
@ -406,12 +425,6 @@ KALEIDOSCOPE_INIT_PLUGINS(
EEPROMSettings, EEPROMSettings,
EEPROMKeymap, EEPROMKeymap,
// SpaceCadet can turn your shifts into parens on tap, while keeping them as
// Shifts when held. SpaceCadetConfig lets Chrysalis configure some aspects of
// the plugin.
// SpaceCadet,
// 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.
Focus, Focus,
@ -479,13 +492,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.
@ -500,42 +513,7 @@ KALEIDOSCOPE_INIT_PLUGINS(
// comfortable - or able - to do automatically, but can be useful // comfortable - or able - to do automatically, but can be useful
// nevertheless. Such as toggling the key report protocol between Boot (used // nevertheless. Such as toggling the key report protocol between Boot (used
// by BIOSes) and Report (NKRO). // by BIOSes) and Report (NKRO).
USBQuirks, USBQuirks);
// The Qukeys plugin enables the "Secondary action" functionality in
// Chrysalis. Keys with secondary actions will have their primary action
// performed when tapped, but the secondary action when held.
Qukeys,
// Enables the "Sticky" behavior for modifiers, and the "Layer shift when
// held" functionality for layer keys.
OneShot,
EscapeOneShot,
EscapeOneShotConfig,
// Turns LEDs off after a configurable amount of idle time.
IdleLEDs,
PersistentIdleLEDs,
// Enables dynamic, Chrysalis-editable macros.
DynamicMacros,
// The FirmwareVersion plugin lets Chrysalis query the version of the firmware
// programmatically.
FirmwareVersion,
// The LayerNames plugin allows Chrysalis to display - and edit - custom layer
// names, to be shown instead of the default indexes.
LayerNames,
// Enables setting, saving (via Chrysalis), and restoring (on boot) the
// default LED mode.
DefaultLEDModeConfig
// Enables the GeminiPR Stenography protocol. Unused by default, but with the
// plugin enabled, it becomes configurable - and then usable - via Chrysalis.
//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
@ -545,21 +523,17 @@ void setup() {
// First, call Kaleidoscope's internal setup function // First, call Kaleidoscope's internal setup function
Kaleidoscope.setup(); Kaleidoscope.setup();
// Set the hue of the boot greeting effect to something that will result in a
// nice green color.
BootGreetingEffect.hue = 85;
// 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);
// We set the brightness of the rainbow effects to 150 (on a scale of 0-255) // We set the brightness of the rainbow effects to 150 (on a scale of 0-255)
// This draws more than 500mA, but looks much nicer than a dimmer effect // This draws more than 500mA, but looks much nicer than a dimmer effect
LEDRainbowEffect.brightness(255); LEDRainbowEffect.brightness(150);
LEDRainbowWaveEffect.brightness(255); LEDRainbowWaveEffect.brightness(150);
// Set the action key the test mode should listen for to Left Fn // Set the action key the test mode should listen for to Left Fn
HardwareTestMode.setActionKey(R3C6); HardwareTestMode.setActionKey(R3C6);
@ -569,41 +543,22 @@ void setup() {
// https://github.com/keyboardio/Kaleidoscope/blob/master/docs/plugins/LED-Stalker.md // https://github.com/keyboardio/Kaleidoscope/blob/master/docs/plugins/LED-Stalker.md
StalkerEffect.variant = STALKER(BlazingTrail); StalkerEffect.variant = STALKER(BlazingTrail);
// We want to make sure that the firmware starts with LED effects off
// This avoids over-taxing devices that don't have a lot of power to share
// with USB devices
LEDOff.activate();
// To make the keymap editable without flashing new firmware, we store // To make the keymap editable without flashing new firmware, we store
// additional layers in EEPROM. For now, we reserve space for eight layers. If // additional layers in EEPROM. For now, we reserve space for five layers. If
// one wants to use these layers, just set the default layer to one in EEPROM, // one wants to use these layers, just set the default layer to one in EEPROM,
// by using the `settings.defaultLayer` Focus command, or by using the // by using the `settings.defaultLayer` Focus command, or by using the
// `keymap.onlyCustom` command to use EEPROM layers only. // `keymap.onlyCustom` command to use EEPROM layers only.
EEPROMKeymap.setup(8); EEPROMKeymap.setup(5);
// We need to tell the Colormap plugin how many layers we want to have custom // We need to tell the Colormap plugin how many layers we want to have custom
// maps for. To make things simple, we set it to eight layers, which is how // maps for. To make things simple, we set it to five layers, which is how
// many editable layers we have (see above). // many editable layers we have (see above).
ColormapEffect.max_layers(8); ColormapEffect.max_layers(5);
// For Dynamic Macros, we need to reserve storage space for the editable
// macros. A kilobyte is a reasonable default.
DynamicMacros.reserve_storage(1024);
// If there's a default layer set in EEPROM, we should set that as the default
// here.
Layer.move(EEPROMSettings.default_layer());
// 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
// no configuration exists.
// SpaceCadetConfig.disableSpaceCadetIfUnconfigured();
// SpaceCadet.disable();
// 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
// reserve 17 / layer in total.
LayerNames.reserve_storage(17 * 8);
// Unless configured otherwise with Chrysalis, we want to make sure that the
// firmware starts with LED effects off. This avoids over-taxing devices that
// don't have a lot of power to share with USB devices
DefaultLEDModeConfig.activateLEDModeIfUnconfigured(&LEDOff);
} }
/** loop is the second of the standard Arduino sketch functions. /** loop is the second of the standard Arduino sketch functions.

@ -126,7 +126,7 @@ struct Model01Props : public kaleidoscope::device::ATmega32U4KeyboardProps {
typedef Model01LEDDriver LEDDriver; typedef Model01LEDDriver LEDDriver;
typedef Model01KeyScannerProps KeyScannerProps; typedef Model01KeyScannerProps KeyScannerProps;
typedef Model01KeyScanner KeyScanner; typedef Model01KeyScanner KeyScanner;
typedef kaleidoscope::driver::bootloader::avr::Caterina Bootloader; typedef kaleidoscope::driver::bootloader::avr::Caterina BootLoader;
static constexpr const char *short_name = "kbio01"; static constexpr const char *short_name = "kbio01";
}; };

@ -1,5 +1,5 @@
// -*- mode: c++ -*- // -*- mode: c++ -*-
// Copyright 2016 Keyboardio, inc. <jesse@keyboard.io> // Copyright 2016-2022 Keyboardio, inc. <jesse@keyboard.io>
// See "LICENSE" for license details // See "LICENSE" for license details
#ifndef BUILD_INFORMATION #ifndef BUILD_INFORMATION
@ -9,7 +9,7 @@
/** /**
* These #include directives pull in the Kaleidoscope firmware core, * These #include directives pull in the Kaleidoscope firmware core,
* as well as the Kaleidoscope plugins we use in the Model 01's firmware * as well as the Kaleidoscope plugins we use in the Model 100's firmware
*/ */
@ -23,22 +23,15 @@
// Support for communicating with the host via a simple Serial protocol // Support for communicating with the host via a simple Serial protocol
#include "Kaleidoscope-FocusSerial.h" #include "Kaleidoscope-FocusSerial.h"
// Support for querying the firmware version via Focus
#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 & dynamic macros // Support for macros
#include "Kaleidoscope-Macros.h" #include "Kaleidoscope-Macros.h"
#include "Kaleidoscope-DynamicMacros.h"
// Support for controlling the keyboard's LEDs // Support for controlling the keyboard's LEDs
#include "Kaleidoscope-LEDControl.h" #include "Kaleidoscope-LEDControl.h"
// Support for "Numpad" mode, which is mostly just the Numpad specific LED mode
#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)
#include "Kaleidoscope-LEDEffect-BootGreeting.h" #include "Kaleidoscope-LEDEffect-BootGreeting.h"
@ -55,12 +48,24 @@
// Support for LED modes that pulse the keyboard's LED in a rainbow pattern // Support for LED modes that pulse the keyboard's LED in a rainbow pattern
#include "Kaleidoscope-LEDEffect-Rainbow.h" #include "Kaleidoscope-LEDEffect-Rainbow.h"
// Support for an LED mode that lights up the keys as you press them
#include "Kaleidoscope-LED-Stalker.h"
// Support for an LED mode that prints the keys you press in letters 4px high
#include "Kaleidoscope-LED-AlphaSquare.h"
// Support for shared palettes for other plugins, like Colormap below // Support for shared palettes for other plugins, like Colormap below
#include "Kaleidoscope-LED-Palette-Theme.h" #include "Kaleidoscope-LED-Palette-Theme.h"
// Support for an LED mode that lets one configure per-layer color maps // Support for an LED mode that lets one configure per-layer color maps
#include "Kaleidoscope-Colormap.h" #include "Kaleidoscope-Colormap.h"
// Support for turning the LEDs off after a certain amount of time
#include "Kaleidoscope-IdleLEDs.h"
// Support for setting a default LED mode
#include "Kaleidoscope-DefaultLEDModeConfig.h"
// Support for Keyboardio's internal keyboard testing mode // Support for Keyboardio's internal keyboard testing mode
#include "Kaleidoscope-HardwareTestMode.h" #include "Kaleidoscope-HardwareTestMode.h"
@ -70,13 +75,20 @@
// Support for magic combos (key chords that trigger an action) // Support for magic combos (key chords that trigger an action)
#include "Kaleidoscope-MagicCombo.h" #include "Kaleidoscope-MagicCombo.h"
// Support for secondary actions (one action when tapped, another when held)
#include "Kaleidoscope-Qukeys.h"
// Support for USB quirks, like changing the key state report protocol // Support for USB quirks, like changing the key state report protocol
#include "Kaleidoscope-USB-Quirks.h" #include "Kaleidoscope-USB-Quirks.h"
/** This 'enum' is a list of all the macros used by the Model 01's firmware // Support for secondary actions on keys
#include "Kaleidoscope-Qukeys.h"
// Support for one-shot modifiers and layer keys
#include "Kaleidoscope-OneShot.h"
#include "Kaleidoscope-Escape-OneShot.h"
// Support for dynamic, Chrysalis-editable macros
#include "Kaleidoscope-DynamicMacros.h"
/** 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
* is unique. * is unique.
* *
@ -89,12 +101,13 @@
* a macro key is pressed. * a macro key is pressed.
*/ */
enum { MACRO_VERSION_INFO, enum {
MACRO_ANY MACRO_VERSION_INFO,
MACRO_ANY,
}; };
/** The Model 01's key layouts are defined as 'keymaps'. By default, there are three /** The Model 100's key layouts are defined as 'keymaps'. By default, there are three
* keymaps: The standard QWERTY keymap, the "Function layer" keymap and the "Numpad" * keymaps: The standard QWERTY keymap, the "Function layer" keymap and the "Numpad"
* keymap. * keymap.
* *
@ -105,10 +118,10 @@ enum { MACRO_VERSION_INFO,
* defined as part of the USB HID Keyboard specification. You can find the names * defined as part of the USB HID Keyboard specification. You can find the names
* (if not yet the explanations) for all the standard `Key_` defintions offered by * (if not yet the explanations) for all the standard `Key_` defintions offered by
* Kaleidoscope in these files: * Kaleidoscope in these files:
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_keyboard.h * https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/keyboard.h
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_consumerctl.h * https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/consumerctl.h
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_sysctl.h * https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/sysctl.h
* https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs_keymaps.h * https://github.com/keyboardio/Kaleidoscope/blob/master/src/kaleidoscope/key_defs/keymaps.h
* *
* Additional things that should be documented here include * Additional things that should be documented here include
* using ___ to let keypresses fall through to the previously active layer * using ___ to let keypresses fall through to the previously active layer
@ -142,9 +155,11 @@ enum { MACRO_VERSION_INFO,
* *
*/ */
enum { PRIMARY, enum {
PRIMARY,
NUMPAD, NUMPAD,
FUNCTION }; // layers FUNCTION,
}; // layers
/** /**
@ -169,155 +184,75 @@ enum { PRIMARY,
/* This comment temporarily turns off astyle's indent enforcement /* This comment temporarily turns off astyle's indent enforcement
* so we can make the keymaps actually resemble the physical key layout better * so we can make the keymaps actually resemble the physical key layout better
*/ */
// *INDENT-OFF* // clang-format off
KEYMAPS( KEYMAPS(
#if defined(PRIMARY_KEYMAP_QWERTY) #if defined (PRIMARY_KEYMAP_QWERTY)
[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), [PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
M(MACRO_ANY), Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_6, Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_7, Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_8, Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_9, ShiftToLayer(FUNCTION),
Key_0,
LockLayer(NUMPAD), M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_Y, Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_U, Key_RightAlt, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_I, Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
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)), ShiftToLayer(FUNCTION)),
#elif defined(PRIMARY_KEYMAP_DVORAK) #elif defined (PRIMARY_KEYMAP_DVORAK)
[PRIMARY] = KEYMAP_STACKED(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext, Key_Backtick, Key_Quote, Key_Comma, Key_Period, Key_P, Key_Y, Key_Tab, Key_PageUp, Key_A, Key_O, Key_E, Key_U, Key_I, Key_PageDown, Key_Semicolon, Key_Q, Key_J, Key_K, Key_X, Key_Escape, Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift, ShiftToLayer(FUNCTION), [PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
M(MACRO_ANY), Key_Backtick, Key_Quote, Key_Comma, Key_Period, Key_P, Key_Y, Key_Tab,
Key_6, Key_PageUp, Key_A, Key_O, Key_E, Key_U, Key_I,
Key_7, Key_PageDown, Key_Semicolon, Key_Q, Key_J, Key_K, Key_X, Key_Escape,
Key_8, Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_9, ShiftToLayer(FUNCTION),
Key_0,
LockLayer(NUMPAD), M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_Enter, Key_F, Key_G, Key_C, Key_R, Key_L, Key_Slash,
Key_F, Key_D, Key_H, Key_T, Key_N, Key_S, Key_Minus,
Key_G, Key_RightAlt, Key_B, Key_M, Key_W, Key_V, Key_Z, Key_Equals,
Key_C, Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
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)), ShiftToLayer(FUNCTION)),
#elif defined(PRIMARY_KEYMAP_COLEMAK) #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_G, Key_Tab, Key_PageUp, Key_A, Key_R, Key_S, Key_T, Key_D, Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape, Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift, ShiftToLayer(FUNCTION), [PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
M(MACRO_ANY), Key_Backtick, Key_Q, Key_W, Key_F, Key_P, Key_G, Key_Tab,
Key_6, Key_PageUp, Key_A, Key_R, Key_S, Key_T, Key_D,
Key_7, Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_8, Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_9, ShiftToLayer(FUNCTION),
Key_0,
LockLayer(NUMPAD), M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_Enter, Key_J, Key_L, Key_U, Key_Y, Key_Semicolon, Key_Equals,
Key_J, Key_H, Key_N, Key_E, Key_I, Key_O, Key_Quote,
Key_L, Key_RightAlt, Key_K, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_U, Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
Key_Y,
Key_Semicolon,
Key_Equals,
Key_H,
Key_N,
Key_E,
Key_I,
Key_O,
Key_Quote,
Key_RightAlt,
Key_K,
Key_M,
Key_Comma,
Key_Period,
Key_Slash,
Key_Minus,
Key_RightShift,
Key_LeftAlt,
Key_Spacebar,
Key_RightControl,
ShiftToLayer(FUNCTION)), ShiftToLayer(FUNCTION)),
#elif defined(PRIMARY_KEYMAP_CUSTOM) #elif defined (PRIMARY_KEYMAP_CUSTOM)
// Edit this keymap to make a custom layout // 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), [PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext,
M(MACRO_ANY), Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_6, Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_7, Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_8, Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_9, ShiftToLayer(FUNCTION),
Key_0,
LockLayer(NUMPAD), M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_Y, Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_U, Key_RightAlt, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_I, Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
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)), ShiftToLayer(FUNCTION)),
#else #else
@ -327,78 +262,98 @@ KEYMAPS(
#endif #endif
[NUMPAD] = KEYMAP_STACKED(___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___,
M(MACRO_VERSION_INFO), [NUMPAD] = KEYMAP_STACKED
___, (___, ___, ___, ___, ___, ___, ___,
Key_7, ___, ___, ___, ___, ___, ___, ___,
Key_8, ___, ___, ___, ___, ___, ___,
Key_9, ___, ___, ___, ___, ___, ___, ___,
Key_KeypadSubtract, ___, ___, ___, ___,
___,
___,
___,
Key_4,
Key_5,
Key_6,
Key_KeypadAdd,
___,
___,
Key_1,
Key_2,
Key_3,
Key_Equals,
___,
___,
___,
Key_0,
Key_Period,
Key_KeypadMultiply,
Key_KeypadDivide,
Key_Enter,
___,
___,
___,
___, ___,
M(MACRO_VERSION_INFO), ___, Key_7, Key_8, Key_9, Key_KeypadSubtract, ___,
___, ___, Key_4, Key_5, Key_6, Key_KeypadAdd, ___,
___, Key_1, Key_2, Key_3, Key_Equals, ___,
___, ___, 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, ___, ___, ___, [FUNCTION] = KEYMAP_STACKED
(___, Key_F1, Key_F2, Key_F3, Key_F4, Key_F5, Key_CapsLock,
Consumer_ScanPreviousTrack, Key_Tab, ___, Key_mouseUp, ___, Key_mouseBtnR, Key_mouseWarpEnd, Key_mouseWarpNE,
Key_F6, Key_Home, Key_mouseL, Key_mouseDn, Key_mouseR, Key_mouseBtnL, Key_mouseWarpNW,
Key_F7, Key_End, Key_PrintScreen, Key_Insert, ___, Key_mouseBtnM, Key_mouseWarpSW, Key_mouseWarpSE,
Key_F8, ___, Key_Delete, ___, ___,
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_ScanPreviousTrack, Key_F6, Key_F7, Key_F8, Key_F9, Key_F10, Key_F11,
Consumer_Mute, Consumer_PlaySlashPause, Consumer_ScanNextTrack, Key_LeftCurlyBracket, Key_RightCurlyBracket, Key_LeftBracket, Key_RightBracket, Key_F12,
Consumer_VolumeDecrement, Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, ___, ___,
Consumer_VolumeIncrement, Key_PcApplication, Consumer_Mute, Consumer_VolumeDecrement, Consumer_VolumeIncrement, ___, Key_Backslash, Key_Pipe,
___, ___, ___, Key_Enter, ___,
Key_Backslash, ___)
Key_Pipe, ) // KEYMAPS(
___,
___, // Define an EGA palette. Conveniently, that's exactly 16 colors, just like the
Key_Enter, // limit of LEDPaletteTheme.
___, //
___)) // KEYMAPS( // We have black and white swapped compared to a normal palette, because of
// technical reasons: colormap defaults to the last color of the palette.
PALETTE(
CRGB(0xff, 0xff, 0xff), // [0x0] white
CRGB(0x00, 0x00, 0xaa), // [0x1] blue
CRGB(0x00, 0xaa, 0x00), // [0x2] green
CRGB(0x00, 0xaa, 0xaa), // [0x3] cyan
CRGB(0xaa, 0x00, 0x00), // [0x4] red
CRGB(0xaa, 0x00, 0xaa), // [0x5] magenta
CRGB(0xaa, 0x55, 0x00), // [0x6] brown
CRGB(0xaa, 0xaa, 0xaa), // [0x7] light gray
CRGB(0x55, 0x55, 0x55), // [0x8] dark gray
CRGB(0x55, 0x55, 0xff), // [0x9] bright blue
CRGB(0x55, 0xff, 0x55), // [0xa] bright green
CRGB(0x55, 0xff, 0xff), // [0xb] bright cyan
CRGB(0xff, 0x55, 0x55), // [0xc] bright red
CRGB(0xff, 0x55, 0xff), // [0xd] bright magenta
CRGB(0xff, 0xff, 0x55), // [0xe] yellow
CRGB(0x00, 0x00, 0x00) // [0xf] black
) // PALETTE
COLORMAPS(
// Our Primary layer has all LEDs off
[PRIMARY] = COLORMAP_STACKED(
0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf,
0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf,
0xf),
// For the Numpad layer, we set the num lock key to blue, and the numpad keys
// to red.
[NUMPAD] = COLORMAP_STACKED(
0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
0xf, 0xf, 0xf, 0xf,
0xf,
0xf, 0xf, 0x4, 0x4, 0x4, 0x4, 0x1,
0xf, 0xf, 0x4, 0x4, 0x4, 0x4, 0xf,
0xf, 0x4, 0x4, 0x4, 0x4, 0xf,
0xf, 0xf, 0x4, 0x4, 0x4, 0x4, 0x4,
0xf, 0xf, 0xf, 0xf,
0xf)
)
/* Re-enable astyle's indent enforcement */ /* Re-enable astyle's indent enforcement */
// *INDENT-ON* // clang-format on
/** versionInfoMacro handles the 'firmware version info' macro /** versionInfoMacro handles the 'firmware version info' macro
* When a key bound to the macro is pressed, this macro * When a key bound to the macro is pressed, this macro
@ -407,7 +362,7 @@ KEYMAPS(
static void versionInfoMacro(uint8_t key_state) { static void versionInfoMacro(uint8_t key_state) {
if (keyToggledOn(key_state)) { if (keyToggledOn(key_state)) {
Macros.type(PSTR("Keyboardio Model 01 - Kaleidoscope ")); Macros.type(PSTR("Keyboardio Model 100 - Kaleidoscope "));
Macros.type(PSTR(BUILD_INFORMATION)); Macros.type(PSTR(BUILD_INFORMATION));
} }
} }
@ -457,7 +412,7 @@ const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
// These 'solid' color effect definitions define a rainbow of // These 'solid' color effect definitions define a rainbow of
// LED color modes calibrated to draw 500mA or less on the // LED color modes calibrated to draw 500mA or less on the
// Keyboardio Model 01. // Keyboardio Model 100.
static kaleidoscope::plugin::LEDSolidColor solidRed(160, 0, 0); static kaleidoscope::plugin::LEDSolidColor solidRed(160, 0, 0);
@ -492,7 +447,7 @@ void hostPowerManagementEventHandler(kaleidoscope::plugin::HostPowerManagement::
toggleLedsOnSuspendResume(event); toggleLedsOnSuspendResume(event);
} }
/** This 'enum' is a list of all the magic combos used by the Model 01's /** This 'enum' is a list of all the magic combos used by the Model 100's
* firmware The names aren't particularly important. What is important is that * firmware The names aren't particularly important. What is important is that
* each is unique. * each is unique.
* *
@ -595,30 +550,29 @@ KALEIDOSCOPE_INIT_PLUGINS(
// The breathe effect slowly pulses all of the LEDs on your keyboard // The breathe effect slowly pulses all of the LEDs on your keyboard
LEDBreatheEffect, LEDBreatheEffect,
// The AlphaSquare effect prints each character you type, using your
// keyboard's LEDs as a display
AlphaSquareEffect,
// The stalker effect lights up the keys you've pressed recently
StalkerEffect,
// The LED Palette Theme plugin provides a shared palette for other plugins, // The LED Palette Theme plugin provides a shared palette for other plugins,
// like Colormap below // like Colormap below
LEDPaletteTheme, LEDPaletteTheme,
// The Colormap effect makes it possible to set up per-layer colormaps // The Colormap effect makes it possible to set up per-layer colormaps
ColormapEffect, ColormapEffect,
// The default colormap plugin allows us to set up a default palette &
// colormap.
DefaultColormap,
// The numpad plugin is responsible for lighting up the 'numpad' mode // The macros plugin adds support for macros
// with a custom LED effect
NumPad,
// The macros plugin adds support for macros, DynamicMacros does the same for
// Chrysalis-editable, dynamic ones.
Macros, Macros,
DynamicMacros,
// 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,
// Qukeys lets you add secondary actions to keys, such that they do their
// original action on tap, but another action (usually a modifier or a layer
// shift action) when held.
Qukeys,
// 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.
HostPowerManagement, HostPowerManagement,
@ -634,9 +588,26 @@ KALEIDOSCOPE_INIT_PLUGINS(
// by BIOSes) and Report (NKRO). // by BIOSes) and Report (NKRO).
USBQuirks, USBQuirks,
// The FirmwareVersion plugin lets Chrysalis query the version of the firmware // The Qukeys plugin enables the "Secondary action" functionality in
// programmatically. // Chrysalis. Keys with secondary actions will have their primary action
FirmwareVersion); // performed when tapped, but the secondary action when held.
Qukeys,
// Enables the "Sticky" behavior for modifiers, and the "Layer shift when
// held" functionality for layer keys.
OneShot,
EscapeOneShot,
EscapeOneShotConfig,
// Turns LEDs off after a configurable amount of idle time.
IdleLEDs,
PersistentIdleLEDs,
// Enables setting a default LED mode without compiling new firmware.
DefaultLEDModeConfig,
// Enables dynamic, Chrysalis-editable macros.
DynamicMacros);
/** 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
@ -646,42 +617,44 @@ void setup() {
// First, call Kaleidoscope's internal setup function // First, call Kaleidoscope's internal setup function
Kaleidoscope.setup(); Kaleidoscope.setup();
// While we hope to improve this in the future, the NumPad plugin // We configure the AlphaSquare effect to use RED letters
// needs to be explicitly told which keymap layer is your numpad layer AlphaSquare.color = CRGB(255, 0, 0);
NumPad.numPadLayer = NUMPAD;
// We set the brightness of the rainbow effects to 150 (on a scale of 0-255) // We set the brightness of the rainbow effects to 150 (on a scale of 0-255)
// This draws more than 500mA, but looks much nicer than a dimmer effect // This draws more than 500mA, but looks much nicer than a dimmer effect
LEDRainbowEffect.brightness(150); LEDRainbowEffect.brightness(255);
LEDRainbowWaveEffect.brightness(150); LEDRainbowWaveEffect.brightness(255);
// Set the action key the test mode should listen for to Left Fn // Set the action key the test mode should listen for to Left Fn
HardwareTestMode.setActionKey(R3C6); HardwareTestMode.setActionKey(R3C6);
// We want to make sure that the firmware starts with LED effects off // The LED Stalker mode has a few effects. The one we like is called
// This avoids over-taxing devices that don't have a lot of power to share // 'BlazingTrail'. For details on other options, see
// with USB devices // https://github.com/keyboardio/Kaleidoscope/blob/master/docs/plugins/LED-Stalker.md
LEDOff.activate(); StalkerEffect.variant = STALKER(BlazingTrail);
// To make the keymap editable without flashing new firmware, we store // To make the keymap editable without flashing new firmware, we store
// additional layers in EEPROM. For now, we reserve space for five layers. If // additional layers in EEPROM. For now, we reserve space for eight layers. If
// one wants to use these layers, just set the default layer to one in EEPROM, // one wants to use these layers, just set the default layer to one in EEPROM,
// by using the `settings.defaultLayer` Focus command, or by using the // by using the `settings.defaultLayer` Focus command, or by using the
// `keymap.onlyCustom` command to use EEPROM layers only. // `keymap.onlyCustom` command to use EEPROM layers only.
EEPROMKeymap.setup(5); EEPROMKeymap.setup(8);
// We need to tell the Colormap plugin how many layers we want to have custom // We need to tell the Colormap plugin how many layers we want to have custom
// maps for. To make things simple, we set it to five layers, which is how // maps for. To make things simple, we set it to eight layers, which is how
// many editable layers we have (see above). // many editable layers we have (see above).
ColormapEffect.max_layers(5); ColormapEffect.max_layers(8);
// For Dynamic Macros, we need to reserve storage space for the editable // For Dynamic Macros, we need to reserve storage space for the editable
// macros. // macros. A kilobyte is a reasonable default.
DynamicMacros.reserve_storage(128); DynamicMacros.reserve_storage(1024);
// Install a default palette & colormap if none are present
DefaultColormap.setup();
// If there's a default layer set in EEPROM, we should set that as the default // If our EEPROM is uninitialized, default to the ColormapEffect as our
// here. // default LED mode.
Layer.move(EEPROMSettings.default_layer()); DefaultLEDModeConfig.activateLEDModeIfUnconfigured(&ColormapEffect);
} }
/** loop is the second of the standard Arduino sketch functions. /** loop is the second of the standard Arduino sketch functions.

@ -1,6 +1,6 @@
name=Kaleidoscope-Hardware-Keyboardio-Model01 name=Kaleidoscope-Hardware-Keyboardio-Model100
version=0.0.0 version=0.0.0
sentence=Keyboardio Model01 hardware support for Kaleidoscope sentence=Keyboardio Model100 hardware support for Kaleidoscope
maintainer=Kaleidoscope's Developers <jesse@keyboard.io> maintainer=Kaleidoscope's Developers <jesse@keyboard.io>
url=https://github.com/keyboardio/Kaleidoscope url=https://github.com/keyboardio/Kaleidoscope
author=Keyboardio author=Keyboardio

@ -141,7 +141,7 @@ struct Model100Props : public kaleidoscope::device::BaseProps {
typedef Model100StorageProps StorageProps; typedef Model100StorageProps StorageProps;
typedef kaleidoscope::driver::storage::GD32Flash<StorageProps> Storage; typedef kaleidoscope::driver::storage::GD32Flash<StorageProps> Storage;
typedef kaleidoscope::driver::bootloader::gd32::Base Bootloader; typedef kaleidoscope::driver::bootloader::gd32::Base BootLoader;
static constexpr const char *short_name = "kbio100"; static constexpr const char *short_name = "kbio100";
typedef kaleidoscope::driver::mcu::GD32Props MCUProps; typedef kaleidoscope::driver::mcu::GD32Props MCUProps;

@ -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));
} }

@ -0,0 +1,275 @@
/* -*- mode: c++ -*-
* Splitography-Sketch -- Chrysalis-enabled sketch for the Splitography
* Copyright (C) 2018-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, either version 3 of the License, or
* (at your option) any later version.
*
* 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/>.
*
* Modeled after the default QMK layout:
* https://github.com/sdothum/qmk_firmware/blob/d865c82efa19beb7cb593e7d3affb2311017833e/keyboards/splitography/keymaps/default/keymap.c
*/
#include "Kaleidoscope.h"
#include "Kaleidoscope-EEPROM-Settings.h"
#include "Kaleidoscope-EEPROM-Keymap.h"
#include "Kaleidoscope-FocusSerial.h"
#include "Kaleidoscope-Ranges.h"
#include "Kaleidoscope-Steno.h"
#include "Kaleidoscope-MouseKeys.h"
#include "Kaleidoscope-Qukeys.h"
#include "Kaleidoscope-OneShot.h"
#include "Kaleidoscope-Escape-OneShot.h"
#include "Kaleidoscope-DynamicMacros.h"
// Layers
enum {
_QWERTY,
_BLUE,
_ORANGE,
_GREEN,
_STENO,
_PLOVER
};
// Custom keys
enum {
QWERTY_1 = kaleidoscope::ranges::SAFE_START,
QWERTY_2
};
#define QWERTY1 Key(QWERTY_1)
#define QWERTY2 Key(QWERTY_2)
#define MO(layer) ShiftToLayer(layer)
#define TO(layer) LockLayer(layer)
#define K_STP Consumer_Stop
#define K_PRV Consumer_ScanPreviousTrack
#define K_NXT Consumer_ScanNextTrack
#define K_PLY Consumer_PlaySlashPause
// Key aliases
#define Key_PgUp Key_PageUp
#define Key_PageDn Key_PageDown
#define Key_PgDn Key_PageDown
#define Key_Del Key_Delete
#define Key_Grave Key_Backtick
#define K_APP Key_PcApplication
#define K_SCRLK Key_ScrollLock
#define K_CPSLK Key_CapsLock
#define K_PAUSE Key_Pause
#define K_PRSCR Key_PrintScreen
#define K_MUTE Consumer_Mute
#define K_VUp Consumer_VolumeIncrement
#define K_VDn Consumer_VolumeDecrement
#define K_PST LCTRL(Key_V)
#define K_CPY LCTRL(Key_LeftControl)
#define K_CUT LCTRL(Key_X)
#define K_UDO LCTRL(Key_Z)
#define KP_0 Key_Keypad0
#define KP_1 Key_Keypad1
#define KP_2 Key_Keypad2
#define KP_3 Key_Keypad3
#define KP_4 Key_Keypad4
#define KP_5 Key_Keypad5
#define KP_6 Key_Keypad6
#define KP_7 Key_Keypad7
#define KP_8 Key_Keypad8
#define KP_9 Key_Keypad9
#define Key_Up Key_UpArrow
#define Key_Dn Key_DownArrow
#define Key_Left Key_LeftArrow
#define Key_Rgt Key_RightArrow
#define KP_SLS Key_KeypadDivide
#define KP_STR Key_KeypadMultiply
#define Key_Plus Key_KeypadAdd
// clang-format off
KEYMAPS(
/* QWERTY
* ,-------------------------. ,--------------------------.
* | Esc | Q | W | E | R | T | | Y | U | I | O | P | Bspc |
* |-----+---+---+---+---+---| |---+---+---+---+---+------|
* | Alt | A | S | D | F | G | | H | J | K | L | ; | Entr |
* |-----+---+---+---+---+---| |---+---+---+---+---+------|
* | Sft | Z | X | C | V | B | | N | M | , | . | / | Gui |
* `-------------+---+---+---' `-+---+---+----------------'
* |ORG|BLU| |SPC|CTR|
* `-------' `-------'
*/
[_QWERTY] = KEYMAP(
Key_Esc ,Key_Q ,Key_W ,Key_E ,Key_R ,Key_T ,Key_Y ,Key_U ,Key_I ,Key_O ,Key_P ,Key_Backspace
,Key_LeftAlt ,Key_A ,Key_S ,Key_D ,Key_F ,Key_G ,Key_H ,Key_J ,Key_K ,Key_L ,Key_Semicolon ,Key_Enter
,Key_LeftShift ,Key_Z ,Key_X ,Key_C ,Key_V ,Key_B ,Key_N ,Key_M ,Key_Comma ,Key_Period ,Key_Slash ,Key_LeftGui
,MO(_ORANGE) ,MO(_BLUE) ,Key_Space ,Key_LeftControl
),
/* Blue
* ,-----------------------------------------. ,----------------------------.
* | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | |
* |-----+------+------+------+-------+------| |------+---+---+---+---+-----|
* | Alt | Stop | Prev | Play | Next | Vol+ | | | | | [ | ] | ' |
* |-----+------+------+------+-------+------| |------+---+---+---+---+-----|
* | Sft | Undo | Cut | Copy | Paste | Vol- | | Mute | | | - | = | Gui |
* `----------------------+------+------+----' `-+---+---+------------------'
* | GRN | [] | |Del|CTR|
* `-------------' `-------'
*/
[_BLUE] = KEYMAP(
Key_Grave ,Key_1 ,Key_2 ,Key_3 ,Key_4 ,Key_5 ,Key_6 ,Key_7 ,Key_8 ,Key_9 ,Key_0 ,XXX
,Key_LeftAlt ,K_STP ,K_PRV ,K_PLY ,K_NXT ,K_VUp ,XXX ,XXX ,XXX ,Key_LeftBracket ,Key_RightBracket ,Key_Quote
,Key_LeftShift ,K_UDO ,K_CUT ,K_CPY ,K_PST ,K_VDn ,K_MUTE ,XXX ,XXX ,Key_Minus ,Key_Equals ,Key_LeftGui
,MO(_GREEN) ,___ ,Key_Del ,Key_LeftControl
),
/* Orange
* ,------------------------------------------. ,-----------------------------------------.
* | Plvr | F1 | F2 | F3 | F4 | | | App | PrScr | ScrLck | Pause | | |
* |------+------+------+------+-------+------| |------+-------+--------+-------+---+-----|
* | Alt | F5 | F6 | F7 | F8 | | | | Ins | Home | PgUp | | |
* |------+------+------+------+-------+------| |------+-------+--------+-------+---+-----|
* | Sft | F9 | F10 | F11 | F12 | | | | Del | End | PgDn | \ | Gui |
* `----------------------+------+------+-----' `-+---+---+-------------------------------'
* | [] | GRN | |Tab|CTR|
* `-------------' `-------'
*/
[_ORANGE] = KEYMAP(
TO(_PLOVER) ,Key_F1 ,Key_F2 ,Key_F3 ,Key_F4 ,XXX ,K_APP ,K_PRSCR ,K_SCRLK ,K_PAUSE ,XXX ,XXX
,Key_LeftAlt ,Key_F5 ,Key_F6 ,Key_F7 ,Key_F8 ,XXX ,XXX ,Key_Insert ,Key_Home ,Key_PageUp ,XXX ,XXX
,Key_LeftShift ,Key_F9 ,Key_F10 ,Key_F11 ,Key_F12 ,XXX ,XXX ,Key_Delete ,Key_End ,Key_PageDn ,Key_Backslash ,Key_LeftGui
,___ ,MO(_GREEN) ,Key_Tab ,Key_LeftControl
),
/* Green
* ,----------------------------------------. ,--------------------------.
* | STENO | | | | | ScrLk | | / | 7 | 8 | 9 | - | |
* |-------+------+----+-----+------+-------| |---+---+---+---+---+------|
* | Alt | Home | Up | End | PgUp | CpsLk | | * | 4 | 5 | 6 | + | Entr |
* |-------+------+----+-----+------+-------| |---+---+---+---+---+------|
* | Sft | Left | Dn | Rgt | PgDn | | | 0 | 1 | 2 | 3 | | Gui |
* `---------------------------+----+----+--' `-+---+---+----------------'
* | [] | [] | | |CTR|
* `---------' `-------'
*/
[_GREEN] = KEYMAP(
TO(_STENO) ,XXX ,XXX ,XXX ,XXX ,K_SCRLK ,KP_SLS ,KP_7 ,KP_8 ,KP_9 ,Key_Minus ,XXX
,Key_LeftAlt ,Key_Home ,Key_Up ,Key_End ,Key_PgUp ,K_CPSLK ,KP_STR ,KP_4 ,KP_5 ,KP_6 ,Key_Plus ,Key_Enter
,Key_LeftShift ,Key_Left ,Key_Dn ,Key_Rgt ,Key_PgDn ,XXX ,KP_0 ,KP_1 ,KP_2 ,KP_3 ,XXX ,Key_LeftGui
,___ ,___ ,XXX ,Key_LeftControl
),
/* Steno (GeminiPR)
* ,-----------------------. ,-----------------------.
* | # | # | # | # | # | # | | # | # | # | # | # | # |
* |---+---+---+---+---+---| |---+---+---+---+---+---|
* |QWR| S | T | P | H | * | | * | F | P | L | T | D |
* |---+---+---+---+---+---| |---+---+---+---+---+---|
* |QWR| S | K | W | R | * | | * | R | B | G | S | Z |
* `-------------+---+---+-' `-+---+---+-------------'
* | A | O | | E | U |
* `-------' `-------'
*/
[_STENO] = KEYMAP(
S(N1) ,S(N2) ,S(N3) ,S(N4) ,S(N5) ,S(N6) ,S(N7) ,S(N8) ,S(N9) ,S(NA) ,S(NB) ,S(NC)
,QWERTY1 ,S(S1) ,S(TL) ,S(PL) ,S(HL) ,S(ST1) ,S(ST3) ,S(FR) ,S(PR) ,S(LR) ,S(TR) ,S(DR)
,QWERTY2 ,S(S2) ,S(KL) ,S(WL) ,S(RL) ,S(ST2) ,S(ST4) ,S(RR) ,S(BR) ,S(GR) ,S(SR) ,S(ZR)
,S(A) ,S(O) ,S(E) ,S(U)
),
/* Steno (Keyboard, QWERTY)
* ,-----------------------. ,-----------------------.
* | 1 | 1 | 1 | 1 | 1 | 1 | | 1 | 1 | 1 | 1 | 1 | 1 |
* |---+---+---+---+---+---| |---+---+---+---+---+---|
* |QWR| S | T | P | H | * | | * | F | P | L | T | D |
* |---+---+---+---+---+---| |---+---+---+---+---+---|
* |QWR| S | K | W | R | * | | * | R | B | G | S | Z |
* `-------------+---+---+-' `-+---+---+-------------'
* | A | O | | E | U |
* `-------' `-------'
*/
[_PLOVER] = KEYMAP(
Key_1 ,Key_1 ,Key_1 ,Key_1 ,Key_1 ,Key_1 ,Key_1 ,Key_1 ,Key_1 ,Key_1 ,Key_1 ,Key_1
,QWERTY1 ,Key_Q ,Key_W ,Key_E ,Key_R ,Key_T ,Key_Y ,Key_U ,Key_I ,Key_O ,Key_P ,Key_LeftBracket
,QWERTY2 ,Key_A ,Key_S ,Key_D ,Key_F ,Key_G ,Key_H ,Key_J ,Key_K ,Key_L ,Key_Semicolon ,Key_Quote
,Key_C ,Key_V ,Key_N ,Key_M
)
);
// clang-format on
namespace kaleidoscope {
namespace plugin {
class MultiSwitcher : public kaleidoscope::Plugin {
public:
MultiSwitcher() {}
EventHandlerResult onKeyEvent(KeyEvent &event) {
if (event.key < QWERTY_1 || event.key > QWERTY_2)
return EventHandlerResult::OK;
uint8_t bit = event.key.getRaw() - QWERTY_1;
if (keyToggledOn(event.state)) {
switch_state_ |= (1 << bit);
if (switch_state_ == (1 << 0 | 1 << 1)) {
Layer.move(_QWERTY);
}
} else {
switch_state_ &= ~(1 << bit);
}
return EventHandlerResult::EVENT_CONSUMED;
}
private:
uint8_t switch_state_ = 0;
};
} // namespace plugin
} // namespace kaleidoscope
kaleidoscope::plugin::MultiSwitcher MultiSwitcher;
#include "Kaleidoscope-MouseKeys.h"
#include "Kaleidoscope-Qukeys.h"
#include "Kaleidoscope-OneShot.h"
#include "Kaleidoscope-Escape-OneShot.h"
#include "Kaleidoscope-DynamicMacros.h"
KALEIDOSCOPE_INIT_PLUGINS(
GeminiPR,
MultiSwitcher,
Focus,
EEPROMSettings,
EEPROMKeymap,
FocusEEPROMCommand,
FocusSettingsCommand,
MouseKeys,
Qukeys,
OneShot,
EscapeOneShot,
EscapeOneShotConfig,
DynamicMacros);
void setup() {
Kaleidoscope.setup();
EEPROMKeymap.setup(8);
DynamicMacros.reserve_storage(256);
}
void loop() {
Kaleidoscope.loop();
}

@ -53,7 +53,7 @@ struct SplitographyProps : kaleidoscope::device::ATmega32U4KeyboardProps {
#endif // KALEIDOSCOPE_VIRTUAL_BUILD #endif // KALEIDOSCOPE_VIRTUAL_BUILD
}; };
typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner; typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner;
typedef kaleidoscope::driver::bootloader::avr::FLIP Bootloader; typedef kaleidoscope::driver::bootloader::avr::FLIP BootLoader;
static constexpr const char *short_name = "splitography"; static constexpr const char *short_name = "splitography";
}; };

@ -1,6 +1,6 @@
/* -*- mode: c++ -*- /* -*- mode: c++ -*-
* Atreus -- A very basic Kaleidoscope example for the Atreus * Atreus -- Chrysalis-enabled Sketch for Technomancy's Atreus
* Copyright (C) 2018 Keyboard.io, Inc * Copyright (C) 2018-2022 Keyboard.io, Inc
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,15 +18,22 @@
*/ */
#include "Kaleidoscope.h" #include "Kaleidoscope.h"
#include "Kaleidoscope-EEPROM-Settings.h"
#include "Kaleidoscope-EEPROM-Keymap.h"
#include "Kaleidoscope-FocusSerial.h"
#include "Kaleidoscope-Macros.h" #include "Kaleidoscope-Macros.h"
#include "Kaleidoscope-MouseKeys.h"
#include "Kaleidoscope-OneShot.h"
#include "Kaleidoscope-Escape-OneShot.h"
#include "Kaleidoscope-DynamicMacros.h"
#include "Kaleidoscope-Qukeys.h"
#define MO(n) ShiftToLayer(n) #define MO(n) ShiftToLayer(n)
#define TG(n) LockLayer(n) #define TG(n) LockLayer(n)
enum { enum {
QWERTY, RESET,
FUN, QW
UPPER
}; };
#define Key_Exclamation LSHIFT(Key_1) #define Key_Exclamation LSHIFT(Key_1)
@ -37,9 +44,15 @@ enum {
#define Key_Star LSHIFT(Key_8) #define Key_Star LSHIFT(Key_8)
#define Key_Plus LSHIFT(Key_Equals) #define Key_Plus LSHIFT(Key_Equals)
enum {
_QW,
_RS,
_LW
};
// clang-format off // clang-format off
KEYMAPS( KEYMAPS(
[QWERTY] = KEYMAP_STACKED [_QW] = KEYMAP_STACKED
( (
Key_Q ,Key_W ,Key_E ,Key_R ,Key_T Key_Q ,Key_W ,Key_E ,Key_R ,Key_T
,Key_A ,Key_S ,Key_D ,Key_F ,Key_G ,Key_A ,Key_S ,Key_D ,Key_F ,Key_G
@ -49,44 +62,58 @@ KEYMAPS(
,Key_Y ,Key_U ,Key_I ,Key_O ,Key_P ,Key_Y ,Key_U ,Key_I ,Key_O ,Key_P
,Key_H ,Key_J ,Key_K ,Key_L ,Key_Semicolon ,Key_H ,Key_J ,Key_K ,Key_L ,Key_Semicolon
,Key_N ,Key_M ,Key_Comma ,Key_Period ,Key_Slash ,Key_N ,Key_M ,Key_Comma ,Key_Period ,Key_Slash
,Key_LeftAlt ,Key_Space ,MO(FUN) ,Key_Minus ,Key_Quote ,Key_Enter ,Key_LeftAlt ,Key_Space ,MO(_RS) ,Key_Minus ,Key_Quote ,Key_Enter
), ),
[FUN] = KEYMAP_STACKED [_RS] = KEYMAP_STACKED
( (
Key_Exclamation ,Key_At ,Key_UpArrow ,Key_LeftCurlyBracket ,Key_RightCurlyBracket Key_Exclamation ,Key_At ,Key_UpArrow ,Key_LeftCurlyBracket ,Key_RightCurlyBracket
,Key_Hash ,Key_LeftArrow ,Key_DownArrow ,Key_RightArrow ,Key_Dollar ,Key_Hash ,Key_LeftArrow ,Key_DownArrow ,Key_RightArrow ,Key_Dollar
,Key_LeftBracket ,Key_RightBracket ,Key_LeftParen ,Key_RightParen ,Key_And ,Key_LeftBracket ,Key_RightBracket ,Key_LeftParen ,Key_RightParen ,Key_And
,TG(UPPER) ,Key_Insert ,Key_LeftGui ,Key_LeftShift ,Key_Backspace ,Key_LeftControl ,TG(_LW) ,Key_Insert ,Key_LeftGui ,Key_LeftShift ,Key_Backspace ,Key_LeftControl
,Key_PageUp ,Key_7 ,Key_8 ,Key_9 ,Key_Star ,Key_PageUp ,Key_7 ,Key_8 ,Key_9 ,Key_Star
,Key_PageDown ,Key_4 ,Key_5 ,Key_6 ,Key_Plus ,Key_PageDown ,Key_4 ,Key_5 ,Key_6 ,Key_Plus
,Key_Backtick ,Key_1 ,Key_2 ,Key_3 ,Key_Backslash ,Key_Backtick ,Key_1 ,Key_2 ,Key_3 ,Key_Backslash
,Key_LeftAlt ,Key_Space ,MO(FUN) ,Key_Period ,Key_0 ,Key_Equals ,Key_LeftAlt ,Key_Space ,___ ,Key_Period ,Key_0 ,Key_Equals
), ),
[UPPER] = KEYMAP_STACKED [_LW] = KEYMAP_STACKED
( (
Key_Insert ,Key_Home ,Key_UpArrow ,Key_End ,Key_PageUp Key_Insert ,Key_Home ,Key_UpArrow ,Key_End ,Key_PageUp
,Key_Delete ,Key_LeftArrow ,Key_DownArrow ,Key_RightArrow ,Key_PageDown ,Key_Delete ,Key_LeftArrow ,Key_DownArrow ,Key_RightArrow ,Key_PageDown
,XXX ,Consumer_VolumeIncrement ,XXX ,XXX ,___ ,XXX ,Consumer_VolumeIncrement ,XXX ,XXX ,M(RESET)
,XXX ,Consumer_VolumeDecrement ,___ ,___ ,___ ,___ ,XXX ,Consumer_VolumeDecrement ,___ ,___ ,___ ,___
,Key_UpArrow ,Key_F7 ,Key_F8 ,Key_F9 ,Key_F10 ,Key_UpArrow ,Key_F7 ,Key_F8 ,Key_F9 ,Key_F10
,Key_DownArrow ,Key_F4 ,Key_F5 ,Key_F6 ,Key_F11 ,Key_DownArrow ,Key_F4 ,Key_F5 ,Key_F6 ,Key_F11
,XXX ,Key_F1 ,Key_F2 ,Key_F3 ,Key_F12 ,XXX ,Key_F1 ,Key_F2 ,Key_F3 ,Key_F12
,___ ,___ ,M(QWERTY),Key_PrintScreen ,Key_ScrollLock ,Consumer_PlaySlashPause ,___ ,___ ,M(QW) ,Key_PrintScreen ,Key_ScrollLock ,Consumer_PlaySlashPause
) )
) )
// clang-format on // clang-format on
KALEIDOSCOPE_INIT_PLUGINS(Macros); KALEIDOSCOPE_INIT_PLUGINS(
EEPROMSettings,
EEPROMKeymap,
Focus,
FocusEEPROMCommand,
FocusSettingsCommand,
Qukeys,
OneShot,
EscapeOneShot,
EscapeOneShotConfig,
Macros,
DynamicMacros,
MouseKeys);
const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) { const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
switch (macro_id) { switch (macro_id) {
case QWERTY: case RESET:
if (keyToggledOn(event.state)) Kaleidoscope.rebootBootloader();
Layer.move(QWERTY); break;
case QW:
Layer.move(_QW);
break; break;
default: default:
break; break;
@ -97,6 +124,9 @@ const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
void setup() { void setup() {
Kaleidoscope.setup(); Kaleidoscope.setup();
EEPROMKeymap.setup(7);
DynamicMacros.reserve_storage(256);
} }
void loop() { void loop() {

@ -1,8 +1,6 @@
# This makefile for a Kaleidoscope sketch pulls in all the targets # This makefile for a Kaleidoscope sketch pulls in all the targets
# required to build the example # required to build the example
# Compile without deprecated code to save space
LOCAL_CFLAGS ?= -DNDEPRECATED -DONESHOT_WITHOUT_METASTICKY

@ -67,9 +67,9 @@ struct AtreusProps : kaleidoscope::device::ATmega32U4KeyboardProps {
typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner; typedef kaleidoscope::driver::keyscanner::ATmega<KeyScannerProps> KeyScanner;
#ifdef KALEIDOSCOPE_HARDWARE_ATREUS_PINOUT_LEGACY_TEENSY2 #ifdef KALEIDOSCOPE_HARDWARE_ATREUS_PINOUT_LEGACY_TEENSY2
typedef kaleidoscope::driver::bootloader::avr::HalfKay Bootloader; typedef kaleidoscope::driver::bootloader::avr::HalfKay BootLoader;
#else #else
typedef kaleidoscope::driver::bootloader::avr::Caterina Bootloader; typedef kaleidoscope::driver::bootloader::avr::Caterina BootLoader;
#endif #endif
static constexpr const char *short_name = "atreus"; static constexpr const char *short_name = "atreus";
}; };

@ -41,13 +41,13 @@ uint8_t Heatmap::heat_colors_length = 4;
// number of millisecond to wait between each heatmap computation // number of millisecond to wait between each heatmap computation
uint16_t Heatmap::update_delay = 1000; uint16_t Heatmap::update_delay = 1000;
uint16_t Heatmap::highest_ = 1;
uint16_t Heatmap::heatmap_[];
Heatmap::TransientLEDMode::TransientLEDMode(const Heatmap *parent) Heatmap::TransientLEDMode::TransientLEDMode(const Heatmap *parent)
: // last heatmap computation time : // store the number of times each key has been strock
last_heatmap_comp_time_(Runtime.millisAtCycleStart()), heatmap_{},
parent_(parent) {} // max of heatmap_ (we divide by it so we start at 1)
highest_(1),
// last heatmap computation time
last_heatmap_comp_time_(Runtime.millisAtCycleStart()) {}
cRGB Heatmap::TransientLEDMode::computeColor(float v) { cRGB Heatmap::TransientLEDMode::computeColor(float v) {
// compute the color corresponding to a value between 0 and 1 // compute the color corresponding to a value between 0 and 1
@ -114,11 +114,11 @@ void Heatmap::TransientLEDMode::shiftStats() {
// we divide every heatmap element by 2 // we divide every heatmap element by 2
for (auto key_addr : KeyAddr::all()) { for (auto key_addr : KeyAddr::all()) {
parent_->heatmap_[key_addr.toInt()] = parent_->heatmap_[key_addr.toInt()] >> 1; heatmap_[key_addr.toInt()] = heatmap_[key_addr.toInt()] >> 1;
} }
// and also divide highest_ accordingly // and also divide highest_ accordingly
parent_->highest_ = parent_->highest_ >> 1; highest_ = highest_ >> 1;
} }
void Heatmap::resetMap() { void Heatmap::resetMap() {
@ -134,10 +134,10 @@ void Heatmap::TransientLEDMode::resetMap() {
// this method can be used as a way to work around an existing bug with a single key // this method can be used as a way to work around an existing bug with a single key
// getting special attention or if the user just wants a button to reset the map // getting special attention or if the user just wants a button to reset the map
for (auto key_addr : KeyAddr::all()) { for (auto key_addr : KeyAddr::all()) {
parent_->heatmap_[key_addr.toInt()] = 0; heatmap_[key_addr.toInt()] = 0;
} }
parent_->highest_ = 1; highest_ = 1;
} }
// It may be better to use `onKeyswitchEvent()` here // It may be better to use `onKeyswitchEvent()` here
@ -167,17 +167,17 @@ EventHandlerResult Heatmap::onKeyEvent(KeyEvent &event) {
EventHandlerResult Heatmap::TransientLEDMode::onKeyEvent(KeyEvent &event) { EventHandlerResult Heatmap::TransientLEDMode::onKeyEvent(KeyEvent &event) {
// increment the heatmap_ value related to the key // increment the heatmap_ value related to the key
parent_->heatmap_[event.addr.toInt()]++; heatmap_[event.addr.toInt()]++;
// check highest_ // check highest_
if (parent_->highest_ < parent_->heatmap_[event.addr.toInt()]) { if (highest_ < heatmap_[event.addr.toInt()]) {
parent_->highest_ = parent_->heatmap_[event.addr.toInt()]; highest_ = heatmap_[event.addr.toInt()];
// if highest_ (and so heatmap_ value related to the key) // if highest_ (and so heatmap_ value related to the key)
// is close to overflow: call shiftStats // is close to overflow: call shiftStats
// NOTE: this is barely impossible since shiftStats should be // NOTE: this is barely impossible since shiftStats should be
// called much sooner by Heatmap::loopHook // called much sooner by Heatmap::loopHook
if (parent_->highest_ == INT16_MAX) if (highest_ == INT16_MAX)
shiftStats(); shiftStats();
} }
@ -204,7 +204,7 @@ EventHandlerResult Heatmap::TransientLEDMode::beforeEachCycle() {
// didn't lose any precision in our heatmap since between each color we have a // didn't lose any precision in our heatmap since between each color we have a
// maximum precision of 256 ; said differently, there is 256 state (at max) // maximum precision of 256 ; said differently, there is 256 state (at max)
// between heat_colors[x] and heat_colors[x+1]. // between heat_colors[x] and heat_colors[x+1].
if (parent_->highest_ > (static_cast<uint16_t>(heat_colors_length) << 9)) if (highest_ > (static_cast<uint16_t>(heat_colors_length) << 9))
shiftStats(); shiftStats();
return EventHandlerResult::OK; return EventHandlerResult::OK;
@ -229,7 +229,7 @@ void Heatmap::TransientLEDMode::update() {
for (auto key_addr : KeyAddr::all()) { for (auto key_addr : KeyAddr::all()) {
// how much the key was pressed compared to the others (between 0 and 1) // how much the key was pressed compared to the others (between 0 and 1)
// (total_keys_ can't be equal to 0) // (total_keys_ can't be equal to 0)
float v = static_cast<float>(parent_->heatmap_[key_addr.toInt()]) / parent_->highest_; float v = static_cast<float>(heatmap_[key_addr.toInt()]) / highest_;
// we could have used an interger instead of a float, but then we would // we could have used an interger instead of a float, but then we would
// have had to change some multiplication in division. // have had to change some multiplication in division.
// / on uint is slower than * on float, so I stay with the float // / on uint is slower than * on float, so I stay with the float

@ -37,7 +37,6 @@ class Heatmap : public Plugin,
static uint16_t update_delay; static uint16_t update_delay;
static const cRGB *heat_colors; static const cRGB *heat_colors;
static uint8_t heat_colors_length; static uint8_t heat_colors_length;
void resetMap(); void resetMap();
EventHandlerResult onKeyEvent(KeyEvent &event); EventHandlerResult onKeyEvent(KeyEvent &event);
@ -61,18 +60,15 @@ class Heatmap : public Plugin,
void update() final; void update() final;
private: private:
uint16_t heatmap_[Runtime.device().numKeys()];
uint16_t highest_;
uint16_t last_heatmap_comp_time_; uint16_t last_heatmap_comp_time_;
const Heatmap *parent_;
void shiftStats(); void shiftStats();
cRGB computeColor(float v); cRGB computeColor(float v);
friend class Heatmap; friend class Heatmap;
}; };
private:
static uint16_t heatmap_[Runtime.device().numKeys()];
static uint16_t highest_;
}; };
} // namespace plugin } // namespace plugin

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/HostOS-Focus.h" #include "kaleidoscope/plugin/HostOS-Focus.h"
#include <Arduino.h> // for PSTR #include <Arduino.h> // for PSTR, strcmp_P
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint8_t #include <stdint.h> // for uint8_t
@ -27,13 +27,12 @@
namespace kaleidoscope { namespace kaleidoscope {
namespace plugin { namespace plugin {
EventHandlerResult FocusHostOSCommand::onFocusEvent(const char *input) { EventHandlerResult FocusHostOSCommand::onFocusEvent(const char *command) {
const char *cmd = PSTR("hostos.type"); const char *cmd = PSTR("hostos.type");
if (::Focus.inputMatchesHelp(input)) if (::Focus.handleHelp(command, cmd))
return ::Focus.printHelp(cmd); return EventHandlerResult::OK;
if (strcmp_P(command, cmd) != 0)
if (!::Focus.inputMatchesCommand(input, cmd))
return EventHandlerResult::OK; return EventHandlerResult::OK;
if (::Focus.isEOL()) { if (::Focus.isEOL()) {

@ -25,7 +25,7 @@ namespace plugin {
class FocusHostOSCommand : public kaleidoscope::Plugin { class FocusHostOSCommand : public kaleidoscope::Plugin {
public: public:
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
}; };
} // namespace plugin } // namespace plugin

@ -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()) {
#ifdef __AVR__
if ((_usbSuspendState & (1 << SUSPI))) {
if (!initial_suspend_) {
if (!was_suspended_) { if (!was_suspended_) {
was_suspended_ = true; was_suspended_ = true;
hostPowerManagementEventHandler(Suspend); hostPowerManagementEventHandler(Suspend);
} else { } else {
hostPowerManagementEventHandler(Sleep); 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

@ -18,7 +18,7 @@
#include "kaleidoscope/plugin/IdleLEDs.h" #include "kaleidoscope/plugin/IdleLEDs.h"
#include <Arduino.h> // for F, PSTR, __FlashStringHelper #include <Arduino.h> // for F, PSTR, __FlashStringHelper, strcmp_P
#include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings #include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint32_t, uint16_t #include <stdint.h> // for uint32_t, uint16_t
@ -97,13 +97,13 @@ void PersistentIdleLEDs::setIdleTimeoutSeconds(uint32_t new_limit) {
Runtime.storage().commit(); Runtime.storage().commit();
} }
EventHandlerResult PersistentIdleLEDs::onFocusEvent(const char *input) { EventHandlerResult PersistentIdleLEDs::onFocusEvent(const char *command) {
const char *cmd = PSTR("idleleds.time_limit"); const char *cmd = PSTR("idleleds.time_limit");
if (::Focus.inputMatchesHelp(input)) if (::Focus.handleHelp(command, cmd))
return ::Focus.printHelp(cmd); return EventHandlerResult::OK;
if (!::Focus.inputMatchesCommand(input, cmd)) if (strcmp_P(command, cmd) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
if (::Focus.isEOL()) { if (::Focus.isEOL()) {

@ -46,7 +46,7 @@ class PersistentIdleLEDs : public IdleLEDs {
public: public:
EventHandlerResult onSetup(); EventHandlerResult onSetup();
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
static void setIdleTimeoutSeconds(uint32_t new_limit); static void setIdleTimeoutSeconds(uint32_t new_limit);

@ -24,7 +24,7 @@ class TestLEDMode : public LEDMode {
void setup() final; void setup() final;
void update() final; void update() final;
kaleidoscope::EventHandlerResult onFocusEvent(const char *input); kaleidoscope::EventHandlerResult onFocusEvent(const char *command);
private: private:
static uint16_t map_base_; static uint16_t map_base_;
@ -41,8 +41,8 @@ void TestLEDMode::update() {
} }
kaleidoscope::EventHandlerResult kaleidoscope::EventHandlerResult
TestLEDMode::onFocusEvent(const char *input) { TestLEDMode::onFocusEvent(const char *command) {
return LEDPaletteTheme.themeFocusEvent(input, PSTR("testLedMode.map"), map_base_, 1); return LEDPaletteTheme.themeFocusEvent(command, PSTR("testLedMode.map"), map_base_, 1);
} }
} }

@ -17,7 +17,7 @@
#include "kaleidoscope/plugin/LED-Palette-Theme.h" #include "kaleidoscope/plugin/LED-Palette-Theme.h"
#include <Arduino.h> // for PSTR #include <Arduino.h> // for strcmp_P, PSTR
#include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings #include <Kaleidoscope-EEPROM-Settings.h> // for EEPROMSettings
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint8_t, uint16_t #include <stdint.h> // for uint8_t, uint16_t
@ -122,16 +122,16 @@ bool LEDPaletteTheme::isThemeUninitialized(uint16_t theme_base, uint8_t max_them
return paletteEmpty && themeEmpty; return paletteEmpty && themeEmpty;
} }
EventHandlerResult LEDPaletteTheme::onFocusEvent(const char *input) { EventHandlerResult LEDPaletteTheme::onFocusEvent(const char *command) {
if (!Runtime.has_leds) if (!Runtime.has_leds)
return EventHandlerResult::OK; return EventHandlerResult::OK;
const char *cmd = PSTR("palette"); const char *cmd = PSTR("palette");
if (::Focus.inputMatchesHelp(input)) if (::Focus.handleHelp(command, cmd))
return ::Focus.printHelp(cmd); return EventHandlerResult::OK;
if (!::Focus.inputMatchesCommand(input, cmd)) if (strcmp_P(command, cmd) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
if (::Focus.isEOL()) { if (::Focus.isEOL()) {
@ -159,17 +159,17 @@ EventHandlerResult LEDPaletteTheme::onFocusEvent(const char *input) {
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
} }
EventHandlerResult LEDPaletteTheme::themeFocusEvent(const char *input, EventHandlerResult LEDPaletteTheme::themeFocusEvent(const char *command,
const char *expected_input, const char *expected_command,
uint16_t theme_base, uint16_t theme_base,
uint8_t max_themes) { uint8_t max_themes) {
if (!Runtime.has_leds) if (!Runtime.has_leds)
return EventHandlerResult::OK; return EventHandlerResult::OK;
if (::Focus.inputMatchesHelp(input)) if (::Focus.handleHelp(command, expected_command))
return ::Focus.printHelp(expected_input); return EventHandlerResult::OK;
if (!::Focus.inputMatchesCommand(input, expected_input)) if (strcmp_P(command, expected_command) != 0)
return EventHandlerResult::OK; return EventHandlerResult::OK;
uint16_t max_index = (max_themes * Runtime.device().led_count) / 2; uint16_t max_index = (max_themes * Runtime.device().led_count) / 2;

@ -40,9 +40,9 @@ class LEDPaletteTheme : public kaleidoscope::Plugin {
static void updatePaletteColor(uint8_t palette_index, cRGB color); static void updatePaletteColor(uint8_t palette_index, cRGB color);
static const cRGB lookupPaletteColor(uint8_t palette_index); static const cRGB lookupPaletteColor(uint8_t palette_index);
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
EventHandlerResult themeFocusEvent(const char *input, EventHandlerResult themeFocusEvent(const char *command,
const char *expected_input, const char *expected_command,
uint16_t theme_base, uint16_t theme_base,
uint8_t max_themes); uint8_t max_themes);
static bool isThemeUninitialized(uint16_t theme_base, uint8_t max_themes); static bool isThemeUninitialized(uint16_t theme_base, uint8_t max_themes);

@ -18,7 +18,7 @@
#include "kaleidoscope/plugin/LayerFocus.h" #include "kaleidoscope/plugin/LayerFocus.h"
#include <Arduino.h> // for PSTR, F, __FlashStringHelper #include <Arduino.h> // for PSTR, strcmp_P, F, __FlashStringHelper
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial #include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint8_t #include <stdint.h> // for uint8_t
@ -32,45 +32,39 @@ EventHandlerResult LayerFocus::onNameQuery() {
return ::Focus.sendName(F("LayerFocus")); return ::Focus.sendName(F("LayerFocus"));
} }
EventHandlerResult LayerFocus::onFocusEvent(const char *input) { EventHandlerResult LayerFocus::onFocusEvent(const char *command) {
const char *cmd_activate = PSTR("layer.activate"); if (::Focus.handleHelp(command, PSTR("layer.activate\nlayer.deactivate\nlayer.isActive"
const char *cmd_deactivate = PSTR("layer.deactivate"); "\nlayer.moveTo\nlayer.state")))
const char *cmd_isActive = PSTR("layer.isActive"); return EventHandlerResult::OK;
const char *cmd_moveTo = PSTR("layer.moveTo");
const char *cmd_state = PSTR("layer.state");
if (::Focus.inputMatchesHelp(input)) if (strncmp_P(command, PSTR("layer."), 6) != 0)
return ::Focus.printHelp(cmd_activate, return EventHandlerResult::OK;
cmd_deactivate,
cmd_isActive,
cmd_moveTo,
cmd_state);
if (::Focus.inputMatchesCommand(input, cmd_activate)) { if (strcmp_P(command + 6, PSTR("activate")) == 0) {
if (!::Focus.isEOL()) { if (!::Focus.isEOL()) {
uint8_t layer; uint8_t layer;
::Focus.read(layer); ::Focus.read(layer);
::Layer.activate(layer); ::Layer.activate(layer);
} }
} else if (::Focus.inputMatchesCommand(input, cmd_deactivate)) { } else if (strcmp_P(command + 6, PSTR("deactivate")) == 0) {
if (!::Focus.isEOL()) { if (!::Focus.isEOL()) {
uint8_t layer; uint8_t layer;
::Focus.read(layer); ::Focus.read(layer);
::Layer.deactivate(layer); ::Layer.deactivate(layer);
} }
} else if (::Focus.inputMatchesCommand(input, cmd_isActive)) { } else if (strcmp_P(command + 6, PSTR("isActive")) == 0) {
if (!::Focus.isEOL()) { if (!::Focus.isEOL()) {
uint8_t layer; uint8_t layer;
::Focus.read(layer); ::Focus.read(layer);
::Focus.send(::Layer.isActive(layer)); ::Focus.send(::Layer.isActive(layer));
} }
} else if (::Focus.inputMatchesCommand(input, cmd_moveTo)) { } else if (strcmp_P(command + 6, PSTR("moveTo")) == 0) {
if (!::Focus.isEOL()) { if (!::Focus.isEOL()) {
uint8_t layer; uint8_t layer;
::Focus.read(layer); ::Focus.read(layer);
::Layer.move(layer); ::Layer.move(layer);
} }
} else if (::Focus.inputMatchesCommand(input, cmd_state)) { } else if (strcmp_P(command + 6, PSTR("state")) == 0) {
if (::Focus.isEOL()) { if (::Focus.isEOL()) {
for (uint8_t i = 0; i < 32; i++) { for (uint8_t i = 0; i < 32; i++) {
::Focus.send(::Layer.isActive(i) ? 1 : 0); ::Focus.send(::Layer.isActive(i) ? 1 : 0);
@ -86,8 +80,6 @@ EventHandlerResult LayerFocus::onFocusEvent(const char *input) {
::Layer.activate(i); ::Layer.activate(i);
} }
} }
} else {
return EventHandlerResult::OK;
} }
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;

@ -27,7 +27,7 @@ namespace plugin {
class LayerFocus : public kaleidoscope::Plugin { class LayerFocus : public kaleidoscope::Plugin {
public: public:
EventHandlerResult onNameQuery(); EventHandlerResult onNameQuery();
EventHandlerResult onFocusEvent(const char *input); EventHandlerResult onFocusEvent(const char *command);
}; };
} // namespace plugin } // namespace plugin

@ -1,75 +0,0 @@
# LayerNames
This plugin provides a [Focus][plugin:focus]-based interface for storing custom
layer names, to be used by software such as [Chrysalis][chrysalis]. The firmware
itself does nothing with the layer names, it is purely for use by applications
on the host side.
[chrysalis]: https://github.com/keyboardio/Chrysalis
## Using the plugin
To use the plugin, we need to include the header, initialize the plugin with
`KALEIDOSCOPE_INIT_PLUGINS()`, and reserve storage space for the names. This is
best illustrated with an example:
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-EEPROMSettings.h>
#include <Kaleidoscope-FocusSerial.h>
#include <Kaleidoscope-LayerNames.h>
KALEIDOSCOPE_INIT_PLUGINS(
EEPROMSettings,
Focus,
LayerNames
);
void setup() {
Kaleidoscope.setup();
LayerNames.reserve_storage(128);
}
```
## Plugin methods
The plugin provides a `LayerNames` object, with the following method available:
### `.reserve_storage(size)`
> Reserves `size` bytes of storage for layer names. This must be called from the
> `setup()` method of your sketch.
## Focus commands
The plugin provides a single Focus command: `keymap.layerNames`.
### `keymap.layerNames [name_length name]...`
> Without arguments, displays all the stored layer names. Each layer is printed
> on its own line, preceded by its length. At the end, the plugin will also
> print an extra line with a name length of zero, followed by the string
> "size=", and then the total size of the storage reserved for layer names.
>
> To set custom names, a list of length & name pairs must be given. The plugin
> stops processing arguments when it encounters a name length of 0.
#### Example
```
> keymap.layerNames
< 6 Qwerty
< 6 Numpad
< 8 Function
< 0 size=128
< .
> keymap.layerNames 6 Dvorak 6 Numpad 8 Function 0
< .
```
## Dependencies
* [Kaleidoscope-EEPROM-Settings](Kaleidoscope-EEPROM-Settings.md)
* [Kaleidoscope-FocusSerial](Kaleidoscope-FocusSerial.md)

@ -1,7 +0,0 @@
name=Kaleidoscope-LayerNames
version=0.0.0
sentence=Kaleidoscope plugin that lets one set custom layer names
maintainer=Kaleidoscope's Developers <jesse@keyboard.io>
url=https://github.com/keyboardio/Kaleidoscope
author=Keyboardio
paragraph=

@ -1,19 +0,0 @@
/* Kaleidoscope - Firmware for computer input devices
* 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/>.
*/
#pragma once
#include "kaleidoscope/plugin/LayerNames.h" // IWYU pragma: export

@ -1,98 +0,0 @@
/* Kaleidoscope - Firmware for computer input devices
* 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/LayerNames.h"
#include <Arduino.h> // for delay, PSTR, F, __FlashStri...
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include "kaleidoscope/Runtime.h" // for Runtime, Runtime_
#include "kaleidoscope/plugin/EEPROM-Settings.h" // for EEPROMSettings
namespace kaleidoscope {
namespace plugin {
// =============================================================================
EventHandlerResult LayerNames::onNameQuery() {
return ::Focus.sendName(F("LayerNames"));
}
EventHandlerResult LayerNames::onFocusEvent(const char *input) {
const char *cmd_layerNames = PSTR("keymap.layerNames");
if (::Focus.inputMatchesHelp(input))
return ::Focus.printHelp(cmd_layerNames);
if (!::Focus.inputMatchesCommand(input, cmd_layerNames))
return EventHandlerResult::OK;
if (::Focus.isEOL()) {
uint16_t pos = 0;
while (pos < storage_size_) {
uint8_t name_size = Runtime.storage().read(storage_base_ + pos++);
if (name_size == 0 || name_size == 255) break;
::Focus.send(name_size);
for (uint8_t i = 0; i < name_size; i++) {
uint8_t b = Runtime.storage().read(storage_base_ + pos++);
::Focus.sendRaw(static_cast<char>(b));
}
::Focus.sendRaw(::Focus.NEWLINE);
}
::Focus.sendRaw(0, ::Focus.SEPARATOR, F("size="), storage_size_);
} else {
uint16_t pos = 0;
while (pos < storage_size_) {
uint8_t name_size;
::Focus.read(name_size);
// size is followed by a space, ignore that.
char spc;
::Focus.read(spc);
Runtime.storage().update(storage_base_ + pos++, name_size);
if (name_size == 0 ||
name_size == ::EEPROMSettings.EEPROM_UNINITIALIZED_BYTE)
break;
for (uint8_t i = 0; i < name_size; i++) {
char c;
::Focus.read(c);
Runtime.storage().update(storage_base_ + pos++, c);
}
}
Runtime.storage().commit();
}
return EventHandlerResult::EVENT_CONSUMED;
}
// public
void LayerNames::reserve_storage(uint16_t size) {
storage_base_ = ::EEPROMSettings.requestSlice(size);
storage_size_ = size;
}
} // namespace plugin
} // namespace kaleidoscope
kaleidoscope::plugin::LayerNames LayerNames;

@ -1,42 +0,0 @@
/* Kaleidoscope - Firmware for computer input devices
* 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/>.
*/
#pragma once
#include <stdint.h> // for uint16_t, uint8_t
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult
#include "kaleidoscope/plugin.h" // for Plugin
namespace kaleidoscope {
namespace plugin {
class LayerNames : public kaleidoscope::Plugin {
public:
EventHandlerResult onNameQuery();
EventHandlerResult onFocusEvent(const char *input);
void reserve_storage(uint16_t size);
private:
uint16_t storage_base_;
uint16_t storage_size_;
};
} // namespace plugin
} // namespace kaleidoscope
extern kaleidoscope::plugin::LayerNames LayerNames;

@ -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
@ -175,12 +181,12 @@ mapping is shown below on the left side of a keyboard with a QWERTY layout:
---|---|--- W - Warp NW Sector (Key_mouseWarpNW) ---|---|--- W - Warp NW Sector (Key_mouseWarpNW)
A S | D | F G E - Warp N Sector (Key_mouseWarpN) A S | D | F G E - Warp N Sector (Key_mouseWarpN)
---|---|--- R - Warp NE Sector (Key_mouseWarpNE) ---|---|--- R - Warp NE Sector (Key_mouseWarpNE)
X | C | V B S - Warp W Sector (Key_mouseWarpW) X | C | V B S - Warp E Sector (Key_mouseWarpE)
D - Warp/Zoom Center (Key_mouseWarpIn) D - Warp/Zoom Center (Key_mouseWarpIn)
F - Warp E Sector (Key_mouseWarpE) F - Warp W Sector (Key_mouseWarpW)
X - Warp SW Sector (Key_mouseWarpSW) K - Warp SE Sector (Key_mouseWarpSE)
C - Warp S Sector (Key_mouseWarpS) C - Warp S Sector (Key_mouseWarpS)
V - Warp SE Sector (Key_mouseWarpSE) V - Warp SW Sector (Key_mouseWarpSW)
T - Right Click (Key_mouseBtnR) T - Right Click (Key_mouseBtnR)
G - Left Click (Key_mouseBtnL) G - Left Click (Key_mouseBtnL)
B - Middle Click (Key_mouseBtnM) B - Middle Click (Key_mouseBtnM)
@ -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;
}
} else if (isMouseWarpKey(event.key)) {
if (keyToggledOn(event.state)) { if (keyToggledOn(event.state)) {
if (isMouseWarpKey(event.key)) {
// 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
// order to get consistent behavior.
accel_start_time_ = Runtime.millisAtCycleStart();
sendMouseMoveReport(); sendMouseMoveReport();
last_cursor_update_time_ = Runtime.millisAtCycleStart();
} else if (isMouseWheelKey(event.key)) { } else if (isMouseWheelKey(event.key)) {
sendMouseWheelReport(); sendMouseWheelReport();
last_wheel_update_time_ = Runtime.millisAtCycleStart();
}
} }
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,36 +44,17 @@ 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;
@ -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;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save