diff --git a/examples/Devices/Keyboardio/Atreus/Atreus.ino b/examples/Devices/Keyboardio/Atreus/Atreus.ino index 9215fa20..52f3e4ad 100644 --- a/examples/Devices/Keyboardio/Atreus/Atreus.ino +++ b/examples/Devices/Keyboardio/Atreus/Atreus.ino @@ -1,6 +1,6 @@ /* -*- mode: c++ -*- * Atreus -- Chrysalis-enabled Sketch for the Keyboardio Atreus - * Copyright (C) 2018, 2019 Keyboard.io, Inc + * 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 @@ -24,13 +24,16 @@ #include "Kaleidoscope.h" #include "Kaleidoscope-EEPROM-Settings.h" #include "Kaleidoscope-EEPROM-Keymap.h" +#include "Kaleidoscope-Escape-OneShot.h" +#include "Kaleidoscope-FirmwareVersion.h" #include "Kaleidoscope-FocusSerial.h" #include "Kaleidoscope-Macros.h" #include "Kaleidoscope-MouseKeys.h" #include "Kaleidoscope-OneShot.h" #include "Kaleidoscope-Qukeys.h" #include "Kaleidoscope-SpaceCadet.h" - +#include "Kaleidoscope-DynamicMacros.h" +#include "Kaleidoscope-LayerNames.h" #define MO(n) ShiftToLayer(n) #define TG(n) LockLayer(n) @@ -100,6 +103,7 @@ KEYMAPS( // clang-format on KALEIDOSCOPE_INIT_PLUGINS( + EscapeOneShot, EEPROMSettings, EEPROMKeymap, Focus, @@ -109,7 +113,11 @@ KALEIDOSCOPE_INIT_PLUGINS( SpaceCadet, OneShot, Macros, - MouseKeys); + DynamicMacros, + MouseKeys, + EscapeOneShotConfig, + FirmwareVersion, + LayerNames); const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) { if (keyToggledOn(event.state)) { @@ -135,7 +143,13 @@ const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) { void setup() { Kaleidoscope.setup(); SpaceCadet.disable(); - EEPROMKeymap.setup(10); + EEPROMKeymap.setup(9); + + DynamicMacros.reserve_storage(48); + + LayerNames.reserve_storage(63); + + Layer.move(EEPROMSettings.default_layer()); } void loop() { diff --git a/examples/Devices/Keyboardio/Model01/Makefile b/examples/Devices/Keyboardio/Model01/Makefile index 19019b31..51c6a792 100644 --- a/examples/Devices/Keyboardio/Model01/Makefile +++ b/examples/Devices/Keyboardio/Model01/Makefile @@ -1,6 +1,8 @@ # This makefile for a Kaleidoscope sketch pulls in all the targets # required to build the example +# Compile without deprecated code to save space +LOCAL_CFLAGS ?= -DNDEPRECATED -DONESHOT_WITHOUT_METASTICKY diff --git a/examples/Devices/Keyboardio/Model01/Model01.ino b/examples/Devices/Keyboardio/Model01/Model01.ino index b66cc0d2..c919871f 100644 --- a/examples/Devices/Keyboardio/Model01/Model01.ino +++ b/examples/Devices/Keyboardio/Model01/Model01.ino @@ -1,106 +1,522 @@ -/* -*- mode: c++ -*- - * Kaleidoscope - A Kaleidoscope example - * Copyright (C) 2016-2019 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 . +// -*- mode: c++ -*- +// Copyright 2016 Keyboardio, inc. +// 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, + * as well as the Kaleidoscope plugins we use in the Model 01's firmware */ -#define DEBUG_SERIAL false +// The Kaleidoscope core #include "Kaleidoscope.h" + +// Support for storing the keymap in EEPROM +#include "Kaleidoscope-EEPROM-Settings.h" +#include "Kaleidoscope-EEPROM-Keymap.h" + +// Support for communicating with the host via a simple Serial protocol +#include "Kaleidoscope-FocusSerial.h" + +// Support for querying the firmware version via Focus +#include "Kaleidoscope-FirmwareVersion.h" + +// Support for keys that move the mouse #include "Kaleidoscope-MouseKeys.h" + +// Support for macros & dynamic macros #include "Kaleidoscope-Macros.h" +#include "Kaleidoscope-DynamicMacros.h" + +// Support for controlling the keyboard's LEDs #include "Kaleidoscope-LEDControl.h" + +// Support for "Numpad" mode, which is mostly just the Numpad specific LED mode #include "Kaleidoscope-NumPad.h" -#include "Kaleidoscope-HardwareTestMode.h" -#include "Kaleidoscope-MagicCombo.h" +// 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) +#include "Kaleidoscope-LEDEffect-BootGreeting.h" + +// Support for LED modes that set all LEDs to a single color #include "Kaleidoscope-LEDEffect-SolidColor.h" + +// Support for an LED mode that makes all the LEDs 'breathe' #include "Kaleidoscope-LEDEffect-Breathe.h" + +// Support for an LED mode that makes a red pixel chase a blue pixel across the keyboard #include "Kaleidoscope-LEDEffect-Chase.h" + +// Support for LED modes that pulse the keyboard's LED in a rainbow pattern #include "Kaleidoscope-LEDEffect-Rainbow.h" -#define NUMPAD_KEYMAP 2 - -// clang-format off -#define GENERIC_FN2 KEYMAP_STACKED ( \ - ___, Key_F1, Key_F2, Key_F3, Key_F4, Key_F5, XXX, \ - Key_Tab, Key_mouseBtnM, Key_mouseUp, ___, Key_mouseWarpNW, Key_mouseWarpNE, Consumer_ScanNextTrack, \ - Key_Home, Key_mouseL, Key_mouseDn, Key_mouseR, Key_mouseWarpSW, Key_mouseWarpSE, \ - Key_End, Key_Z, Key_X, Key_C, Key_V, Key_mouseWarpEnd, ___, \ - Key_LeftControl, Key_mouseBtnL, Key_LeftGui, Key_LeftShift, \ - ___, \ -\ - XXX, Key_F6, Key_F7, Key_F8, Key_F9, ___, ___, \ - Key_Delete, Consumer_PlaySlashPause, Key_LeftCurlyBracket, Key_RightCurlyBracket, Key_LeftBracket, Key_RightBracket, System_Sleep, \ - Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, Key_F11, Key_F12, \ - ___, Consumer_VolumeDecrement, Consumer_VolumeIncrement, Key_BacklightDown, Key_BacklightUp, Key_Backslash, Key_Pipe, \ - Key_RightShift, Key_RightAlt, Key_mouseBtnR, Key_RightControl, \ - ___\ -) - -#define NUMPAD KEYMAP (\ - ___, ___, ___, ___, ___, ___, ___, ___, ___, Key_Keypad7, Key_Keypad8, Key_Keypad9, Key_KeypadSubtract, ___, \ - ___, ___, ___, ___, ___, ___, ___, ___, ___, Key_Keypad4, Key_Keypad5, Key_Keypad6, Key_KeypadAdd, ___, \ - ___, ___, ___, ___, ___, ___, ___, Key_Keypad1, Key_Keypad2, Key_Keypad3, Key_Equals, Key_Quote, \ - ___, ___, ___, ___, ___, ___, ___, ___, ___, Key_Keypad0, Key_KeypadDot, Key_KeypadMultiply, Key_KeypadDivide, Key_Enter, \ - Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift, Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl, \ - Key_Keymap1_Momentary, Key_Keymap1_Momentary \ -) - -#define QWERTY KEYMAP ( \ - ___, Key_1, Key_2, Key_3, Key_4, Key_5, Key_LEDEffectNext, ___, Key_6, Key_7, Key_8, Key_9, Key_0, Key_KeypadNumLock, \ - Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab, Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals, \ - Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G, Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote, \ - Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape, ___, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus, \ - Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift, Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl, \ - Key_KeymapNext_Momentary, Key_KeymapNext_Momentary \ -) +// Support for shared palettes for other plugins, like Colormap below +#include "Kaleidoscope-LED-Palette-Theme.h" + +// Support for an LED mode that lets one configure per-layer color maps +#include "Kaleidoscope-Colormap.h" + +// Support for Keyboardio's internal keyboard testing mode +#include "Kaleidoscope-HardwareTestMode.h" + +// Support for host power management (suspend & wakeup) +#include "Kaleidoscope-HostPowerManagement.h" + +// Support for magic combos (key chords that trigger an action) +#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 +#include "Kaleidoscope-USB-Quirks.h" + +/** This 'enum' is a list of all the macros used by the Model 01's firmware + * The names aren't particularly important. What is important is that each + * is unique. + * + * These are the names of your macros. They'll be used in two places. + * The first is in your keymap definitions. There, you'll use the syntax + * `M(MACRO_NAME)` to mark a specific keymap position as triggering `MACRO_NAME` + * + * The second usage is in the 'switch' statement in the `macroAction` function. + * That switch statement actually runs the code associated with a macro when + * a macro key is pressed. + */ + +enum { MACRO_VERSION_INFO, + MACRO_ANY +}; + + +/** 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" + * keymap. + * + * Each keymap is defined as a list using the 'KEYMAP_STACKED' macro, built + * of first the left hand's layout, followed by the right hand's layout. + * + * Keymaps typically consist mostly of `Key_` definitions. There are many, many keys + * 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 + * 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_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_keymaps.h + * + * Additional things that should be documented here include + * using ___ to let keypresses fall through to the previously active layer + * using XXX to mark a keyswitch as 'blocked' on this layer + * using ShiftToLayer() and LockLayer() keys to change the active keymap. + * keeping NUM and FN consistent and accessible on all layers + * + * The PROG key is special, since it is how you indicate to the board that you + * want to flash the firmware. However, it can be remapped to a regular key. + * When the keyboard boots, it first looks to see whether the PROG key is held + * down; if it is, it simply awaits further flashing instructions. If it is + * not, it continues loading the rest of the firmware and the keyboard + * functions normally, with whatever binding you have set to PROG. More detail + * here: https://community.keyboard.io/t/how-the-prog-key-gets-you-into-the-bootloader/506/8 + * + * The "keymaps" data structure is a list of the keymaps compiled into the firmware. + * The order of keymaps in the list is important, as the ShiftToLayer(#) and LockLayer(#) + * macros switch to key layers based on this list. + * + * + + * A key defined as 'ShiftToLayer(FUNCTION)' will switch to FUNCTION while held. + * Similarly, a key defined as 'LockLayer(NUMPAD)' will switch to NUMPAD when tapped. + */ + +/** + * Layers are "0-indexed" -- That is the first one is layer 0. The second one is layer 1. + * The third one is layer 2. + * This 'enum' lets us use names like QWERTY, FUNCTION, and NUMPAD in place of + * the numbers 0, 1 and 2. + * + */ + +enum { PRIMARY, + NUMPAD, + FUNCTION }; // layers + + +/** + * To change your keyboard's layout from QWERTY to DVORAK or COLEMAK, comment out the line + * + * #define PRIMARY_KEYMAP_QWERTY + * + * by changing it to + * + * // #define PRIMARY_KEYMAP_QWERTY + * + * Then uncomment the line corresponding to the layout you want to use. + * + */ + +#define PRIMARY_KEYMAP_QWERTY +// #define PRIMARY_KEYMAP_DVORAK +// #define PRIMARY_KEYMAP_COLEMAK +// #define PRIMARY_KEYMAP_CUSTOM + + +/* This comment temporarily turns off astyle's indent enforcement + * so we can make the keymaps actually resemble the physical key layout better + */ +// *INDENT-OFF* KEYMAPS( - QWERTY, - GENERIC_FN2, - NUMPAD -) -// clang-format on - -static kaleidoscope::plugin::LEDSolidColor solidRed(60, 0, 0); -static kaleidoscope::plugin::LEDSolidColor solidOrange(60, 20, 0); -static kaleidoscope::plugin::LEDSolidColor solidYellow(40, 35, 0); -static kaleidoscope::plugin::LEDSolidColor solidGreen(0, 100, 0); -static kaleidoscope::plugin::LEDSolidColor solidBlue(0, 15, 100); -static kaleidoscope::plugin::LEDSolidColor solidIndigo(0, 0, 100); -static kaleidoscope::plugin::LEDSolidColor solidViolet(70, 0, 60); + +#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), + + 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)), + +#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), + + 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), + + 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(___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, ___, + + 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, ___, ___, ___, + + 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( + +/* Re-enable astyle's indent enforcement */ +// *INDENT-ON* + +/** versionInfoMacro handles the 'firmware version info' macro + * When a key bound to the macro is pressed, this macro + * prints out the firmware build information as virtual keystrokes + */ + +static void versionInfoMacro(uint8_t key_state) { + if (keyToggledOn(key_state)) { + Macros.type(PSTR("Keyboardio Model 01 - Kaleidoscope ")); + Macros.type(PSTR(BUILD_INFORMATION)); + } +} + +/** anyKeyMacro is used to provide the functionality of the 'Any' key. + * + * When the 'any key' macro is toggled on, a random alphanumeric key is + * selected. While the key is held, the function generates a synthetic + * keypress event repeating that randomly selected key. + * + */ + +static void anyKeyMacro(KeyEvent &event) { + if (keyToggledOn(event.state)) { + event.key.setKeyCode(Key_A.getKeyCode() + (uint8_t)(millis() % 36)); + event.key.setFlags(0); + } +} + + +/** macroAction dispatches keymap events that are tied to a macro + to that macro. It takes two uint8_t parameters. + + The first is the macro being called (the entry in the 'enum' earlier in this file). + The second is the state of the keyswitch. You can use the keyswitch state to figure out + if the key has just been toggled on, is currently pressed or if it's just been released. + + The 'switch' statement should have a 'case' for each entry of the macro enum. + Each 'case' statement should call out to a function to handle the macro in question. + + */ const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) { - if (macro_id == 1 && keyToggledOn(event.state)) { - Kaleidoscope.serialPort().print("Keyboard.IO keyboard driver v0.00"); - return MACRO(I(25), - D(LeftShift), - T(M), - U(LeftShift), - T(O), - T(D), - T(E), - T(L), - T(Spacebar), - W(100), - T(0), - T(1)); + switch (macro_id) { + + case MACRO_VERSION_INFO: + versionInfoMacro(event.state); + break; + + case MACRO_ANY: + anyKeyMacro(event); + break; } return MACRO_NONE; } + +// These 'solid' color effect definitions define a rainbow of +// LED color modes calibrated to draw 500mA or less on the +// Keyboardio Model 01. + + +static kaleidoscope::plugin::LEDSolidColor solidRed(160, 0, 0); +static kaleidoscope::plugin::LEDSolidColor solidOrange(140, 70, 0); +static kaleidoscope::plugin::LEDSolidColor solidYellow(130, 100, 0); +static kaleidoscope::plugin::LEDSolidColor solidGreen(0, 160, 0); +static kaleidoscope::plugin::LEDSolidColor solidBlue(0, 70, 130); +static kaleidoscope::plugin::LEDSolidColor solidIndigo(0, 0, 170); +static kaleidoscope::plugin::LEDSolidColor solidViolet(130, 0, 120); + +/** toggleLedsOnSuspendResume toggles the LEDs off when the host goes to sleep, + * and turns them back on when it wakes up. + */ +void toggleLedsOnSuspendResume(kaleidoscope::plugin::HostPowerManagement::Event event) { + switch (event) { + case kaleidoscope::plugin::HostPowerManagement::Suspend: + LEDControl.disable(); + break; + case kaleidoscope::plugin::HostPowerManagement::Resume: + LEDControl.enable(); + break; + case kaleidoscope::plugin::HostPowerManagement::Sleep: + break; + } +} + +/** hostPowerManagementEventHandler dispatches power management events (suspend, + * resume, and sleep) to other functions that perform action based on these + * events. + */ +void hostPowerManagementEventHandler(kaleidoscope::plugin::HostPowerManagement::Event event) { + toggleLedsOnSuspendResume(event); +} + +/** 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 + * each is unique. + * + * These are the names of your magic combos. They will be used by the + * `USE_MAGIC_COMBOS` call below. + */ +enum { + // Toggle between Boot (6-key rollover; for BIOSes and early boot) and NKRO + // mode. + COMBO_TOGGLE_NKRO_MODE, + // Enter test mode + COMBO_ENTER_TEST_MODE +}; + +/** Wrappers, to be used by MagicCombo. **/ + +/** + * This simply toggles the keyboard protocol via USBQuirks, and wraps it within + * a function with an unused argument, to match what MagicCombo expects. + */ +static void toggleKeyboardProtocol(uint8_t combo_index) { + USBQuirks.toggleKeyboardProtocol(); +} + /** * This enters the hardware test mode */ @@ -112,35 +528,168 @@ static void enterHardwareTestMode(uint8_t combo_index) { /** Magic combo list, a list of key combo and action pairs the firmware should * recognise. */ -USE_MAGIC_COMBOS({.action = enterHardwareTestMode, +USE_MAGIC_COMBOS({.action = toggleKeyboardProtocol, + // Left Fn + Esc + Shift + .keys = {R3C6, R2C6, R3C7}}, + {.action = enterHardwareTestMode, // Left Fn + Prog + LED .keys = {R3C6, R0C0, R0C6}}); -KALEIDOSCOPE_INIT_PLUGINS(HardwareTestMode, - LEDControl, - LEDOff, - solidRed, - solidOrange, - solidYellow, - solidGreen, - solidBlue, - solidIndigo, - solidViolet, - LEDBreatheEffect, - LEDRainbowEffect, - LEDChaseEffect, - NumPad, - Macros, - MouseKeys, - MagicCombo); +// First, tell Kaleidoscope which plugins you want to use. +// The order can be important. For example, LED effects are +// added in the order they're listed here. +KALEIDOSCOPE_INIT_PLUGINS( + // The EEPROMSettings & EEPROMKeymap plugins make it possible to have an + // editable keymap in EEPROM. + EEPROMSettings, + EEPROMKeymap, + + // Focus allows bi-directional communication with the host, and is the + // interface through which the keymap in EEPROM can be edited. + Focus, + + // FocusSettingsCommand adds a few Focus commands, intended to aid in + // changing some settings of the keyboard, such as the default layer (via the + // `settings.defaultLayer` command) + FocusSettingsCommand, + + // FocusEEPROMCommand adds a set of Focus commands, which are very helpful in + // both debugging, and in backing up one's EEPROM contents. + FocusEEPROMCommand, + + // The boot greeting effect pulses the LED button for 10 seconds after the + // keyboard is first connected + BootGreetingEffect, + + // The hardware test mode, which can be invoked by tapping Prog, LED and the + // left Fn button at the same time. + HardwareTestMode, + + // LEDControl provides support for other LED modes + LEDControl, + + // We start with the LED effect that turns off all the LEDs. + LEDOff, + + // The rainbow effect changes the color of all of the keyboard's keys at the same time + // running through all the colors of the rainbow. + LEDRainbowEffect, + + // The rainbow wave effect lights up your keyboard with all the colors of a rainbow + // and slowly moves the rainbow across your keyboard + LEDRainbowWaveEffect, + + // The chase effect follows the adventure of a blue pixel which chases a red pixel across + // your keyboard. Spoiler: the blue pixel never catches the red pixel + LEDChaseEffect, + + // These static effects turn your keyboard's LEDs a variety of colors + solidRed, + solidOrange, + solidYellow, + solidGreen, + solidBlue, + solidIndigo, + solidViolet, + + // The breathe effect slowly pulses all of the LEDs on your keyboard + LEDBreatheEffect, + + // The LED Palette Theme plugin provides a shared palette for other plugins, + // like Colormap below + LEDPaletteTheme, + + // The Colormap effect makes it possible to set up per-layer colormaps + ColormapEffect, + // The numpad plugin is responsible for lighting up the 'numpad' mode + // with a custom LED effect + NumPad, + + // The macros plugin adds support for macros, DynamicMacros does the same for + // Chrysalis-editable, dynamic ones. + Macros, + DynamicMacros, + + // The MouseKeys plugin lets you add keys to your keymap which move the mouse. + 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 + // goes to sleep, and resume them when it wakes up. + HostPowerManagement, + + // The MagicCombo plugin lets you use key combinations to trigger custom + // actions - a bit like Macros, but triggered by pressing multiple keys at the + // same time. + MagicCombo, + + // The USBQuirks plugin lets you do some things with USB that we aren't + // comfortable - or able - to do automatically, but can be useful + // nevertheless. Such as toggling the key report protocol between Boot (used + // by BIOSes) and Report (NKRO). + USBQuirks, + + // The FirmwareVersion plugin lets Chrysalis query the version of the firmware + // programmatically. + FirmwareVersion); + +/** 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 + * Kaleidoscope and any plugins. + */ void setup() { + // First, call Kaleidoscope's internal setup function Kaleidoscope.setup(); - NumPad.numPadLayer = NUMPAD_KEYMAP; + // While we hope to improve this in the future, the NumPad plugin + // needs to be explicitly told which keymap layer is your numpad layer + NumPad.numPadLayer = NUMPAD; + + // 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 + LEDRainbowEffect.brightness(150); + LEDRainbowWaveEffect.brightness(150); + + // Set the action key the test mode should listen for to Left Fn + HardwareTestMode.setActionKey(R3C6); + + // 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 + // 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, + // by using the `settings.defaultLayer` Focus command, or by using the + // `keymap.onlyCustom` command to use EEPROM layers only. + EEPROMKeymap.setup(5); + + // 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 + // many editable layers we have (see above). + ColormapEffect.max_layers(5); + + // For Dynamic Macros, we need to reserve storage space for the editable + // macros. + DynamicMacros.reserve_storage(128); + + // If there's a default layer set in EEPROM, we should set that as the default + // here. + Layer.move(EEPROMSettings.default_layer()); } +/** loop is the second of the standard Arduino sketch functions. + * As you might expect, it runs in a loop, never exiting. + * + * For Kaleidoscope-based keyboard firmware, you usually just want to + * call Kaleidoscope.loop(); and not do anything custom here. + */ void loop() { Kaleidoscope.loop(); diff --git a/examples/Devices/Keyboardio/Model01/sketch.json b/examples/Devices/Keyboardio/Model01/sketch.json index 884ed009..d65116ce 100644 --- a/examples/Devices/Keyboardio/Model01/sketch.json +++ b/examples/Devices/Keyboardio/Model01/sketch.json @@ -3,4 +3,4 @@ "fqbn": "keyboardio:avr:model01", "port": "" } -} +} \ No newline at end of file diff --git a/examples/Devices/Keyboardio/Model100/Model100.ino b/examples/Devices/Keyboardio/Model100/Model100.ino index 0d56ab84..b8e1a0e6 100644 --- a/examples/Devices/Keyboardio/Model100/Model100.ino +++ b/examples/Devices/Keyboardio/Model100/Model100.ino @@ -2,17 +2,11 @@ // Copyright 2016-2022 Keyboardio, inc. // 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, * as well as the Kaleidoscope plugins we use in the Model 100's firmware */ - // The Kaleidoscope core #include "Kaleidoscope.h" @@ -23,6 +17,9 @@ // Support for communicating with the host via a simple Serial protocol #include "Kaleidoscope-FocusSerial.h" +// Support for querying the firmware version via Focus +#include "Kaleidoscope-FirmwareVersion.h" + // Support for keys that move the mouse #include "Kaleidoscope-MouseKeys.h" @@ -66,6 +63,9 @@ // 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 #include "Kaleidoscope-HardwareTestMode.h" @@ -88,6 +88,15 @@ // 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 * is unique. @@ -225,16 +234,16 @@ KEYMAPS( [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_Backtick, Key_Q, Key_W, Key_F, Key_P, Key_B, Key_Tab, + Key_PageUp, Key_A, Key_R, Key_S, Key_T, Key_G, + Key_PageDown, Key_Z, Key_X, Key_C, Key_D, Key_V, Key_Escape, Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift, ShiftToLayer(FUNCTION), M(MACRO_ANY), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD), Key_Enter, Key_J, Key_L, Key_U, Key_Y, Key_Semicolon, Key_Equals, - Key_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_M, Key_N, Key_E, Key_I, Key_O, Key_Quote, + Key_RightAlt, Key_K, Key_H, Key_Comma, Key_Period, Key_Slash, Key_Minus, Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl, ShiftToLayer(FUNCTION)), @@ -304,8 +313,8 @@ KEYMAPS( static void versionInfoMacro(uint8_t key_state) { if (keyToggledOn(key_state)) { - Macros.type(PSTR("Keyboardio Model 100 - Kaleidoscope ")); - Macros.type(PSTR(BUILD_INFORMATION)); + Macros.type(PSTR("Keyboardio Model 100 - Firmware version ")); + Macros.type(PSTR(KALEIDOSCOPE_FIRMWARE_VERSION)); } } @@ -414,6 +423,17 @@ static void toggleKeyboardProtocol(uint8_t combo_index) { 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 */ @@ -430,7 +450,10 @@ USE_MAGIC_COMBOS({.action = toggleKeyboardProtocol, .keys = {R3C6, R2C6, R3C7}}, {.action = enterHardwareTestMode, // 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. // The order can be important. For example, LED effects are @@ -441,6 +464,12 @@ KALEIDOSCOPE_INIT_PLUGINS( EEPROMSettings, 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 // interface through which the keymap in EEPROM can be edited. Focus, @@ -547,7 +576,23 @@ KALEIDOSCOPE_INIT_PLUGINS( PersistentIdleLEDs, // Enables dynamic, Chrysalis-editable macros. - DynamicMacros); + 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. * It's called when your keyboard first powers up. This is where you set up @@ -581,11 +626,6 @@ void setup() { // https://github.com/keyboardio/Kaleidoscope/blob/master/docs/plugins/LED-Stalker.md 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 // 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, @@ -601,6 +641,25 @@ void setup() { // 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(); + + // 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.