Merge pull request #365 from keyboardio/f/monorepo

Pull in the essential plugins, on the way to become monorepo
pull/367/head
Gergely Nagy 6 years ago committed by GitHub
commit f291c56f3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,31 @@
#!/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
DEVICE="${DEVICE:-/dev/ttyACM0}"
stty -F "${DEVICE}" 9600 raw -echo
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

@ -0,0 +1,65 @@
# Kaleidoscope-EEPROM-Keymap
While keyboards usually ship with a keymap programmed in, to be able to change that keymap, without flashing new firmware, we need a way to place the keymap into a place we can update at run-time, and which persists across reboots. Fortunately, we have a bit of `EEPROM` on the keyboard, and can use it to store either the full keymap (and saving space in the firmware then), or store additional layers there.
In short, this plugin allows us to change our keymaps, without having to compile and flash new firmware. It does so through the use of the [FocusSerial][plugin:focusSerial] plugin.
[plugin:focusSerial]: FocusSerial.md
## Using the plugin
Using the plugin is reasonably simple: after including the header, enable the plugin, and configure how many layers at most we want to store in `EEPROM`. There are other settings one can tweak, but these two steps are enough to get started with.
Once these are set up, we can update the keymap via [Focus][plugin:focusSerial].
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-EEPROM-Keymap.h>
#include <Kaleidoscope-FocusSerial.h>
KALEIDOSCOPE_INIT_PLUGINS(EEPROMKeymap,
Focus);
void setup() {
Kaleidoscope.setup();
EEPROMKeymap.setup(1);
}
```
## Plugin methods
The plugin provides the `EEPROMKeymap` object, which has the following method:
### `.setup(layers[, mode])`
> Reserve space in EEPROM for up to `layers` layers, and set things up to work according to the specified `mode` (see below for a list of supported modes). To be called from the `setup` method of one's sketch.
>
> Supported modes are:
> - `EEPROMKeymap.Mode::EXTEND`: Extend the keymap with layers from EEPROM, treating them as extensions of the main keymap embedded in the firmware. The first layer in EEPROM will have a number one higher than the last layer in PROGMEM. In this case, the total number of layers will be the number of them in PROGMEM plus `layers`.
> - `EEPROMKeymap.Mode::CUSTOM`: For advanced use cases where the `EXTEND` mode is not appropriate. In this case, the plugin merely reserves a slice of EEPROM for the requested amount of layers, but does no other configuration - that's entirely up to the Sketch.
## Focus commands
The plugin provides the `keymap.map` and a `keymap.roLayers` commands.
### `keymap.map [codes...]`
> Without arguments, displays the keymap currently in effect. Each key is printed as its raw, 16-bit keycode.
>
> With arguments, it stores as many keys as given. One does not need to set all keys, on all layers: the command will start from the first key on the first layer, and go on as long as it has input. It will not go past the total amount of layers (that is, `layer_count`).
### `keymap.roLayers`
> Returns the number of read-only layers. This only makes sense for the `EEPROMKeymap.Mode::EXTEND` mode, where it returns the number of layers in PROGMEM. In any other case, it doesn't return anything, doing so is left for another event handler that understands what the correct value would be.
## Dependencies
* [Kaleidoscope-EEPROM-Settings](EEPROM-Settings.md)
* [Kaleidoscope-FocusSerial](FocusSerial.md)
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting started with the plugin.
[plugin:example]: ../../examples/EEPROM-Keymap/EEPROM-Keymap.ino

@ -0,0 +1,168 @@
# Kaleidoscope-EEPROM-Settings
To be able to reliably store persistent configuration in `EEPROM`, we need to be
able to split up the available space for plugins to use. We also want to make
sure that we notice when the `EEPROM` contents and the firmware are out of sync.
This plugin provides the tools to do that.
It does not guard against errors, it merely provides the means to discover them,
and let the firmware Sketch handle the case in whatever way it finds reasonable.
It's a building block, and not much else. All Kaleidoscope plugins that need to
store data in `EEPROM` are encouraged to make use of this library.
## Using the plugin
There are a few steps one needs to take to use the plugin: we must first
register it, then either let other plugins request slices of `EEPROM`, or do so
ourselves. And finally, seal it, to signal that we are done setting up. At that
point, we can verify whether the contents of the `EEPROM` agree with our
firmware.
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-EEPROM-Settings.h>
static uint16_t settingsBase;
static struct {
bool someSettingFlag;
} testSettings;
KALEIDOSCOPE_INIT_PLUGINS(EEPROMSettings, /* Other plugins that use EEPROM... */);
void setup () {
Kaleidoscope.setup();
settingsBase = EEPROMSettings.requestSlice(sizeof(testSettings));
EEPROMSettings.seal();
if (!EEPROMSettings.isValid()) {
// Handle the case where the settings are out of sync...
// Flash LEDs, for example.
return;
}
EEPROM.get(settingsBase, testSettings);
}
```
## Plugin methods
The plugin provides the `EEPROMSettings` object, which has the following methods:
### `requestSlice(size)`
> Requests a slice of the `EEPROM`, and returns the starting address (or 0 on
> error, including when the request arrived after sealing the layout).
>
> Should only be called **before** calling `seal()`.
### `default_layer([id])`
> Sets (or returns, if called without an ID) the default layer. When the
> keyboard boots up, it will automatically switch to the configured layer - if
> any.
>
> This is the Focus counterpart of the `default_layer()` method documented
> above.
### `seal()`
> Seal the `EEPROM` layout, so no new slices can be requested. The CRC checksum
> is considered final at this time, and the `isValid()`, `crc()`, `used()` and
> `version()` methods can be used from this point onwards.
>
> If not called explicitly, the layout will be sealed automatically after
> `setup()` in the sketch finished.
### `update()`
> Updates the `EEPROM` header with the current status quo, including the version
> and the CRC checksum.
>
> This should be called when upgrading from one version to another, or when
> fixing up an out-of-sync case.
### `isValid()`
> Returns whether the `EEPROM` header is valid, that is, if it has the expected
> CRC checksum.
>
> Should only be called after calling `seal()`.
### `invalidate()`
> Invalidates the `EEPROM` header. Use when the version does not match what the
> firmware would expect. This signals to other plugins that the contents of
> `EEPROM` should not be trusted.
### `version([newVersion])`
> Sets or returns the version of the `EEPROM` layout. This is purely for use by
> the firmware, so it can attempt to upgrade the contents, if need be, or alert
> the user in there's a mismatch. Plugins do not use this property.
>
> Should only be called after calling `seal()`.
### `crc()`
> Returns the CRC checksum of the layout. Should only be used after calling
> `seal()`.
### `used()`
> Returns the amount of space requested so far.
>
> Should only be used after calling `seal()`.
## Focus commands
The plugin provides two - optional - [Focus][FocusSerial] command plugins:
`FocusSettingsCommand` and `FocusEEPROMCommand`. These must be explicitly added
to `KALEIDOSCOPE_INIT_PLUGINS` if one wishes to use them. They provide the
following commands:
[FocusSerial]: FocusSerial.md
### `settings.defaultLayer`
> Sets or returns (if called without arguments) the ID of the default layer. If
> set, the keyboard will automatically switch to the given layer when connected.
> Setting it to `255` disables the automatic switching.
### `settings.crc`
> Returns the actual, and the expected checksum of the settings.
### `settings.valid?`
> Returns either `true` or `false`, depending on whether the sealed settings are
> to be considered valid or not.
### `settings.version`
> Returns the (user-set) version of the settings.
### `eeprom.contents`
> Without argument, displays the full contents of the `EEPROM`, including the
> settings header.
>
> With arguments, the command updates as much of the `EEPROM` as arguments are
> provided. It will discard any unnecessary arguments.
### `eeprom.free`
> Returns the amount of free bytes in `EEPROM`.
## Dependencies
* [Kaleidoscope-FocusSerial][FocusSerial]
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting
started with the plugin.
[plugin:example]: ../../examples/EEPROM-Settings/EEPROM-Settings.ino

@ -0,0 +1,292 @@
# Kaleidoscope-FocusSerial
Bidirectional communication for Kaleidoscope. With this plugin enabled, plugins that implement the `onFocusEvent` hook will start responding to Focus commands sent via `Serial`, allowing bidirectional communication between firmware and host.
This plugin is an upgrade of the former [Kaleidoscope-Focus][kaleidoscope:focus] plugin. See the [UPGRADING][upgrading] section for information about how to transition to the new system.
[kaleidoscope:focus]: Focus.md
[upgrading]: #upgrading-from-focus-to-onfocusevent--focusserial
## Using the plugin
This plugin is **not** meant to be used by the end-user (apart from setting it up to use plugin-provided hooks), but by plugin authors instead. As an end user, you just need to use Focus-enabled plugins like you normally would, and once `FocusSerial` is enabled, their commands will be available too.
Nevertheless, a very simple example is shown below:
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-FocusSerial.h>
namespace kaleidoscope {
class FocusTestCommand : public Plugin {
public:
FocusTestCommand() {}
EventHandlerResult onFocusEvent(const char *command) {
if (strcmp_P(command, PSTR("test")) != 0)
return EventHandlerResult::OK;
Serial.println(F("Congratulations, the test command works!"));
return EventHandlerResult::EVENT_CONSUMED;
}
};
}
kaleidoscope::FocusTestCommand FocusTestCommand;
KALEIDOSCOPE_INIT_PLUGINS(Focus, FocusTestCommand);
void setup () {
Kaleidoscope.setup ();
}
```
## Plugin methods
The plugin provides the `Focus` object, with a couple of helper methods aimed at developers. Documenting those is a work in progress for now.
## Wire protocol
`Focus` uses a simple, textual, request-response-based wire protocol.
Each request has to be on one line, anything before the first space is the command part (if there is no space, just a newline, then the whole line will be considered a command), everything after are arguments. The plugin itself only parses until the end of the command part, argument parsing is left to the various hooks. If there is anything left on the line after hooks are done processing, it will be ignored.
Responses can be multi-line, but most aren't. Their content is also up to the hooks, `Focus` does not enforce anything, except a trailing dot and a newline. Responses should end with a dot on its own line.
Apart from these, there are no restrictions on what can go over the wire, but to make the experience consistent, find a few guidelines below:
* Commands should be namespaced, so that the plugin name, or functionality comes first, then the sub-command or property. Such as `led.theme`, or `led.setAll`.
* One should not use setters and getters, but a single property command instead. One, which when called without arguments, will act as a getter, and as a setter otherwise.
* Namespaces should be lowercase, while the commands within them camel-case.
* Do as little work in the hooks as possible. While the protocol is human readable, the expectation is that tools will be used to interact with the keyboard.
* As such, keep formatting to the bare minimum. No fancy table-like responses.
* In general, the output of a getter should be copy-pasteable to a setter.
These are merely guidelines, and there can be - and are - exceptions. Use your discretion when writing Focus hooks.
### Example
In the examples below, `<` denotes what the host sends to the keyboard, `>` what
the keyboard responds.
```
< test
> Congratulations, the test command works!
> .
```
```
< help
> help
> test
> palette
> .
```
```
< palette
> 0 0 0 128 128 128 255 255 255
> .
< palette 0 0 0 128 128 128 255 255 255
> .
```
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting started with the plugin.
[plugin:example]: ../../examples/FocusSerial/FocusSerial.ino
Upgrading from Focus to onFocusEvent + FocusSerial
==================================================
Upgrading from `Focus` to `onFocusEvent` and `FocusSerial` is a reasonably simple process, the interface is quite similar. Nevertheless, we present a step-by-step guide here, covering two use cases: one where we wish to always provide a Focus command when both our plugin and `FocusSerial` are enabled; and another where we only wish to provide the command when explicitly asked to do so.
## The most trivial example
The biggest difference between `Focus` and `onFocusEvent` is that the former required explicit registering of hooks, while the latter does it automatically: every plugin that implements the `onFocusEvent` method will be part of the system. As a consequence, only plugins are able to supply new commands: there is no explicit registration, thus, no way to inject a command that isn't part of a plugin. This also means that these functions now return `kaleidoscope::EventHandlerResult` instead of `bool`. Lets see a trivial example!
### Focus
```c++
bool exampleFocusHook(const char *command) {
if (strcmp_P(command, PSTR("example")) != 0)
return false;
Serial.println(F("This is an example response. Hello world!"));
return true;
}
KALEIDOSCOPE_INIT_PLUGINS(Focus)
void setup() {
Serial.begin(9600);
Kaleidoscope.setup();
Focus.addHook(FOCUS_HOOK(exampleFocusHook, "example"));
}
```
### onFocusEvent
```c++
namespace kaleidoscope {
class FocusExampleCommand : public Plugin {
public:
FocusExampleCommand() {}
EventHandlerResult onFocusEvent(const char *command) {
if (strcmp_P(command, PSTR("example")) != 0)
return EventHandlerResult::OK;
Serial.println(F("This is an example response. Hello world!"));
return EventHandlerResult::EVENT_CONSUMED;
}
};
}
kaleidoscope::FocusExampleCommand FocusExampleCommand;
KALEIDOSCOPE_INIT_PLUGINS(Focus, FocusExampleCommand);
void setup() {
Kaleidoscope.setup();
}
```
### Summary
The new version is slightly more verbose for the trivial use case, because we have to wrap it up in an object. But other than that, the changes are minimal, and we don't need to explicitly register it!
Observe that the return values changed: with `Focus`, if we wanted other hooks to have a chance at processing the same command, the hook returned `false`; if we wanted to stop processing, and consider it consumed, it returned `true`. With the new system, this is more descriptive with the `EventHandlerResult::OK` and `EventHandlerResult::EVENT_CONSUMED` return values.
## A stateful example
Perhaps a better example that shows the quality of life improvements the new system brings is the case where the command needs access to either plugin state, or plugin methods. With the former system, the focus hooks needed to be static methods, and needed to be public. This is not necessarily the case now, because `onFocusEvent` is a non-static object method. It has full access to plugin internals!
### Focus
```c++
namespace kaleidoscope {
class ExamplePlugin : public Plugin {
public:
ExamplePlugin();
static bool exampleToggle() {
example_toggle_ = !example_toggle_;
return example_toggle_;
}
static bool focusHook(const char *command) {
if (strcmp_P(command, PSTR("example.toggle")) != 0)
return false;
::Focus.printBool(exampleToggle());
return true;
}
private:
static bool example_toggle_;
};
}
kaleidoscope::ExamplePlugin ExamplePlugin;
KALEIDOSCOPE_PLUGIN_INIT(Focus, ExamplePlugin)
void setup() {
Serial.begin(9600);
Kaleidoscope.setup();
Focus.addHook(FOCUS_HOOK(ExamplePlugin.focusHook, "example.toggle"));
}
```
### onFocusEvent
```c++
namespace kaleidoscope {
class ExamplePlugin : public Plugin {
public:
ExamplePlugin();
EventHandlerResult onFocusEvent(const char *command) {
if (strcmp_P(command, PSTR("example.toggle")) != 0)
return EventHandlerResult::OK;
example_toggle_ = !example_toggle_;
::Focus.printBool(example_toggle_);
return EventHandlerResult::EVENT_CONSUMED;
}
private:
static bool example_toggle_;
};
}
kaleidoscope::ExamplePlugin ExamplePlugin;
KALEIDOSCOPE_PLUGIN_INIT(Focus, ExamplePlugin)
void setup() {
Kaleidoscope.setup();
}
```
### Summary
It's just another plugin, with just another event handler method implemented, nothing more. No need to explicitly register the focus hook, no need to provide access to private variables - we can just keep them private.
## Optional commands
Optional commands are something that were perhaps easier with the `Focus` method: one just didn't register them. With `onFocusEvent`, we need to do a bit more than that, and move the command to a separate plugin, if we do not wish to enable it in every case. This adds a bit of overhead, but still less than `Focus` did.
### Focus
```c++
bool exampleOptionalHook(const char *command) {
if (strcmp_P(command, PSTR("optional")) != 0)
return false;
Serial.println(Layer.getLayerState(), BIN);
return true;
}
KALEIDOSCOPE_INIT_PLUGINS(Focus)
void setup() {
Kaleidoscope.setup();
}
```
Do note that we do not register the `exampleOptionalHook` here! As such, because it is unused code, it will get optimized out during compilation. While this is a simplistic example, the optional hook might have been part of a class, that provides other hooks.
### onFocusEvent
```c++
namespace kaleidoscope {
class ExampleOptionalCommand : public Plugin {
public:
ExampleOptionalCommand() {}
EventHandlerResult onFocusEvent(const char *command) {
if (strcmp_P(command, PSTR("optional")) != 0)
return EventHandlerResult::OK;
Serial.println(Layer.getLayerState(), BIN);
return EventHandlerResult::EVENT_CONSUMED;
}
};
}
KALEIDOSCOPE_INIT_PLUGINS(Focus)
void setup() {
Kaleidoscope.setup();
}
```
### Summary
The trick here is to move optional commands out into a separate plugin. It's a bit more boilerplate, but not by much.

@ -0,0 +1,7 @@
# Kaleidoscope-Hardware-Model01
This is a plugin for [Kaleidoscope][fw], that adds hardware support for
the [Keyboardio Model01][kbdio:model01].
[fw]: https://github.com/keyboardio/Kaleidoscope
[kbdio:model01]: https://shop.keyboard.io/

@ -0,0 +1,47 @@
# Kaleidoscope-HostPowerManagement
Support performing custom actions whenever the host suspends, resumes, or is
sleeping.
## Using the plugin
To use the plugin, one needs to include the header, and activate it. No further
configuration is necessary, unless one wants to perform custom actions.
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-HostPowerManagement.h>
KALEIDOSCOPE_INIT_PLUGINS(HostPowerManagement);
void setup () {
Kaleidoscope.setup ();
}
```
## Plugin methods
The plugin provides the `HostPowerManagement` object, with no public methods.
## Overrideable methods
### `hostPowerManagementEventHandler(event)`
> The `hostPowerManagementEventHandler` method is the brain of the plugin: this function
> tells it what action to perform in response to the various events.
>
> Currently supported events are:
> `kaleidoscope::plugin::HostPowerManagement::Suspend` is fired once when the
> host suspends; `kaleidoscope::plugin::HostPowerManagement::Sleep` is fired
> every cycle while the host is suspended;
> `kaleidoscope::plugin::HostPowerManagement::Resume` is fired once when the
> host wakes up.
>
> The default implementation is empty.
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting
started with the plugin.
[plugin:example]: ../../examples/HostPowerManagement/HostPowerManagement.ino

@ -0,0 +1,109 @@
# Kaleidoscope-LED-AlphaSquare
An alphabet for your per-key LEDs, `AlphaSquare` provides a way to display 4x4
"pixel" symbols on your keyboard. With this building block, one can build some
sweet animations, or just show off - the possibilities are almost endless!
## Using the plugin
To use the plugin, one needs to include the header in their Sketch, tell the
firmware to `use` the plugin, and one way or another, call the `display` method.
This can be done from a macro, or via the `AlphaSquareEffect` LED mode.
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LED-AlphaSquare.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
AlphaSquare,
AlphaSquareEffect);
void setup() {
Kaleidoscope.setup();
AlphaSquare.display (Key_A);
}
```
## Plugin methods
The plugin provides the `AlphaSquare` object, which has its methods and
properties listed below, and an `AlphaSquareEffect` LED mode, which has no
methods or properties other than those provided by all LED modes.
### `.display(key)`
### `.display(key, col)`
### `.display(key, row, col)`
### `.display(key, row, col, color)`
> Display the symbol for `key` at the given row or column, with pixels set to
> the specified `color`. If `row` is omitted, the first row - `0` is assumed. If
> the column is omitted, then the third column - `2` - is used.
> If the `color` is omitted, the plugin will use the global `.color` property.
>
> The plugin can display the English alphabet, and the numbers from 0 to 9. The
> symbol will be drawn with the top-left corner at the given position.
>
> Please consult the appropriate hardware library of your keyboard to see how
> keys are laid out in rows and columns.
### `.display(symbol)`
### `.display(symbol, col)`
### `.display(symbol, row, col)`
### `.display(symbol, row, col, color)`
> As the previous function, but instead of a key, it expects a 4x4 bitmap in
> the form of a 16-bit unsigned integer, where the low bit is the top-right
> corner, the second-lowest bit is to the right of that, and so on.
>
> The `SYM4x4` macro can be used to simplify creating these bitmaps.
### `.clear(key)`, `.clear(symbol)`
### `.clear(key, col)`, `.clear(symbol, col)`
### `.clear(key, col, row)`, `.clear(symbol, col, row)`
> Just like the `.display()` counterparts, except these clear the symbol, by
> turning the LED pixels it is made up from off.
### `.color`
> The color to use to draw the pixels.
>
> Defaults to `{ 0x80, 0x80, 0x80 }` (light gray).
## Plugin helpers
### `SYM4x4(...)`
> A helper macro, which can be used to set up custom bitmaps. It expects 16
> values, a 4x4 square of zeroes and ones. Zeroes are transparent pixels, ones
> will be colored.
## Extra symbols
There is a growing number of pre-defined symbols available in the
`kaleidoscope::plugin::alpha_square::symbols` namespace. Ok, growing may have
been an exaggeration, there is only one as of this writing:
### `Lambda`
> A lambda (`λ`) symbol.
## Dependencies
* [Kaleidoscope-LEDControl](LEDControl.md)
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting
started with the plugin.
[plugin:example]: ../../examples/LED-AlphaSquare/LED-AlphaSquare.ino
## Upgrading
Former versions of the plugin used to have extra symbols in the
`kaleidoscope::alpha_square::symbols` namespace, while current versions have
them under `kaleidoscope::plugin::alpha_square::symbols`. The old name is
deprecated, and will be removed by 2019-01-14.

@ -0,0 +1,84 @@
# Kaleidoscope-LED-Stalker
The `StalkerEffect` plugin provides an interesting new typing experience: the
LEDs light up as you tap keys and play one of the selected effects: a haunting
trail of ghostly white lights, or a blazing trail of fire.
## Using the plugin
To use the plugin, one needs to include the header and select the effect.
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LED-Stalker.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDControl, StalkerEffect);
void setup (){
Kaleidoscope.setup();
StalkerEffect.variant = STALKER(Haunt, (CRGB(0, 128, 0)));
StalkerEffect.activate();
}
```
It is recommended to place the activation of the plugin (the `Kaleidoscope.use`
call) as early as possible, so the plugin can catch all relevant key presses.
The configuration can happen at any time and should use the `STALKER` macro to
do so.
## Plugin methods
The plugin provides the `StalkerEffect` object, which has the following
properties:
### `.variant`
> Set the effect to use with the plugin. See below for a list.
>
> It is recommended to use the `STALKER` macro to declare the effect itself.
### `.step_length`
> The length - in milliseconds - of each step of the animation. An animation
> lasts 256 steps.
>
> Defaults to 50.
## Plugin helpers
### `STALKER(effect, params)`
> Returns an effect, to be used to assign a value the `.variant` property of the
> `StalkerEffect` object. Any arguments given to the macro are passed on
> to the effect. If the effect takes no arguments, use an empty `params` list.
## Plugin effects
The plugin provides the following effects:
### `Haunt([color])`
> A ghostly haunt effect, that trails the key taps with a ghostly white color
> (or any other color, if specified). Use the `CRGB(r,g,b)` macro to specify the
> color, if you want something else than the ghostly white.
### `BlazingTrail()`
> A blazing trail of fire will follow our fingers!
### `Rainbow()`
> Leave a rainbow behind, where your fingers has been!
## Dependencies
* [Kaleidoscope-LEDControl](LEDControl.md)
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting
started with the plugin.
[plugin:example]: ../../examples/LED-Stalker/LED-Stalker.ino

@ -0,0 +1,19 @@
# Kaleidoscope-LEDControl
This is a plugin for [Kaleidoscope][fw], for controlling the LEDs, and LED
effects.
[fw]: https://github.com/keyboardio/Kaleidoscope
## Upgrading
The `LEDUtils.h` and `LED-Off.h` headers are now included by default when using
`<Kaleidoscope-LEDControl.h>`, and their explicit use is therefore deprecated.
The includes can be safely removed.
Compatibility headers are in place for both, but will be removed by 2019-01-14.
Furthermore, to implement LED modes, one should use
`kaleidoscope::plugin::LEDMode` as a base class now, instead of the former
`kaleidoscope::LEDMode`. There is a backwards compatible typedef, but like the
headers, it will be removed by 2019-01-14.

@ -0,0 +1,146 @@
# Kaleidoscope-LEDEffect-BootGreeting
If you want to have your keyboard signal when it turns on, but you don't want to
use any more complicated LED modes, this plugin is for you. It will make the
`LEDEffectNext` key on your keymap slowly breathe for about ten seconds after
plugging the keyboard in (without blocking the normal functionality of the
keyboard, of course).
## Using the plugin
To use the plugin, include the header, and tell `Kaleidoscope` to use the plugin:
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LEDEffect-BootGreeting.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
BootGreetingEffect
LEDOff);
void setup() {
Kaleidoscope.setup();
}
```
You may also set optional parameters.
### Specify by search key
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LEDEffect-BootGreeting.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
BootGreetingEffect
LEDOff);
void setup() {
Kaleidoscope.setup();
BootGreetingEffect.search_key = Key_M;
}
```
### Specify by position
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LEDEffect-BootGreeting.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
BootGreetingEffect
LEDOff);
void setup() {
Kaleidoscope.setup();
//Butterfly key
BootGreetingEffect.key_col = 7;
BootGreetingEffect.key_row = 3;
}
```
### Specify longer timeout
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LEDEffect-BootGreeting.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
BootGreetingEffect
LEDOff);
void setup() {
Kaleidoscope.setup();
//Butterfly key
BootGreetingEffect.timeout = 15000;
}
```
### Specify different color
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LEDEffect-BootGreeting.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
BootGreetingEffect
LEDOff);
void setup() {
Kaleidoscope.setup();
//Butterfly key
BootGreetingEffect.hue = 90;
Kaleidoscope.setup();
}
```
## Plugin methods
The plugin provides the `BootGreetingEffect` object, with the following methods and
properties:
### `.search_key`
> Set the key in the current keymap that should be activated with the pulsing
> LED on startup. The plugin will search from the top left to the bottom right
> of the keyboard, row by row, to find this key. The first matching key will
> be selected.
>
> Defaults to `Key_LEDEffectNext`
### `.key_row`
> This is an optional override to explicitly set the selected key by exact row
> and column. This number is 0-indexed, so the top row is 0, the second row is
> 1, etc. Must set `.key_col` property for this feature to be enabled.
### `.key_col`
> This is an optional override to explicitly set the selected key by exact row
> and column. This number is 0-indexed, so the left-most column is 0, the
> second column is 1, etc. Must set `.key_row` property for this feature to
> be enabled.
### `.timeout`
> This property specifies the timeout (in milliseconds) for the effect to last.
> When the keyboard is first connected, the pulsing LED effect will last for
> this duration before turning off.
>
> Defaults to `9200` ms.
### `.hue`
> This property sets the color hue that the LED pulsing effect.
>
> The default is `170`, which is a blue color.
## Dependencies
* [Kaleidoscope-LEDControl](LEDControl.md)

@ -0,0 +1,39 @@
# Kaleidoscope-LEDEffect-Breathe
Provides a breathing effect for the keyboard. Breathe in, breathe out.
## Using the extension
To use the plugin, include the header, and tell the firmware to use it:
```c++
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LEDEffect-Breathe.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
LEDBreatheEffect);
void setup() {
Kaleidoscope.setup();
}
```
## Plugin properties
The plugin provides the `LEDBreatheEffect` object, which has a single property:
### `.hue`
> The hue of the breathe effect.
>
> Defaults to 170, a blue hue.
### `.saturation`
> The color saturation of the breathe effect.
>
> Defaults to 255, the maximum.
## Dependencies
* [Kaleidoscope-LEDControl](LEDControl.md)

@ -0,0 +1,29 @@
# Kaleidoscope-LEDEffect-Chase
A simple LED effect where one color chases another across the keyboard and back,
over and over again. Playful colors they are.
## Using the extension
To use the plugin, include the header, and tell the firmware to use it:
```c++
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LEDEffect-Chase.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
LEDEffect-Chase);
void setup() {
Kaleidoscope.setup();
}
```
## Plugin methods
The plugin provides the `LEDChaseEffect` object, which has no public methods or
properties, outside of those provided by all LED modes.
## Dependencies
* [Kaleidoscope-LEDControl](LEDControl.md)

@ -0,0 +1,51 @@
# Kaleidoscope-LEDEffect-Rainbow
Two colorful rainbow effects are implemented by this plugin: one where the
rainbow waves through the keys, and another where the LEDs breathe though the
colors of a rainbow. The difference is that in the first case, we have all the
rainbow colors on display, and it waves through the keyboard. In the second
case, we have only one color at a time, for the whole board, and the color
cycles through the rainbow's palette.
## Using the extension
To use the plugin, include the header, and tell the firmware to use either (or
both!) of the effects:
```c++
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LEDEffect-Rainbow.h>
KALEIDOSCOPE_INIT_PLUGINS(LEDRainbowEffect, LEDRainbowWaveEffect);
void setup() {
Kaleidoscope.setup();
LEDRainbowEffect.brightness(150);
LEDRainbowWaveEffect.brightness(150);
LEDRainbowWaveEffect.update_delay(50);
}
```
## Plugin methods
The plugin provides two objects: `LEDRainbowEffect`, and `LEDRainbowWaveEffect`,
both of which provide the following methods:
### `.brightness([brightness])`
> Sets (or gets, if called without an argument) the LED brightness for the
> effect.
>
> Defaults to 50.
### `.update_delay([delay])`
> Sets (or gets, if called without an argument) the number of milliseconds
> between effect updates. Smaller number results in faster rainbows.
>
> Defaults to 40.
## Dependencies
* [Kaleidoscope-LEDControl](LEDControl.md)

@ -0,0 +1,33 @@
# Kaleidoscope-LEDEffect-SolidColor
This plugin provides tools to build LED effects that set the entire keyboard to
a single color. For show, and for backlighting purposes.
## Using the extension
To use the plugin, include the header, declare an effect using the
`kaleidoscope::plugin::LEDSolidColor` class, and tell the firmware to use the
new effect:
```c++
#include <Kaleidoscope-LEDEffect-SolidColor.h>
static kaleidoscope::plugin::LEDSolidColor solidRed(160, 0, 0);
KALEIDOSCOPE_INIT_PLUGINS(LEDControl, solidRed);
void setup() {
Kaleidoscope.setup();
}
```
## Dependencies
* [Kaleidoscope-LEDControl](LEDControl.md)
## Upgrading
Previous versions of `LEDEffect-SolidColor` used `kaleidoscope::LEDSolidColor`
as a class for defining solid-color effects. This is called
`kaleidoscope::plugin::LEDSolidColor` now. The old name still works, but is
deprecated, and will be removed by 2019-01-14.

@ -0,0 +1,183 @@
# Kaleidoscope-Macros
Macros are a standard feature on many keyboards and Kaleidoscope-powered ones
are no exceptions. Macros are a way to have a single key-press do a whole lot of
things under the hood: conventionally, macros play back a key sequence, but with
Kaleidoscope, there is much more we can do. Nevertheless, playing back a
sequence of events is still the primary use of macros.
Playing back a sequence means that when we press a macro key, we can have it
play pretty much any sequence. It can type some text for us, or invoke a
complicated shortcut - the possibilities are endless!
In Kaleidoscope, macros are implemented via this plugin. You can define upto 256 macros.
## Using the plugin
To use the plugin, we need to include the header, tell the firmware to `use` the
plugin, place macros on the keymap, and create a special handler function
(`macroAction`) that will tell the plugin what shall happen when macro keys are
pressed. It is best illustrated with an example:
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-Macros.h>
// Give a name to the macros!
enum {
MACRO_MODEL01,
MACRO_HELLO,
MACRO_SPECIAL,
};
// Somewhere in the keymap:
M(MACRO_MODEL01), M(MACRO_HELLO), M(MACRO_SPECIAL)
// later in the Sketch:
const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
switch (macroIndex) {
case MACRO_MODEL01:
return MACRODOWN(I(25),
D(LeftShift), T(M), U(LeftShift), T(O), T(D), T(E), T(L),
T(Spacebar),
W(100),
T(0), T(1) );
case MACRO_HELLO:
if (keyToggledOn(keyState)) {
return Macros.type(PSTR("Hello "), PSTR("world!"));
}
break;
case MACRO_SPECIAL:
if (keyToggledOn(keyState)) {
// Do something special
}
break;
}
return MACRO_NONE;
}
KALEIDOSCOPE_INIT_PLUGINS(Macros);
void setup() {
Kaleidoscope.setup ();
}
```
## Keymap markup
### `M(id)`
> Places a macro key on the keymap, with the `id` number (0 to 255) as identifier. Whenever this key
> has to be handled, the `macroAction` overrideable function will be called,
> with the identifier and key state as arguments.
>
> It is recommended to give a *name* to macro ids, by using an `enum`.
## Plugin methods
The plugin provides a `Macros` object, with the following methods and properties available:
### `.play(macro)`
> Plays back a macro, where a macro is a sequence created with the `MACRO()`
> helper discussed below. This method will be used by the plugin to play back
> the result of the `macroAction()` method, but is used rarely otherwise.
>
> The `macro` argument must be a sequence created with the `MACRO()` helper!
### `.type(strings...)`
> In cases where we only want to type some strings, it is far more convenient to
> use this method: we do not have to use the `MACRO()` helper, but just give
> this one a set of strings, and it will type them for us on the keyboard. We
> can use as many strings as we want, and all of them will be typed in order.
>
> Each string is limited to a sequence of printable ASCII characters. No
> international symbols, or unicode, or anything like it: just plain ASCII.
>
> Each of `strings` arguments must also reside in program memory, and the
> easiest way to do that is to wrap the string in a `PSTR()` helper. See the
> program code at the beginning of this documentation for an example!
### `.row`, `.col`
> The `row` and `col` properties describe the physical position a macro was
> triggered from if it was triggered by a key. The playback functions
> do not use these properties, but they are available, would one want to create
> a macro that needs to know which key triggered it.
>
> When the macro was not triggered by a key the value of these properties are
> unspecified.
## Macro helpers
Macros need to be able to simulate key down and key up events for any key - even
keys that may not be on the keymap otherwise. For this reason and others, we
need to define them in a special way, using the `MACRO` helper (or its
`MACRODOWN()` variant, see below):
### `MACRO(steps...)`
> Defines a macro, that is built up from `steps` (explained below). The plugin
> will iterate through the sequence, and re-play the steps in order.
>
> Note: In older versions of the Macros plugin, the sequence of steps had to end
> with a special step called END. This is no longer required. Existing macros
> that end with END will still work correctly, but new code should not use END;
> usage of END is deprecated.
### `MACRODOWN(steps...)`
> The same as the `MACRO()` helper above, but it will create a special sequence,
> where the steps are only played back when the triggering key was just pressed.
> That is, the macro will not be performed when the key is released, or held, or
> not pressed at all.
>
> Use this over `MACRO()` when you only want to perform an action when the key
> actuates, and no action should be taken when it is held, released, or when it
> is not pressed at all. For a lot of macros that emit a sequence without any
> other side effects, `MACRODOWN()` is usually the better choice.
>
> Can only be used from the `macroAction()` overrideable method.
## `MACRO` steps
Macro steps can be divided into two groups:
### Delays
* `I(millis)`: Sets the interval between steps to `millis`. By default, there is
no delay between steps, and they are played back as fast as possible. Useful
when we want to see the macro being typed, or need to slow it down, to allow
the host to process it.
* `W(millis)`: Waits for `millis` milliseconds. For dramatic effects.
### Key events
Key event steps have three variants: one that prefixes its argument with `Key_`,
one that does not, and a third that allows for a more compact - but also more
limited - representation. The first are the `D`, `U`, and `T` variants, the
second are `Dr`, `Ur`, and `Tr`, and the last variant are `Dc`, `Uc`, and `Tc`.
In most cases, one is likely use normal keys for the steps, so the `D`, `U`, and
`T` steps apply the `Key_` prefix. This allows us to write `MACRO(T(X))` instead
of `MACRO(Tr(Key_X))` - making the macro definition shorter, and more readable.
The compact variant (`Dc`, `Uc`, and `Tc`) prefix the argument with `Key_` too,
but unlike `D`, `U`, and `T`, they ignore the `flags` component of the key, and
as such, are limited to ordinary keys. Mouse keys, consumer- or system keys are
not supported by this compact representation.
* `D(key)`, `Dr(key)`, `Dc(key)`: Simulates a key being pressed (pushed down).
* `U(key)`, `Ur(key)`, `Uc(key)`: Simulates a key being released (going up).
* `T(key)`, `Tr(key)`, `Tc(key)`: Simulates a key being tapped (pressed first, then released).
## Overrideable methods
### `macroAction(macroIndex, keyState)`
> The `macroAction` method is the brain of the macro support in Kaleidoscope:
> this function tells the plugin what sequence to play when given a macro index
> and a key state.
>
> It should return a macro sequence, or `MACRO_NONE` if nothing is to be played
> back.

@ -0,0 +1,182 @@
# Kaleidoscope-MagicCombo
The `MagicCombo` extension provides a way to perform custom actions when a
particular set of keys are held down together. The functionality assigned to
these keys are not changed, and the custom action triggers as long as all keys
within the set are pressed. The order in which they were pressed do not matter.
This can be used to tie complex actions to key chords.
## Using the extension
To use the extension, we must include the header, create actions for the magic
combos we want to trigger, and set up a mapping:
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-Macros.h>
#include <Kaleidoscope-MagicCombo.h>
enum { KIND_OF_MAGIC };
void kindOfMagic(uint8_t combo_index) {
Macros.type(PSTR("It's a kind of magic!"));
}
USE_MAGIC_COMBOS(
[KIND_OF_MAGIC] = {
.action = kindOfMagic,
.keys = {R3C6, R3C9} // Left Fn + Right Fn
});
KALEIDOSCOPE_INIT_PLUGINS(MagicCombo, Macros);
void setup() {
Kaleidoscope.setup();
}
```
It is recommended to use the `RxCy` macros of the core firmware to set the keys
that are part of a combination.
## Plugin properties
The extension provides a `MagicCombo` singleton object, with the following
property:
### `.min_interval`
> Restrict the magic action to fire at most once every `min_interval`
> milliseconds.
>
> Defaults to 500.
## Plugin callbacks
Whenever a combination is found to be held, the plugin will trigger the
specified action, which is just a regular method with a single `uint8_t`
argument: the index of the magic combo. This function will be called repeatedly
(every `min_interval` milliseconds) while the combination is held.
## Further reading
Starting from the [example][plugin:example] is the recommended way of getting
started with the plugin.
`RxCy` coordinates for a Model01:
![rxcy layout](../model01_coordinates.png)
[plugin:example]: ../../examples/MagicCombo/MagicCombo.ino
## Upgrading
To make `MagicCombo` more portable, and easier to use, we had to break the API
previously provided, there was no way to maintain backwards compatibility. This
document is an attempt at guiding you through the process of migrating from the
earlier API to the current one.
Migration should be a straightforward process, but if you get stuck, please feel
free to [open an issue][gh:issues], or start a thread on the [forums][forums],
and we'll help you with it.
[gh:issues]: https://github.com/keyboardio/Kaleidoscope/issues
[forums]: https://community.keyboard.io/
## The old API
```c++
void magicComboActions(uint8_t combo_index, uint32_t left_hand, uint32_t right_hand) {
switch (combo_index) {
case 0:
Macros.type(PSTR("It's a kind of magic!"));
break;
}
}
static const kaleidoscope::MagicCombo::combo_t magic_combos[] PROGMEM = {
{
R3C6, // left palm key
R3C9 // right palm key
},
{0, 0}
};
void setup() {
Kaleidoscope.setup();
MagicCombo.magic_combos = magic_combos;
}
```
Previously, we used a global, overrideable function (`magicComboActions`) to run
the actions of all magic combos, similar to how macros are set up to work.
Unlike macros, magic combos can't be defined in the keymap, due to technical
reasons, so we had to use a separate list - `magic_combos` in our example. We
also needed to tell `MagicCombo` to use this list, which is what we've done in
`setup()`.
## The new API
```c++
void kindOfMagic(uint8_t combo_index) {
Macros.type(PSTR("It's a kind of magic!"));
}
USE_MAGIC_COMBOS({
.action = kindOfMagic,
.keys = {R3C6, R3C9} // Left Fn + Right Fn
});
```
The new API is much shorter, and is inspired by the way the [Leader][leader]
plugin works: instead of having a list, and a dispatching function like
`magicComboActions`, we include the action method in the list too!
[leader]: Leader.md
We also don't make a difference between left- and right-hand anymore, you can
just list keys for either in the same list. This will be very handy for
non-split keyboards.
## Migration
First of all, we'll need to split up `magicComboActions` into separate
functions. Each function should have a unique name, but their shape is always
the same:
```c++
void someFunction(uint8_t combo_index) {
// Do some action here
}
```
Copy the body of each `case` statement of `magicComboActions`, and copy them one
by one into appropriately named functions of the above shape. You can name your
functions anything you want, the only constraint is that they need to be valid
C++ function names. The plugin itself does nothing with the name, we'll
reference them later in the `USE_MAGIC_COMBOS` helper macro.
Once `magicComboActions` is split up, we need to migrate the `magic_combos` list
to the new format. That list had to be terminated by a `{0, 0}` entry, the new
method does not require such a sentinel at the end.
For each entry in `magic_combos`, add an entry to `USE_MAGIC_COMBOS`, with the
following structure:
```c++
{.action = theActionFunction,
.keys = { /* list of keys */ }}
```
The list of keys are the same `RxCy` constants you used for `magic_combos`, with
the left- and right hands combined. The action, `theActionFunction`, is the
function you extracted the magic combo action to. It's the function that has the
same body as the `case` statement in `magicComboActions` had.
And this is all there is to it.
If your actions made use of the `left_hand` or `right_hand` arguments of
`magicComboActions`, the same information is still available. But that's a bit
more involved to get to, out of scope for this simple migration guide. Please
open an issue, or ask for help on the forums, and we'll help you.

@ -0,0 +1,246 @@
# Kaleidoscope-MouseKeys
Have you ever wanted to control the mouse cursor from the comfort of your
keyboard? With this plugin, you can. While it may not replace the mouse in all
situations, there are plenty of cases where one will not have to lift their
hands off the keyboard just to nudge the mouse cursor away a little.
Of course, there are a lot more one can do with the plugin than to nudge the
cursor! Mouse keys are provided for all four *and* diagonal movement; mouse
buttons; and a unique warping mechanism too. And not only these: the speed of
the cursor, the mouse wheel, and that of acceleration can all be configured to
match one's desired behaviour.
## Using the plugin
To use the plugin, simply include the header in your Sketch, tell the firmware
to use the `MouseKeys` object, and place mouse keys on your keymap. It is best
illustrated with an example:
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-MouseKeys.h>
// Somewhere in the keymap:
Key_mouseUp, Key_mouseDn, Key_mouseL, Key_mouseR,
Key_mouseBtnL, Key_mouseBtnR
KALEIDOSCOPE_INIT_PLUGINS(MouseKeys);
void setup() {
Kaleidoscope.setup ();
}
```
## Keys provided by the plugin
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:
### Cursor movement
The simplest set of keys are the mouse cursor movement keys. These move the
cursor one direction or the other, with speed and acceleration factored in. When
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:
* `Key_mouseUp`, `Key_mouseDn`, `Key_mouseL`, `Key_mouseR`: Move the cursor up,
down, left, or right, respectively.
* `Key_mouseUpL`, `Key_mouseUpR`, `Key_mouseDnL`, `Key_mouseDnR`: Move the
cursor up-left, up-right, down-left, down-right, respectively.
### Scroll wheel
Controlling the scroll wheel is similarly simple. It does not have acceleration,
but one can control the speed with the `.wheelSpeed` and `.wheelDelay`
properties (see below).
* `Key_mouseScrollUp`, `Key_mouseScrollDn`: Scroll the mouse wheel up or down,
respectively.
* `Key_mouseScrollL`, `Key_mouseScrollR`: Scroll the mouse wheel left or right,
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 is one of the most interesting features of the plugin, and is a feature
unique to Kaleidoscope, as far as we can tell. The warping keys position the
mouse cursor within a sector of the screen on first press, and any subsequent
taps will warp within the previously selected sector. For example, pressing the
north-west warp key twice will first jump to the middle of the north-west
sector of your screen, then select the north-west sector of that, and jump to
the middle of it.
To stop warping, use any other mouse key, or hit the "warp end" key.
### Warp grid size
The warp grid size determines how MouseKeys partitions the screen to select the
next position to jump to when pressing a warp key. The plugin provides two grid
sizes to choose from: a *2x2* grid that splits the screen into quadrants, and a
*3x3* grid with nine cells similar to a navigation feature included with some
speech recognition software. By default, the plugin splits the screen into the
2x2 grid.
To change the warp grid size, call the plugin's `setWarpGridSize()` method:
```c++
MouseKeys.setWarpGridSize(MOUSE_WARP_GRID_3X3);
```
#### 2x2 grid
As described above, MouseKeys warps the pointer using a grid model that reflects
locations on the screen. By default, the plugin uses a 2x2 grid. To understand
how warping works, examine this diagram of a screen split into that 2x2 grid:
+-----------------------|-----------------------+
| | | |
| G | tab | |
| | | |
|-----------|-----------| tab |
| | | |
| B | esc | |
| | | |
+-----------------------|-----------------------+
| | |
| | |
| | |
| B | esc |
| | |
| | |
| | |
+-----------------------|-----------------------+
Each quadrant is labed with a key that, when pressed, moves the mouse pointer
to the center of that quadrant. With this layout, pressing <kbd>G</kbd> warps
the pointer to the top-left quadant. Then, the plugin "zooms" into that sector
with a smaller grid so that the next warp key pressed jumps the pointer more
precisely within the sector. In this case, if we press <kbd>esc</kbd> next,
the pointer warps to the bottom-right corner within that quadrant.
The warping keys for the 2x2 grid are the following:
* `Key_mouseWarpNW`, `Key_mouseWarpNE`, `Key_mouseWarpSW`, `Key_mouseWarpSE`:
Warp towards the north-west, north-east, south-west, or south-east quadrants,
respectively.
* `Key_mouseWarpEnd`: End the warping sequence, resetting it to the default
state. Using any of the warping keys after this will start from the whole
screen again.
#### 3x3 grid
A 3x3 warp grid assigns a key to each of nine sectors of the screen. The next
diagram shows a screen with a key label that warps to each sector. As we can
see, pressing <kbd>W</kbd> warps the pointer into the top-left sector, and
pressing <kbd>V</kbd> warps to the bottom-right corner within that sector:
+-----------------|-----------------|-----------------+
| W | E | R | | |
|-----|-----|-----| | |
| S | D | F | E | R |
|-----|-----|-----| | |
| X | C | V | | |
+-----------------|-----------------|-----------------+
| | | |
| | | |
| S | D | F |
| | | |
| | | |
+-----------------|-----------------|-----------------+
| | | |
| | | |
| X | C | V |
| | | |
| | | |
+-----------------|-----------------|-----------------+
To use a 3x3 warp grid, we may need to remap some keys. A suggested warp key
mapping is shown below on the left side of a keyboard with a QWERTY layout:
W | E | R T A - End Warping (Key_mouseWarpEnd)
---|---|--- W - Warp NW Sector (Key_mouseWarpNW)
A S | D | F G E - Warp N Sector (Key_mouseWarpN)
---|---|--- R - Warp NE Sector (Key_mouseWarpNE)
X | C | V B S - Warp E Sector (Key_mouseWarpE)
D - Warp/Zoom Center (Key_mouseWarpIn)
F - Warp W Sector (Key_mouseWarpW)
K - Warp SE Sector (Key_mouseWarpSE)
C - Warp S Sector (Key_mouseWarpS)
V - Warp SW Sector (Key_mouseWarpSW)
T - Right Click (Key_mouseBtnR)
G - Left Click (Key_mouseBtnL)
B - Middle Click (Key_mouseBtnM)
This example layout replaces the default directional mouse keys and sets the
warp keys in a comfortable position for a warp-only configuration. Of course,
a Kaleidoscope user may retain the directional keys and map the warp keys
elsewhere according to his or her liking.
A 3x3 warp grid layout contains all of the keys from the 2x2 grid layout with
the following additions:
* `Key_mouseWarpN`, `Key_mouseWarpE`, `Key_mouseWarpS`, `Key_mouseWarpW`:
Warp towards the north, east, south, and west sectors, respectively.
* `Key_mouseWarpIn`: Warp to the center sector of the grid. The plugin will
continue to "zoom" into center of the current cell with each consecutive
press of this key.
## Plugin methods
The plugin provides a `MouseKeys` object, with the following methods and
properties available:
### `.speed` and `.speedDelay`
> These two control the speed of the mouse cursor, when a movement key is held.
> The former, `.speed`, controls the amount of pixels the cursor moves, when it
> has to move, and defaults to 1. The latter, `.speedDelay` is the amount of
> time - in milliseconds - to wait between two movements, and defaults to 0, no
> delay.
### `.accelSpeed` and `.accelDelay`
> These two properties control the speed of acceleration. The former,
> `.accelSpeed`, controls how much the speed shall be increased at each step,
> while the second, `.accelDelay`, controls how often (in milliseconds)
> acceleration should be applied.
>
> They default to 1 pixel and 50 milliseconds, respectively.
### `.wheelSpeed` and `.wheelDelay`
> The last two properties supported by the plugin control the mouse wheel
> scrolling speed. The former, `.wheelSpeed`, controls the amount of ticks the
> wheel shall scroll, and defaults to 1. The second, `.wheelDelay`, controls the
> delay between two scroll events, and defaults to 50 milliseconds.
### `.setSpeedLimit`
> This method sets the maximum speed after which acceleration stops.
> The default is 127, and the minimum value is 16 (things will not work
> properly below 16).
### `.setWarpGridSize`
> 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`

@ -0,0 +1,39 @@
# Kaleidoscope-NumPad
This is a plugin for [Kaleidoscope][fw], that adds a NumPad-specific LED
effect, along with a way to toggle to a numpad layer, and apply the effect.
## Using the extension
To use the plugin, include the header, and tell the firmware to use it:
```c++
#include "Kaleidoscope-NumPad.h"
KALEIDOSCOPE_INIT_PLUGINS(NumPad);
void setup() {
Kaleidoscope.setup();
NumPad.color = CRGB(0, 0, 160); // a blue color
NumPad.lock_hue = 85; // green
}
```
## Plugin methods
The plugin provides the `NumPad` object, with the following properties:
### `.color`
> This property sets the color that the NumPad keys are highlighted in.
>
> The default is `CRGB(160, 0, 0)`, a red color.
### `.lock_hue`
> This property sets the color hue that the NumLock LED breathes in.
>
> The default is `170`, a blue hue.
[fw]: https://github.com/keyboardio/Kaleidoscope

@ -0,0 +1,39 @@
# Kaleidoscope-USB-Quirks
USB-Quirks provides a few methods to deal with more obscure parts of the USB spec, such as changing between `Boot` and `Report` protocols. These are in a separate plugin, because these features are not part of the USB spec, and are often workarounds for various issues. See the provided methods for more information about what they're useful for.
## Using the plugin
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-Macros.h>
#include <Kaleidoscope-USB-Quirks.h>
KALEIDOSCOPE_INIT_PLUGINS(USBQuirks, Macros);
const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
if (macroIndex == 0) {
USBQuirks.toggleKeyboardProtocol();
}
return MACRO_NONE;
}
void setup() {
Kaleidoscope.setup();
}
```
## Plugin methods
The plugin provides one object, `USBQuirks`, which provides the following method:
### `.toggleKeyboardProtocol()`
> Toggle between `Boot` and `Report` protocol by detaching, and then
> re-attaching the USB devices, and setting the `BootKeyboard` protocol
> inbetween.
>
> This is most useful when one needs to have a boot keyboard, when one's in a
> BIOS, boot loader, or early password prompt or the like, and the host does not
> explicitly request the boot protocol for one reason or the other. With this
> toggle, we can switch between the two on-demand.

@ -16,8 +16,9 @@
*/
#include "Kaleidoscope.h"
#include "Kaleidoscope-EEPROM-Settings.h"
#include "Kaleidoscope-Macros.h"
#include "Kaleidoscope-HostOS.h"
#include "Kaleidoscope/HostOS-select.h"
#include "Macros.h"
@ -54,7 +55,8 @@ const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
return MACRO_NONE;
}
KALEIDOSCOPE_INIT_PLUGINS(HostOS,
KALEIDOSCOPE_INIT_PLUGINS(EEPROMSettings,
HostOS,
Macros);
void setup() {

@ -0,0 +1,53 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Keymap -- EEPROM-based keymap support.
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-EEPROM-Keymap.h>
#include <Kaleidoscope-FocusSerial.h>
// *INDENT-OFF*
KEYMAPS(
[0] = KEYMAP_STACKED
(Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_skip,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
Key_skip),
)
// *INDENT-ON*
KALEIDOSCOPE_INIT_PLUGINS(EEPROMKeymap, Focus);
void setup() {
Kaleidoscope.setup();
EEPROMKeymap.setup(1, EEPROMKeymap.Mode::EXTEND);
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,59 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Settings -- Basic EEPROM settings plugin for Kaleidoscope.
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-EEPROM-Settings.h>
// *INDENT-OFF*
const Key keymaps[][ROWS][COLS] PROGMEM = {
[0] = KEYMAP_STACKED
(Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_skip,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
Key_skip),
};
// *INDENT-ON*
KALEIDOSCOPE_INIT_PLUGINS(EEPROMSettings);
void setup() {
Serial.begin(9600);
Kaleidoscope.setup();
while (!Serial) {
}
Serial.println(EEPROMSettings.isValid() ? F("valid EEPROM settings") : F("invalid EEPROM settings"));
Serial.println(EEPROMSettings.crc(), HEX);
Serial.println(EEPROMSettings.version());
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,86 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FocusSerial -- Bidirectional communication plugin
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-FocusSerial.h>
// *INDENT-OFF*
const Key keymaps[][ROWS][COLS] PROGMEM = {
[0] = KEYMAP_STACKED
(Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_skip,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
Key_skip),
};
// *INDENT-OFF*
namespace kaleidoscope {
class FocusTestCommand : public Plugin {
public:
FocusTestCommand() {}
EventHandlerResult onFocusEvent(const char *command) {
const char *cmd = PSTR("test");
if (::Focus.handleHelp(command, cmd))
return EventHandlerResult::OK;
if (strcmp_P(command, cmd) == 0) {
Serial.println(F("ok!"));
return EventHandlerResult::EVENT_CONSUMED;
}
return EventHandlerResult::OK;
}
};
class FocusHelpCommand : public Plugin {
public:
FocusHelpCommand() {}
EventHandlerResult onFocusEvent(const char *command) {
::Focus.handleHelp(command, PSTR("help"));
return EventHandlerResult::OK;
}
};
}
kaleidoscope::FocusTestCommand FocusTestCommand;
kaleidoscope::FocusHelpCommand FocusHelpCommand;
KALEIDOSCOPE_INIT_PLUGINS(Focus, FocusTestCommand, FocusHelpCommand);
void setup() {
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,71 @@
/* -*- mode: c++ -*-
* Kaleidoscope-HostPowerManagement -- Host power management support plugin.
* Copyright (C) 2017, 2018 Gergely Nagy
*
* 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/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-HostPowerManagement.h>
// *INDENT-OFF*
const Key keymaps[][ROWS][COLS] PROGMEM = {
[0] = KEYMAP_STACKED
(
Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_NoKey,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
Key_NoKey
),
};
// *INDENT-ON*
void hostPowerManagementEventHandler(kaleidoscope::plugin::HostPowerManagement::Event event) {
switch (event) {
case kaleidoscope::plugin::HostPowerManagement::Suspend:
LEDControl.paused = true;
LEDControl.set_all_leds_to({0, 0, 0});
LEDControl.syncLeds();
break;
case kaleidoscope::plugin::HostPowerManagement::Resume:
LEDControl.paused = false;
LEDControl.refreshAll();
break;
case kaleidoscope::plugin::HostPowerManagement::Sleep:
break;
}
}
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
HostPowerManagement);
void setup() {
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

@ -17,13 +17,12 @@
#define DEBUG_SERIAL false
#include "Kaleidoscope.h"
#include "Kaleidoscope-MouseKeys.h"
#include "Kaleidoscope-Macros.h"
#include "Kaleidoscope-LEDControl.h"
#include "Kaleidoscope-NumPad.h"
#include "Kaleidoscope.h"
#include "LED-Off.h"
#include "Kaleidoscope-LEDEffect-SolidColor.h"
#include "Kaleidoscope-LEDEffect-Breathe.h"
#include "Kaleidoscope-LEDEffect-Chase.h"

@ -0,0 +1,110 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-AlphaSquare -- 4x4 pixel LED alphabet
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LED-AlphaSquare.h>
#include <Kaleidoscope-Macros.h>
// *INDENT-OFF*
const Key keymaps[][ROWS][COLS] PROGMEM = {
[0] = KEYMAP_STACKED
(
Key_LEDEffectNext, Key_1, Key_2, Key_3, Key_4, Key_5, M(0),
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,
Key_skip,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
Key_skip),
};
// *INDENT-ON*
const macro_t *macroAction(uint8_t macro_index, uint8_t key_state) {
if (!keyToggledOn(key_state))
return MACRO_NONE;
if (macro_index == 0) {
for (uint8_t i = Key_A.keyCode; i <= Key_0.keyCode; i++) {
LEDControl.set_all_leds_to(0, 0, 0);
LEDControl.syncLeds();
delay(100);
uint8_t col = 2;
if (i % 2)
col = 10;
for (uint8_t step = 0; step <= 0xf0; step += 8) {
AlphaSquare.color = { step, step, step };
AlphaSquare.display({i, 0}, col);
delay(10);
}
for (uint8_t step = 0xff; step >= 8; step -= 8) {
AlphaSquare.color = { step, step, step };
AlphaSquare.display({i, 0}, col);
delay(10);
}
delay(100);
}
LEDControl.set_all_leds_to(0, 0, 0);
LEDControl.syncLeds();
delay(100);
for (uint8_t step = 0; step <= 0xf0; step += 8) {
AlphaSquare.color = { step, step, step };
AlphaSquare.display(kaleidoscope::plugin::alpha_square::symbols::Lambda, 2);
AlphaSquare.display(kaleidoscope::plugin::alpha_square::symbols::Lambda, 10);
delay(10);
}
for (uint8_t step = 0xff; step >= 8; step -= 8) {
AlphaSquare.color = { step, step, step };
AlphaSquare.display(kaleidoscope::plugin::alpha_square::symbols::Lambda, 2);
AlphaSquare.display(kaleidoscope::plugin::alpha_square::symbols::Lambda, 10);
delay(10);
}
delay(100);
}
LEDControl.set_all_leds_to(0, 0, 0);
return MACRO_NONE;
}
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
AlphaSquare,
AlphaSquareEffect,
Macros);
void setup() {
Kaleidoscope.setup();
AlphaSquare.color = { 0xcb, 0xc0, 0xff };
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,57 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-Stalker -- Stalk keys pressed by lighting up and fading back the LED under them
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LED-Stalker.h>
// *INDENT-OFF*
const Key keymaps[][ROWS][COLS] PROGMEM = {
[0] = KEYMAP_STACKED
(
Key_LEDEffectNext, 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,
Key_NoKey,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
Key_NoKey),
};
// *INDENT-ON*
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
LEDOff,
StalkerEffect);
void setup() {
Kaleidoscope.setup();
StalkerEffect.variant = STALKER(BlazingTrail);
StalkerEffect.activate();
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,54 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LEDEffect-BootGreeting -- Small greeting at boot time
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#include <Kaleidoscope-LEDEffect-BootGreeting.h>
// *INDENT-OFF*
const Key keymaps[][ROWS][COLS] PROGMEM = {
[0] = KEYMAP_STACKED
(
Key_LEDEffectNext, 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,
Key_NoKey,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
Key_NoKey),
};
// *INDENT-ON*
KALEIDOSCOPE_INIT_PLUGINS(LEDControl,
BootGreetingEffect,
LEDOff);
void setup() {
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,62 @@
/* -*- mode: c++ -*-
* Kaleidoscope-MagicCombo -- Magic combo framework
* Copyright (C) 2016, 2017, 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/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-Macros.h>
#include <Kaleidoscope-MagicCombo.h>
enum {
KIND_OF_MAGIC
};
void kindOfMagic(uint8_t combo_index) {
Macros.type(PSTR("It's a kind of magic!"));
}
USE_MAGIC_COMBOS([KIND_OF_MAGIC] = {.action = kindOfMagic, .keys = {R3C6, R3C9}});
// *INDENT-OFF*
const Key keymaps[][ROWS][COLS] PROGMEM = {
[0] = KEYMAP_STACKED
(
Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_NoKey,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_RightAlt, Key_Spacebar, Key_RightControl,
Key_NoKey),
};
// *INDENT-ON*
KALEIDOSCOPE_INIT_PLUGINS(MagicCombo, Macros);
void setup() {
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

@ -0,0 +1,20 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Keymap -- EEPROM-based keymap support.
* Copyright (C) 2017 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/EEPROM-Keymap.h>

@ -0,0 +1,20 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Settings -- Basic EEPROM settings plugin for Kaleidoscope.
* Copyright (C) 2017 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/EEPROM-Settings.h>

@ -0,0 +1,20 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FocusSerial -- Bidirectional communication plugin
* Copyright (C) 2017, 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/>.
*/
#pragma once
#include <kaleidoscope/plugin/FocusSerial.h>

@ -0,0 +1,20 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Model01 -- Keyboard.io Model01 hardware support for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "kaleidoscope/hardware/Model01.h"

@ -0,0 +1,21 @@
/* -*- mode: c++ -*-
* Kaleidoscope-HostPowerManagement -- Host power management support plugin.
* Copyright (C) 2017 Gergely Nagy
*
* 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/>.
*/
#pragma once
#include <kaleidoscope/plugin/HostPowerManagement.h>

@ -0,0 +1,22 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-AlphaSquare -- 4x4 pixel LED alphabet
* Copyright (C) 2017 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/LED-AlphaSquare.h>
#include <kaleidoscope/plugin/LED-AlphaSquare/Effect.h>
#include <kaleidoscope/plugin/LED-AlphaSquare/Symbols.h>

@ -0,0 +1,20 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-Stalker -- Stalk keys pressed by lighting up and fading back the LED under them
* Copyright (C) 2017 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/LED-Stalker.h>

@ -0,0 +1,21 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#pragma once
#include <kaleidoscope/plugin/LEDControl.h>
#include <kaleidoscope/plugin/LEDControl/LEDUtils.h>
#include <kaleidoscope/plugin/LEDControl/LED-Off.h>

@ -0,0 +1,20 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LEDEffect-BootGreeting -- Small greeting at boot time
* Copyright (C) 2017, 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/>.
*/
#pragma once
#include "kaleidoscope/plugin/LEDEffect-BootGreeting.h"

@ -0,0 +1,19 @@
/* Kaleidoscope-LEDEffect-Breathe - A breathing effect on the LEDs, for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "kaleidoscope/plugin/LEDEffect-Breathe.h"

@ -0,0 +1,19 @@
/* Kaleidoscope-LEDEffect-Chase - A Chase LED effect for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "kaleidoscope/plugin/LEDEffect-Chase.h"

@ -0,0 +1,19 @@
/* Kaleidoscope-LEDEffect-Rainbow - Rainbow LED effects for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "kaleidoscope/plugin/LEDEffect-Rainbow.h"

@ -0,0 +1,19 @@
/* Kaleidoscope-LEDEffect-SolidColor - Solid color LED effects for Kaleidoscope.
* Copyright (C) 2017 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/LEDEffect-SolidColor.h"

@ -0,0 +1,19 @@
/* Kaleidoscope-Macros - Macro keys for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "kaleidoscope/plugin/Macros.h"

@ -0,0 +1,20 @@
/* -*- mode: c++ -*-
* Kaleidoscope-MagicCombo -- Magic combo framework
* Copyright (C) 2016, 2017 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/MagicCombo.h>

@ -0,0 +1,19 @@
/* Kaleidoscope-Model01-TestMode - A factory test mode for the Model 01.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "kaleidoscope/plugin/Model01-TestMode.h"

@ -0,0 +1,19 @@
/* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "kaleidoscope/plugin/MouseKeys.h"

@ -0,0 +1,19 @@
/* Kaleidoscope-NumPad - A NumPad plugin for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "kaleidoscope/plugin/NumPad.h"

@ -0,0 +1,21 @@
/* -*- mode: c++ -*-
* Kaleidoscope-USB-Quirks -- USB Quirks for Kaleidoscope
* Copyright (C) 2018 Gergely Nagy
*
* 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/>.
*/
#pragma once
#include <kaleidoscope/plugin/USB-Quirks.h>

@ -0,0 +1,21 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#pragma once
#warning The "LED-Off.h" header is deprecated, the mode is included by default when using <Kaleidoscope-LEDControl.h>. It can be safely removed.
#include "kaleidoscope/plugin/LEDControl/LED-Off.h"

@ -0,0 +1,21 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#pragma once
#warning The "LEDUtils.h" header is deprecated, the mode is included by default when using <Kaleidoscope-LEDControl.h>. It can be safely removed.
#include "kaleidoscope/plugin/LEDControl/LEDUtils.h"

@ -0,0 +1,21 @@
/* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#warning The "MouseWrapper.h" header is deprecated, the same functionality is included by default when using <Kaleidoscope-MouseKeys.h>. It can be safely removed.
#include "kaleidoscope/plugin/MouseKeys/MouseWrapper.h"

@ -0,0 +1,316 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Model01 -- Keyboard.io Model01 hardware support for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#include <Kaleidoscope.h>
#include <KeyboardioHID.h>
#include <avr/wdt.h>
namespace kaleidoscope {
namespace hardware {
KeyboardioScanner Model01::leftHand(0);
KeyboardioScanner Model01::rightHand(3);
bool Model01::isLEDChanged = true;
keydata_t Model01::leftHandMask;
keydata_t Model01::rightHandMask;
static constexpr uint8_t key_led_map[4][16] = {
{3, 4, 11, 12, 19, 20, 26, 27, 36, 37, 43, 44, 51, 52, 59, 60},
{2, 5, 10, 13, 18, 21, 25, 28, 35, 38, 42, 45, 50, 53, 58, 61},
{1, 6, 9, 14, 17, 22, 24, 29, 34, 39, 41, 46, 49, 54, 57, 62},
{0, 7, 8, 15, 16, 23, 31, 30, 33, 32, 40, 47, 48, 55, 56, 63},
};
Model01::Model01(void) {
}
void Model01::enableScannerPower(void) {
// PC7
//pinMode(13, OUTPUT);
//digitalWrite(13, HIGH);
// Turn on power to the LED net
DDRC |= _BV(7);
PORTC |= _BV(7);
}
// This lets the keyboard pull up to 1.6 amps from
// the host. That violates the USB spec. But it sure
// is pretty looking
void Model01::enableHighPowerLeds(void) {
// PE6
// pinMode(7, OUTPUT);
// digitalWrite(7, LOW);
DDRE |= _BV(6);
PORTE &= ~_BV(6);
// Set B4, the overcurrent check to an input with an internal pull-up
DDRB &= ~_BV(4); // set bit, input
PORTB &= ~_BV(4); // set bit, enable pull-up resistor
}
void Model01::setup(void) {
wdt_disable();
delay(100);
enableScannerPower();
// Consider not doing this until 30s after keyboard
// boot up, to make it easier to rescue things
// in case of power draw issues.
enableHighPowerLeds();
leftHandState.all = 0;
rightHandState.all = 0;
TWBR = 12; // This is 400mhz, which is the fastest we can drive the ATTiny
}
void Model01::setCrgbAt(uint8_t i, cRGB crgb) {
if (i < 32) {
cRGB oldColor = getCrgbAt(i);
isLEDChanged |= !(oldColor.r == crgb.r && oldColor.g == crgb.g && oldColor.b == crgb.b);
leftHand.ledData.leds[i] = crgb;
} else if (i < 64) {
cRGB oldColor = getCrgbAt(i);
isLEDChanged |= !(oldColor.r == crgb.r && oldColor.g == crgb.g && oldColor.b == crgb.b);
rightHand.ledData.leds[i - 32] = crgb;
} else {
// TODO(anyone):
// how do we want to handle debugging assertions about crazy user
// code that would overwrite other memory?
}
}
void Model01::setCrgbAt(byte row, byte col, cRGB color) {
setCrgbAt(key_led_map[row][col], color);
}
uint8_t Model01::getLedIndex(byte row, byte col) {
return key_led_map[row][col];
}
cRGB Model01::getCrgbAt(uint8_t i) {
if (i < 32) {
return leftHand.ledData.leds[i];
} else if (i < 64) {
return rightHand.ledData.leds[i - 32] ;
} else {
return {0, 0, 0};
}
}
void Model01::syncLeds() {
if (!isLEDChanged)
return;
leftHand.sendLEDData();
rightHand.sendLEDData();
leftHand.sendLEDData();
rightHand.sendLEDData();
leftHand.sendLEDData();
rightHand.sendLEDData();
leftHand.sendLEDData();
rightHand.sendLEDData();
isLEDChanged = false;
}
boolean Model01::ledPowerFault() {
if (PINB & _BV(4)) {
return true;
} else {
return false;
}
}
void debugKeyswitchEvent(keydata_t state, keydata_t previousState, uint8_t keynum, uint8_t row, uint8_t col) {
if (bitRead(state.all, keynum) != bitRead(previousState.all, keynum)) {
Serial.print("Looking at row ");
Serial.print(row);
Serial.print(", col ");
Serial.print(col);
Serial.print(" key # ");
Serial.print(keynum);
Serial.print(" ");
Serial.print(bitRead(previousState.all, keynum));
Serial.print(" -> ");
Serial.print(bitRead(state.all, keynum));
Serial.println();
}
}
void Model01::readMatrix() {
//scan the Keyboard matrix looking for connections
previousLeftHandState = leftHandState;
previousRightHandState = rightHandState;
if (leftHand.readKeys()) {
leftHandState = leftHand.getKeyData();
}
if (rightHand.readKeys()) {
rightHandState = rightHand.getKeyData();
}
}
void Model01::actOnHalfRow(byte row, byte colState, byte colPrevState, byte startPos) {
if ((colState != colPrevState) || (colState != 0)) {
for (byte col = 0; col < 8; col++) {
// Build up the key state for row, col
uint8_t keyState = ((bitRead(colPrevState, 0) << 0) |
(bitRead(colState, 0) << 1));
if (keyState)
handleKeyswitchEvent(Key_NoKey, row, startPos - col, keyState);
// Throw away the data we've just used, so we can read the next column
colState = colState >> 1;
colPrevState = colPrevState >> 1;
}
}
}
void Model01::actOnMatrixScan() {
for (byte row = 0; row < 4; row++) {
actOnHalfRow(row, leftHandState.rows[row], previousLeftHandState.rows[row], 7);
actOnHalfRow(row, rightHandState.rows[row], previousRightHandState.rows[row], 15);
}
}
void Model01::scanMatrix() {
readMatrix();
actOnMatrixScan();
}
void Model01::rebootBootloader() {
// Set the magic bits to get a Caterina-based device
// to reboot into the bootloader and stay there, rather
// than run move onward
//
// These values are the same as those defined in
// Caterina.c
uint16_t bootKey = 0x7777;
uint16_t *const bootKeyPtr = reinterpret_cast<uint16_t *>(0x0800);
// Stash the magic key
*bootKeyPtr = bootKey;
// Set a watchdog timer
wdt_enable(WDTO_120MS);
while (1) {} // This infinite loop ensures nothing else
// happens before the watchdog reboots us
}
// In the maskKey(), unMaskKey(), and isKeyMasked() functions, we read and write bits in
// two bitfields -- one for each half of the keyboard. The fourth bit of the column number
// tells us which bitfield (right or left) to access, thus the "8" (B00001000). The row
// number tells us which element of the array to access. The last three bits of the column
// number tell us which of the eight bits to access, thus the "7" (B00000111), and we
// shift a bit starting from the left (B10000000, or 128) by that many places to get
// there. This is all nice and convenient because the keyboard has 64 keys, in symmetric
// halves, with eight keys per logical row.
constexpr byte HIGH_BIT = B10000000;
constexpr byte HAND_BIT = B00001000;
constexpr byte ROW_BITS = B00110000;
constexpr byte COL_BITS = B00000111;
void Model01::maskKey(byte row, byte col) {
if (row >= ROWS || col >= COLS)
return;
if (col & HAND_BIT) {
rightHandMask.rows[row] |= (HIGH_BIT >> (col & COL_BITS));
} else {
leftHandMask.rows[row] |= (HIGH_BIT >> (col & COL_BITS));
}
}
void Model01::unMaskKey(byte row, byte col) {
if (row >= ROWS || col >= COLS)
return;
if (col & HAND_BIT) {
rightHandMask.rows[row] &= ~(HIGH_BIT >> (col & COL_BITS));
} else {
leftHandMask.rows[row] &= ~(HIGH_BIT >> (col & COL_BITS));
}
}
bool Model01::isKeyMasked(byte row, byte col) {
if (row >= ROWS || col >= COLS)
return false;
if (col & HAND_BIT) {
return rightHandMask.rows[row] & (HIGH_BIT >> (col & COL_BITS));
} else {
return leftHandMask.rows[row] & (HIGH_BIT >> (col & COL_BITS));
}
}
void Model01::maskHeldKeys(void) {
memcpy(leftHandMask.rows, leftHandState.rows, sizeof(leftHandMask));
memcpy(rightHandMask.rows, rightHandState.rows, sizeof(rightHandMask));
}
void Model01::setKeyscanInterval(uint8_t interval) {
leftHand.setKeyscanInterval(interval);
rightHand.setKeyscanInterval(interval);
}
void Model01::detachFromHost() {
UDCON |= (1 << DETACH);
}
void Model01::attachToHost() {
UDCON &= ~(1 << DETACH);
}
bool Model01::isKeyswitchPressed(byte row, byte col) {
if (col <= 7) {
return (bitRead(leftHandState.rows[row], 7 - col) != 0);
} else {
return (bitRead(rightHandState.rows[row], 7 - (col - 8)) != 0);
}
}
bool Model01::isKeyswitchPressed(uint8_t keyIndex) {
keyIndex--;
return isKeyswitchPressed(keyIndex / COLS, keyIndex % COLS);
}
uint8_t Model01::pressedKeyswitchCount() {
return __builtin_popcountl(leftHandState.all) + __builtin_popcountl(rightHandState.all);
}
}
}
HARDWARE_IMPLEMENTATION KeyboardHardware;

@ -0,0 +1,322 @@
/* -*- mode: c++ -*-
* Kaleidoscope-Hardware-Model01 -- Keyboard.io Model01 hardware support for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#pragma once
#include <Arduino.h>
#define HARDWARE_IMPLEMENTATION kaleidoscope::hardware::Model01
#include "Kaleidoscope-HIDAdaptor-KeyboardioHID.h"
#include "KeyboardioScanner.h"
#include "kaleidoscope/macro_helpers.h"
#define COLS 16
#define ROWS 4
#define CRGB(r,g,b) (cRGB){b, g, r}
namespace kaleidoscope {
namespace hardware {
class Model01 {
public:
Model01(void);
void syncLeds(void);
void setCrgbAt(byte row, byte col, cRGB color);
void setCrgbAt(uint8_t i, cRGB crgb);
cRGB getCrgbAt(uint8_t i);
uint8_t getLedIndex(byte row, byte col);
void scanMatrix(void);
void readMatrix(void);
void actOnMatrixScan(void);
void setup();
void rebootBootloader();
/** Detaching from / attaching to the host.
*
* These two functions should detach the device from (or attach it to) the
* host, preferably without rebooting the device. Their purpose is to allow
* one to do some configuration inbetween, so the re-attach happens with
* different properties. The device remains powered between these operations,
* only the connection to the host gets severed.
*/
void detachFromHost();
void attachToHost();
/* These public functions are things supported by the Model 01, but
* aren't necessarily part of the Kaleidoscope API
*/
void enableHighPowerLeds(void);
void enableScannerPower(void);
void setKeyscanInterval(uint8_t interval);
boolean ledPowerFault(void);
/* Key masking
* -----------
*
* There are situations when one wants to ignore key events for a while, and
* mask them out. These functions help do that. In isolation, they do nothing,
* plugins and the core firmware is expected to make use of these.
*
* See `handleKeyswitchEvent` in the Kaleidoscope sources for a use-case.
*/
void maskKey(byte row, byte col);
void unMaskKey(byte row, byte col);
bool isKeyMasked(byte row, byte col);
void maskHeldKeys(void);
/** Key switch states
*
* These methods offer a way to peek at the key switch states, for those cases
* where we need to deal with the state closest to the hardware. Some methods
* offer a way to check if a key is pressed, others return the number of
* pressed keys.
*/
/**
* Check if a key is pressed at a given position.
*
* @param row is the row the key is located at in the matrix.
* @param col is the column the key is located at in the matrix.
*
* @returns true if the key is pressed, false otherwise.
*/
bool isKeyswitchPressed(byte row, byte col);
/**
* Check if a key is pressed at a given position.
*
* @param keyIndex is the key index, as calculated by `keyIndex`.
*
* @note Key indexes start at 1, not 0!
*
* @returns true if the key is pressed, false otherwise.
*/
bool isKeyswitchPressed(uint8_t keyIndex);
/**
* Check the number of key switches currently pressed.
*
* @returns the number of keys pressed.
*/
uint8_t pressedKeyswitchCount();
keydata_t leftHandState;
keydata_t rightHandState;
keydata_t previousLeftHandState;
keydata_t previousRightHandState;
private:
static void actOnHalfRow(byte row, byte colState, byte colPrevState, byte startPos);
static bool isLEDChanged;
static KeyboardioScanner leftHand;
static KeyboardioScanner rightHand;
static keydata_t leftHandMask;
static keydata_t rightHandMask;
};
}
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/* To be used by the hardware implementations, `keyIndex` tells us the index of
* a key, from which we can figure out the row and column as needed. The index
* starts at one, so that plugins that work with a list of key indexes can use
* zero as a sentinel. This is important, because when we initialize arrays with
* fewer elements than the declared array size, the remaining elements will be
* zero. We can use this to avoid having to explicitly add a sentinel in
* user-facing code.
*/
constexpr byte keyIndex(byte row, byte col) {
return row * COLS + col + 1;
}
constexpr byte R0C0 = keyIndex(0, 0);
constexpr byte R0C1 = keyIndex(0, 1);
constexpr byte R0C2 = keyIndex(0, 2);
constexpr byte R0C3 = keyIndex(0, 3);
constexpr byte R0C4 = keyIndex(0, 4);
constexpr byte R0C5 = keyIndex(0, 5);
constexpr byte R0C6 = keyIndex(0, 6);
constexpr byte R0C7 = keyIndex(0, 7);
constexpr byte R1C0 = keyIndex(1, 0);
constexpr byte R1C1 = keyIndex(1, 1);
constexpr byte R1C2 = keyIndex(1, 2);
constexpr byte R1C3 = keyIndex(1, 3);
constexpr byte R1C4 = keyIndex(1, 4);
constexpr byte R1C5 = keyIndex(1, 5);
constexpr byte R1C6 = keyIndex(1, 6);
constexpr byte R1C7 = keyIndex(1, 7);
constexpr byte R2C0 = keyIndex(2, 0);
constexpr byte R2C1 = keyIndex(2, 1);
constexpr byte R2C2 = keyIndex(2, 2);
constexpr byte R2C3 = keyIndex(2, 3);
constexpr byte R2C4 = keyIndex(2, 4);
constexpr byte R2C5 = keyIndex(2, 5);
constexpr byte R2C6 = keyIndex(2, 6);
constexpr byte R2C7 = keyIndex(2, 7);
constexpr byte R3C0 = keyIndex(3, 0);
constexpr byte R3C1 = keyIndex(3, 1);
constexpr byte R3C2 = keyIndex(3, 2);
constexpr byte R3C3 = keyIndex(3, 3);
constexpr byte R3C4 = keyIndex(3, 4);
constexpr byte R3C5 = keyIndex(3, 5);
constexpr byte R3C6 = keyIndex(3, 6);
constexpr byte R3C7 = keyIndex(3, 7);
constexpr byte R0C8 = keyIndex(0, 8);
constexpr byte R0C9 = keyIndex(0, 9);
constexpr byte R0C10 = keyIndex(0, 10);
constexpr byte R0C11 = keyIndex(0, 11);
constexpr byte R0C12 = keyIndex(0, 12);
constexpr byte R0C13 = keyIndex(0, 13);
constexpr byte R0C14 = keyIndex(0, 15);
constexpr byte R0C15 = keyIndex(0, 16);
constexpr byte R1C8 = keyIndex(1, 8);
constexpr byte R1C9 = keyIndex(1, 9);
constexpr byte R1C10 = keyIndex(1, 10);
constexpr byte R1C11 = keyIndex(1, 11);
constexpr byte R1C12 = keyIndex(1, 12);
constexpr byte R1C13 = keyIndex(1, 13);
constexpr byte R1C14 = keyIndex(1, 14);
constexpr byte R1C15 = keyIndex(1, 15);
constexpr byte R2C8 = keyIndex(2, 8);
constexpr byte R2C9 = keyIndex(2, 9);
constexpr byte R2C10 = keyIndex(2, 10);
constexpr byte R2C11 = keyIndex(2, 11);
constexpr byte R2C12 = keyIndex(2, 12);
constexpr byte R2C13 = keyIndex(2, 13);
constexpr byte R2C14 = keyIndex(2, 14);
constexpr byte R2C15 = keyIndex(2, 15);
constexpr byte R3C8 = keyIndex(3, 8);
constexpr byte R3C9 = keyIndex(3, 9);
constexpr byte R3C10 = keyIndex(3, 10);
constexpr byte R3C11 = keyIndex(3, 11);
constexpr byte R3C12 = keyIndex(3, 12);
constexpr byte R3C13 = keyIndex(3, 13);
constexpr byte R3C14 = keyIndex(3, 14);
constexpr byte R3C15 = keyIndex(3, 15);
#define LED_COUNT 64
#define LED_PGDN 0
#define LED_PGUP 1
#define LED_BACKTICK 2
#define LED_PROG 3
#define LED_1 4
#define LED_Q 5
#define LED_A 6
#define LED_Z 7
#define LED_X 8
#define LED_S 9
#define LED_W 10
#define LED_2 11
#define LED_3 12
#define LED_E 13
#define LED_D 14
#define LED_C 15
#define LED_V 16
#define LED_F 17
#define LED_R 18
#define LED_4 19
#define LED_5 20
#define LED_T 21
#define LED_G 22
#define LED_B 23
#define LED_ESC 24
#define LED_TAB 25
#define LED_LED 26
#define LED_L_CTRL 27
#define LED_BKSP 28
#define LED_CMD 29
#define LED_L_SHIFT 30
#define LED_L_FN 31
#define LED_R_FN 32
#define LED_R_SHIFT 33
#define LED_ALT 34
#define LED_SPACE 35
#define LED_R_CTRL 36
#define LED_ANY 37
#define LED_RETURN 38
#define LED_BUTTERFLY 39
#define LED_N 40
#define LED_H 41
#define LED_Y 42
#define LED_6 43
#define LED_7 44
#define LED_U 45
#define LED_J 46
#define LED_M 47
#define LED_COMMA 48
#define LED_K 49
#define LED_I 50
#define LED_8 51
#define LED_9 52
#define LED_O 53
#define LED_L 54
#define LED_PERIOD 55
#define LED_SLASH 56
#define LED_SEMICOLON 57
#define LED_P 58
#define LED_0 59
#define LED_NUM 60
#define LED_EQUALS 61
#define LED_APOSTROPHE 62
#define LED_MINUS 63
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
#define KEYMAP_STACKED( \
r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, \
r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, r1c6, \
r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, \
r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r2c6, \
r0c7, r1c7, r2c7, r3c7, \
r3c6, \
\
r0c9, r0c10, r0c11, r0c12, r0c13, r0c14, r0c15, \
r1c9, r1c10, r1c11, r1c12, r1c13, r1c14, r1c15, \
r2c10, r2c11, r2c12, r2c13, r2c14, r2c15, \
r2c9, r3c10, r3c11, r3c12, r3c13, r3c14, r3c15, \
r3c8, r2c8, r1c8, r0c8, \
r3c9, ...) \
{ \
{r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, r0c7, r0c8, r0c9, r0c10, r0c11, r0c12, r0c13, r0c14, r0c15}, \
{r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, r1c6, r1c7, r1c8, r1c9, r1c10, r1c11, r1c12, r1c13, r1c14, r1c15}, \
{r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, r2c6, r2c7, r2c8, r2c9, r2c10, r2c11, r2c12, r2c13, r2c14, r2c15}, \
{r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r3c6, r3c7, r3c8, r3c9, r3c10, r3c11, r3c12, r3c13, r3c14, RESTRICT_ARGS_COUNT((r3c15), 64, KEYMAP_STACKED, ##__VA_ARGS__)}, \
}
#define KEYMAP( \
r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, r0c9, r0c10, r0c11, r0c12, r0c13, r0c14, r0c15, \
r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, r1c6, r1c9, r1c10, r1c11, r1c12, r1c13, r1c14, r1c15, \
r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, r2c10, r2c11, r2c12, r2c13, r2c14, r2c15, \
r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r2c6, r2c9, r3c10, r3c11, r3c12, r3c13, r3c14, r3c15, \
r0c7, r1c7, r2c7, r3c7, r3c8, r2c8, r1c8, r0c8, \
r3c6, r3c9, ...) \
{ \
{r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, r0c7, r0c8, r0c9, r0c10, r0c11, r0c12, r0c13, r0c14, r0c15}, \
{r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, r1c6, r1c7, r1c8, r1c9, r1c10, r1c11, r1c12, r1c13, r1c14, r1c15}, \
{r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, r2c6, r2c7, r2c8, r2c9, r2c10, r2c11, r2c12, r2c13, r2c14, r2c15}, \
{r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r3c6, r3c7, r3c8, r3c9, r3c10, r3c11, r3c12, r3c13, r3c14, RESTRICT_ARGS_COUNT((r3c15), 64, KEYMAP, ##__VA_ARGS__)}, \
}

@ -0,0 +1,155 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Keymap -- EEPROM-based keymap support.
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope-EEPROM-Settings.h>
#include <Kaleidoscope-EEPROM-Keymap.h>
#include <Kaleidoscope-FocusSerial.h>
namespace kaleidoscope {
namespace plugin {
EEPROMKeymap::Mode EEPROMKeymap::mode_;
uint16_t EEPROMKeymap::keymap_base_;
uint8_t EEPROMKeymap::max_layers_;
uint8_t EEPROMKeymap::progmem_layers_;
EventHandlerResult EEPROMKeymap::onSetup() {
::EEPROMSettings.onSetup();
progmem_layers_ = layer_count;
return EventHandlerResult::OK;
}
void EEPROMKeymap::setup(uint8_t max, Mode mode) {
switch (mode) {
case Mode::CUSTOM:
break;
case Mode::EXTEND:
layer_count = progmem_layers_ + max;
Layer.getKey = getKeyExtended;
break;
}
mode_ = mode;
max_layers(max);
}
void EEPROMKeymap::max_layers(uint8_t max) {
max_layers_ = max;
keymap_base_ = ::EEPROMSettings.requestSlice(max_layers_ * ROWS * COLS * 2);
}
Key EEPROMKeymap::getKey(uint8_t layer, byte row, byte col) {
Key key;
if (layer >= max_layers_)
return Key_NoKey;
uint16_t pos = ((layer * ROWS * COLS) + (row * COLS) + col) * 2;
key.flags = EEPROM.read(keymap_base_ + pos);
key.keyCode = EEPROM.read(keymap_base_ + pos + 1);
return key;
}
Key EEPROMKeymap::getKeyExtended(uint8_t layer, byte row, byte col) {
Key key;
// If the layer is within PROGMEM bounds, look it up from there
if (layer < progmem_layers_) {
return Layer.getKeyFromPROGMEM(layer, row, col);
}
// If the layer is outside of PROGMEM, look up from EEPROM
return getKey(layer - progmem_layers_, row, col);
}
uint16_t EEPROMKeymap::keymap_base(void) {
return keymap_base_;
}
void EEPROMKeymap::updateKey(uint16_t base_pos, Key key) {
EEPROM.update(keymap_base_ + base_pos * 2, key.flags);
EEPROM.update(keymap_base_ + base_pos * 2 + 1, key.keyCode);
}
Key EEPROMKeymap::parseKey(void) {
Key key;
key.raw = Serial.parseInt();
return key;
}
void EEPROMKeymap::printKey(Key k) {
::Focus.printNumber(k.raw);
}
EventHandlerResult EEPROMKeymap::onFocusEvent(const char *command) {
const char *cmd = PSTR("keymap.map");
if (::Focus.handleHelp(command, PSTR("keymap.map\nkeymap.roLayers")))
return EventHandlerResult::OK;
if (strncmp_P(command, PSTR("keymap."), 7) != 0)
return EventHandlerResult::OK;
if (strcmp_P(command + 7, PSTR("roLayers")) == 0) {
if (mode_ != Mode::EXTEND)
return EventHandlerResult::OK;
Serial.println(progmem_layers_);
return EventHandlerResult::EVENT_CONSUMED;
}
if (strcmp_P(command + 7, PSTR("map")) != 0)
return EventHandlerResult::OK;
if (Serial.peek() == '\n') {
for (uint8_t layer = 0; layer < layer_count; layer++) {
for (uint8_t row = 0; row < ROWS; row++) {
for (uint8_t col = 0; col < COLS; col++) {
Key k = Layer.getKey(layer, row, col);
printKey(k);
::Focus.printSpace();
}
}
}
Serial.println();
} else {
uint16_t i = 0;
uint8_t layers = layer_count;
if (layers > 0)
layers--;
while ((Serial.peek() != '\n') && (i < ROWS * COLS * layers)) {
Key k = parseKey();
if (mode_ == Mode::EXTEND) {
uint8_t layer = i / (ROWS * COLS);
if (layer >= progmem_layers_)
updateKey(i - (progmem_layers_ * ROWS * COLS), k);
} else {
updateKey(i, k);
}
i++;
}
}
return EventHandlerResult::EVENT_CONSUMED;
}
}
}
kaleidoscope::plugin::EEPROMKeymap EEPROMKeymap;

@ -0,0 +1,60 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Keymap -- EEPROM-based keymap support.
* Copyright (C) 2017, 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/>.
*/
#pragma once
#include <Kaleidoscope.h>
#include <Kaleidoscope-EEPROM-Settings.h>
namespace kaleidoscope {
namespace plugin {
class EEPROMKeymap : public kaleidoscope::Plugin {
public:
enum class Mode {
CUSTOM,
EXTEND,
};
EEPROMKeymap(void) {}
EventHandlerResult onSetup();
EventHandlerResult onFocusEvent(const char *command);
static void setup(uint8_t max, Mode mode = Mode::EXTEND);
static void max_layers(uint8_t max);
static uint16_t keymap_base(void);
static Key getKey(uint8_t layer, byte row, byte col);
static Key getKeyExtended(uint8_t layer, byte row, byte col);
static void updateKey(uint16_t base_pos, Key key);
private:
static uint16_t keymap_base_;
static uint8_t max_layers_;
static uint8_t progmem_layers_;
static Mode mode_;
static Key parseKey(void);
static void printKey(Key key);
};
}
}
extern kaleidoscope::plugin::EEPROMKeymap EEPROMKeymap;

@ -0,0 +1,217 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Settings -- Basic EEPROM settings plugin for Kaleidoscope.
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope-EEPROM-Settings.h>
#include <Kaleidoscope-FocusSerial.h>
#include "kaleidoscope/plugin/EEPROM-Settings/crc.h"
namespace kaleidoscope {
namespace plugin {
struct EEPROMSettings::settings EEPROMSettings::settings_;
bool EEPROMSettings::is_valid_;
bool EEPROMSettings::sealed_;
uint16_t EEPROMSettings::next_start_ = sizeof(EEPROMSettings::settings);
EventHandlerResult EEPROMSettings::onSetup() {
EEPROM.get(0, settings_);
return EventHandlerResult::OK;
}
EventHandlerResult EEPROMSettings::beforeEachCycle() {
if (!sealed_)
seal();
return EventHandlerResult::OK;
}
bool EEPROMSettings::isValid(void) {
return is_valid_;
}
uint16_t EEPROMSettings::crc(void) {
if (sealed_)
return settings_.crc;
return 0;
}
uint8_t EEPROMSettings::default_layer(uint8_t layer) {
if (layer == 0xff)
return settings_.default_layer;
settings_.default_layer = layer;
update();
return settings_.default_layer;
}
void EEPROMSettings::seal(void) {
sealed_ = true;
CRC.finalize();
/* If we have a default layer set, switch to it. As 0xff is the default EEPROM
* value, treat it as not having a default layer set. */
if (settings_.default_layer != 0xff)
Layer.move(settings_.default_layer);
/* Until we set a version, consider the EEPROM contents flexible, and always
* update the CRC. This will always result in the settings being considered
* valid. */
if (settings_.version == 0xff) {
return update();
}
if (settings_.crc != CRC.crc)
is_valid_ = false;
}
uint16_t EEPROMSettings::requestSlice(uint16_t size) {
if (sealed_)
return 0;
uint16_t start = next_start_;
next_start_ += size;
CRC.update((const void *)&size, sizeof(size));
return start;
}
void EEPROMSettings::invalidate(void) {
is_valid_ = false;
}
uint16_t EEPROMSettings::used(void) {
return next_start_;
}
void EEPROMSettings::update(void) {
settings_.crc = CRC.crc;
EEPROM.put(0, settings_);
is_valid_ = true;
}
uint8_t EEPROMSettings::version(void) {
return settings_.version;
}
void EEPROMSettings::version(uint8_t ver) {
settings_.version = ver;
update();
}
/** Focus **/
EventHandlerResult FocusSettingsCommand::onFocusEvent(const char *command) {
enum {
DEFAULT_LAYER,
IS_VALID,
GET_VERSION,
CRC,
} sub_command;
if (::Focus.handleHelp(command, PSTR("settings.defaultLayer\nsettings.valid?\nsettings.version\nsettings.crc")))
return EventHandlerResult::OK;
if (strncmp_P(command, PSTR("settings."), 9) != 0)
return EventHandlerResult::OK;
if (strcmp_P(command + 9, PSTR("defaultLayer")) == 0)
sub_command = DEFAULT_LAYER;
else if (strcmp_P(command + 9, PSTR("valid?")) == 0)
sub_command = IS_VALID;
else if (strcmp_P(command + 9, PSTR("version")) == 0)
sub_command = GET_VERSION;
else if (strcmp_P(command + 9, PSTR("crc")) == 0)
sub_command = CRC;
else
return EventHandlerResult::OK;
switch (sub_command) {
case DEFAULT_LAYER: {
if (Serial.peek() == '\n') {
Serial.println(::EEPROMSettings.default_layer());
} else {
::EEPROMSettings.default_layer(Serial.parseInt());
}
break;
}
case IS_VALID:
::Focus.printBool(::EEPROMSettings.isValid());
Serial.println();
break;
case GET_VERSION:
Serial.println(::EEPROMSettings.version());
break;
case CRC:
Serial.print(::CRC.crc, HEX);
Serial.print(F("/"));
Serial.println(::EEPROMSettings.crc(), HEX);
break;
}
return EventHandlerResult::EVENT_CONSUMED;
}
EventHandlerResult FocusEEPROMCommand::onFocusEvent(const char *command) {
enum {
CONTENTS,
FREE,
} sub_command;
if (::Focus.handleHelp(command, PSTR("eeprom.contents\neeprom.free")))
return EventHandlerResult::OK;
if (strcmp_P(command, PSTR("eeprom.contents")) == 0)
sub_command = CONTENTS;
else if (strcmp_P(command, PSTR("eeprom.free")) == 0)
sub_command = FREE;
else
return EventHandlerResult::OK;
switch (sub_command) {
case CONTENTS: {
if (Serial.peek() == '\n') {
for (uint16_t i = 0; i < EEPROM.length(); i++) {
uint8_t d = EEPROM[i];
::Focus.printNumber(d);
::Focus.printSpace();
}
Serial.println();
} else {
for (uint16_t i = 0; i < EEPROM.length() && Serial.peek() != '\n'; i++) {
uint8_t d = Serial.parseInt();
EEPROM.update(i, d);
}
}
break;
}
case FREE:
Serial.println(EEPROM.length() - ::EEPROMSettings.used());
break;
}
return EventHandlerResult::EVENT_CONSUMED;
}
}
}
kaleidoscope::plugin::EEPROMSettings EEPROMSettings;
kaleidoscope::plugin::FocusSettingsCommand FocusSettingsCommand;
kaleidoscope::plugin::FocusEEPROMCommand FocusEEPROMCommand;

@ -0,0 +1,75 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Settings -- Basic EEPROM settings plugin for Kaleidoscope.
* Copyright (C) 2017, 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/>.
*/
#pragma once
#include <Kaleidoscope.h>
#include <EEPROM.h>
namespace kaleidoscope {
namespace plugin {
class EEPROMSettings : public kaleidoscope::Plugin {
public:
EEPROMSettings(void) {}
EventHandlerResult onSetup();
EventHandlerResult beforeEachCycle();
static void update(void);
static bool isValid(void);
static void invalidate(void);
static uint8_t version(void);
static void version(uint8_t ver);
static uint16_t requestSlice(uint16_t size);
static void seal(void);
static uint16_t crc(void);
static uint16_t used(void);
static uint8_t default_layer(uint8_t layer = 0xff);
private:
static uint16_t next_start_;
static bool is_valid_;
static bool sealed_;
static struct settings {
uint8_t default_layer;
uint8_t version;
uint16_t crc;
} settings_;
};
class FocusSettingsCommand : public kaleidoscope::Plugin {
public:
FocusSettingsCommand() {}
EventHandlerResult onFocusEvent(const char *command);
};
class FocusEEPROMCommand : public kaleidoscope::Plugin {
public:
FocusEEPROMCommand() {}
EventHandlerResult onFocusEvent(const char *command);
};
}
}
extern kaleidoscope::plugin::EEPROMSettings EEPROMSettings;
extern kaleidoscope::plugin::FocusSettingsCommand FocusSettingsCommand;
extern kaleidoscope::plugin::FocusEEPROMCommand FocusEEPROMCommand;

@ -0,0 +1,69 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Settings -- Basic EEPROM settings plugin for Kaleidoscope.
* Copyright (C) 2017 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/>.
*
* Originally generated by pycrc v0.9, https://pycrc.org
*
* using the configuration:
* Width = 16
* Poly = 0x8005
* Xor_In = 0x0000
* ReflectIn = True
* Xor_Out = 0x0000
* ReflectOut = True
* Algorithm = bit-by-bit-fast
*/
#include "crc.h"
void
CRC_::reflect(uint8_t len) {
uint8_t i;
uint16_t newCRC;
newCRC = crc & 0x01;
for (i = 1; i < len; i++) {
crc >>= 1;
newCRC = (newCRC << 1) | (crc & 0x01);
}
crc = newCRC;
}
void
CRC_::update(const void *data, uint8_t len) {
const uint8_t *d = (const uint8_t *)data;
uint8_t i;
bool bit;
uint8_t c;
while (len--) {
c = *d++;
for (i = 0x01; i & 0xff; i <<= 1) {
bit = crc & 0x8000;
if (c & i) {
bit = !bit;
}
crc <<= 1;
if (bit) {
crc ^= 0x8005;
}
}
crc &= 0xffff;
}
crc &= 0xffff;
}
CRC_ CRC;

@ -0,0 +1,46 @@
/* -*- mode: c++ -*-
* Kaleidoscope-EEPROM-Settings -- Basic EEPROM settings plugin for Kaleidoscope.
* Copyright (C) 2017 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/>.
*
* Originally generated by pycrc v0.9, https://pycrc.org
*
* using the configuration:
* Width = 16
* Poly = 0x8005
* Xor_In = 0x0000
* ReflectIn = True
* Xor_Out = 0x0000
* ReflectOut = True
* Algorithm = bit-by-bit-fast
*/
#pragma once
#include <Arduino.h>
class CRC_ {
public:
uint16_t crc = 0;
CRC_(void) {};
void update(const void *data, uint8_t len);
void finalize(void) {
reflect(16);
}
void reflect(uint8_t len);
};
extern CRC_ CRC;

@ -0,0 +1,110 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FocusSerial -- Bidirectional communication plugin
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope-FocusSerial.h>
#ifdef __AVR__
#include <avr/pgmspace.h>
#endif
namespace kaleidoscope {
namespace plugin {
char FocusSerial::command_[32];
void FocusSerial::drain(void) {
if (Serial.available())
while (Serial.peek() != '\n')
Serial.read();
}
EventHandlerResult FocusSerial::beforeReportingState() {
if (Serial.available() == 0)
return EventHandlerResult::OK;
uint8_t i = 0;
do {
command_[i++] = Serial.read();
if (Serial.peek() == '\n')
break;
} while (command_[i - 1] != ' ' && i < 32);
if (command_[i - 1] == ' ')
command_[i - 1] = '\0';
else
command_[i] = '\0';
Kaleidoscope.onFocusEvent(command_);
Serial.println(F("."));
drain();
if (Serial.peek() == '\n')
Serial.read();
return EventHandlerResult::OK;
}
bool FocusSerial::handleHelp(const char *command,
const char *help_message) {
if (strcmp_P(command, PSTR("help")) != 0)
return false;
Serial.println((const __FlashStringHelper *)help_message);
return true;
}
EventHandlerResult FocusSerial::onFocusEvent(const char *command) {
handleHelp(command, PSTR("help"));
return EventHandlerResult::OK;
}
void FocusSerial::printSpace(void) {
Serial.print(F(" "));
}
void FocusSerial::printNumber(uint16_t num) {
Serial.print(num);
}
void FocusSerial::printColor(uint8_t r, uint8_t g, uint8_t b) {
printNumber(r);
printSpace();
printNumber(g);
printSpace();
printNumber(b);
}
void FocusSerial::printSeparator(void) {
Serial.print(F(" | "));
}
void FocusSerial::printBool(bool b) {
Serial.print((b) ? F("true") : F("false"));
}
void FocusSerial::readColor(cRGB &color) {
color.r = Serial.parseInt();
color.g = Serial.parseInt();
color.b = Serial.parseInt();
}
}
}
kaleidoscope::plugin::FocusSerial Focus;

@ -0,0 +1,56 @@
/* -*- mode: c++ -*-
* Kaleidoscope-FocusSerial -- Bidirectional communication plugin
* Copyright (C) 2017, 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/>.
*/
#pragma once
#include <Kaleidoscope.h>
namespace kaleidoscope {
namespace plugin {
class FocusSerial : public kaleidoscope::Plugin {
public:
FocusSerial(void) {}
bool handleHelp(const char *command,
const char *help_message);
/* Helpers */
static void printNumber(uint16_t number);
static void printSpace(void);
static void printColor(uint8_t r, uint8_t g, uint8_t b);
static void printSeparator(void);
static void printBool(bool b);
static void readColor(cRGB &color);
/* Hooks */
EventHandlerResult onSetup() {
Serial.begin(9600);
return EventHandlerResult::OK;
}
EventHandlerResult beforeReportingState();
EventHandlerResult onFocusEvent(const char *command);
private:
static char command_[32];
static void drain(void);
};
}
}
extern kaleidoscope::plugin::FocusSerial Focus;

@ -0,0 +1,64 @@
/* -*- mode: c++ -*-
* Kaleidoscope-HostPowerManagement -- Host power management support plugin.
* Copyright (C) 2017, 2018 Gergely Nagy
*
* 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/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-HostPowerManagement.h>
#include <Kaleidoscope-LEDControl.h>
// 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 plugin {
bool HostPowerManagement::was_suspended_ = false;
bool HostPowerManagement::initial_suspend_ = true;
EventHandlerResult HostPowerManagement::beforeEachCycle() {
#ifdef __AVR__
if ((_usbSuspendState & (1 << SUSPI))) {
if (!initial_suspend_) {
if (!was_suspended_) {
was_suspended_ = true;
hostPowerManagementEventHandler(Suspend);
} else {
hostPowerManagementEventHandler(Sleep);
}
}
} else {
if (initial_suspend_)
initial_suspend_ = false;
if (was_suspended_) {
was_suspended_ = false;
hostPowerManagementEventHandler(Resume);
}
}
#endif
return EventHandlerResult::OK;
}
}
}
__attribute__((weak)) void hostPowerManagementEventHandler(kaleidoscope::plugin::HostPowerManagement::Event event) {
}
kaleidoscope::plugin::HostPowerManagement HostPowerManagement;

@ -0,0 +1,57 @@
/* -*- mode: c++ -*-
* Kaleidoscope-HostPowerManagement -- Host power management support plugin.
* Copyright (C) 2017, 2018 Gergely Nagy
*
* 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/>.
*/
#pragma once
#include <Kaleidoscope.h>
#define _DEPRECATED_MESSAGE_ENABLEWAKEUP \
"The HostPowerManagement.enableWakeup() call is not necessary anymore,\n" \
"the firmware supports wakeup by default now. The line can be safely\n" \
"removed."
namespace kaleidoscope {
namespace plugin {
class HostPowerManagement : public kaleidoscope::Plugin {
public:
typedef enum {
Suspend,
Sleep,
Resume,
} Event;
HostPowerManagement(void) {}
void enableWakeup(void) DEPRECATED(ENABLEWAKEUP) {}
EventHandlerResult beforeEachCycle();
private:
static bool was_suspended_;
static bool initial_suspend_;
};
}
// Backwards compatibility
typedef plugin::HostPowerManagement HostPowerManagement;
}
void hostPowerManagementEventHandler(kaleidoscope::plugin::HostPowerManagement::Event event);
extern kaleidoscope::plugin::HostPowerManagement HostPowerManagement;

@ -0,0 +1,101 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-AlphaSquare -- 4x4 pixel LED alphabet
* Copyright (C) 2017 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-LED-AlphaSquare.h>
#include <kaleidoscope/plugin/LED-AlphaSquare/Font-4x4.h>
namespace kaleidoscope {
namespace plugin {
static const uint16_t alphabet[] PROGMEM = {
ALPHASQUARE_SYMBOL_A,
ALPHASQUARE_SYMBOL_B,
ALPHASQUARE_SYMBOL_C,
ALPHASQUARE_SYMBOL_D,
ALPHASQUARE_SYMBOL_E,
ALPHASQUARE_SYMBOL_F,
ALPHASQUARE_SYMBOL_G,
ALPHASQUARE_SYMBOL_H,
ALPHASQUARE_SYMBOL_I,
ALPHASQUARE_SYMBOL_J,
ALPHASQUARE_SYMBOL_K,
ALPHASQUARE_SYMBOL_L,
ALPHASQUARE_SYMBOL_M,
ALPHASQUARE_SYMBOL_N,
ALPHASQUARE_SYMBOL_O,
ALPHASQUARE_SYMBOL_P,
ALPHASQUARE_SYMBOL_Q,
ALPHASQUARE_SYMBOL_R,
ALPHASQUARE_SYMBOL_S,
ALPHASQUARE_SYMBOL_T,
ALPHASQUARE_SYMBOL_U,
ALPHASQUARE_SYMBOL_V,
ALPHASQUARE_SYMBOL_W,
ALPHASQUARE_SYMBOL_X,
ALPHASQUARE_SYMBOL_Y,
ALPHASQUARE_SYMBOL_Z,
ALPHASQUARE_SYMBOL_1,
ALPHASQUARE_SYMBOL_2,
ALPHASQUARE_SYMBOL_3,
ALPHASQUARE_SYMBOL_4,
ALPHASQUARE_SYMBOL_5,
ALPHASQUARE_SYMBOL_6,
ALPHASQUARE_SYMBOL_7,
ALPHASQUARE_SYMBOL_8,
ALPHASQUARE_SYMBOL_9,
ALPHASQUARE_SYMBOL_0
};
cRGB AlphaSquare::color = {0x80, 0x80, 0x80};
void AlphaSquare::display(Key key, uint8_t row, uint8_t col, cRGB key_color) {
if (key < Key_A || key > Key_0)
return;
uint8_t index = key.keyCode - Key_A.keyCode;
uint16_t symbol = pgm_read_word(&alphabet[index]);
display(symbol, row, col, key_color);
}
void AlphaSquare::display(Key key, uint8_t row, uint8_t col) {
display(key, row, col, color);
}
void AlphaSquare::display(uint16_t symbol, uint8_t row, uint8_t col, cRGB key_color) {
for (uint8_t r = 0; r < 4; r++) {
for (uint8_t c = 0; c < 4; c++) {
uint8_t pixel = bitRead(symbol, r * 4 + c);
if (!pixel)
continue;
::LEDControl.setCrgbAt(row + r, col + c, key_color);
}
}
::LEDControl.syncLeds();
}
void AlphaSquare::display(uint16_t symbol, uint8_t row, uint8_t col) {
display(symbol, row, col, color);
}
}
}
kaleidoscope::plugin::AlphaSquare AlphaSquare;

@ -0,0 +1,84 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-AlphaSquare -- 4x4 pixel LED alphabet
* Copyright (C) 2017 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.h>
#include <Kaleidoscope-LEDControl.h>
#define SYM4x4( \
p00, p01, p02, p03, \
p10, p11, p12, p13, \
p20, p21, p22, p23, \
p30, p31, p32, p33) \
(uint16_t) ( \
p00 << 0 | p01 << 1 | p02 << 2 | p03 << 3 | \
p10 << 4 | p11 << 5 | p12 << 6 | p13 << 7 | \
p20 << 8 | p21 << 9 | p22 << 10 | p23 << 11 | \
p30 << 12 | p31 << 13 | p32 << 14 | p33 << 15 )
namespace kaleidoscope {
namespace plugin {
class AlphaSquare : public kaleidoscope::Plugin {
public:
AlphaSquare(void) {}
static void display(Key key, uint8_t row, uint8_t col, cRGB key_color);
static void display(Key key, uint8_t row, uint8_t col);
static void display(Key key) {
display(key, 0, 2);
}
static void display(Key key, uint8_t col) {
display(key, 0, col);
}
static void display(uint16_t symbol, uint8_t row, uint8_t col, cRGB key_color);
static void display(uint16_t symbol, uint8_t row, uint8_t col);
static void display(uint16_t symbol) {
display(symbol, 0, 2);
}
static void display(uint16_t symbol, uint8_t col) {
display(symbol, 0, col);
}
static void clear(Key key, uint8_t row, uint8_t col) {
display(key, row, col, {0, 0, 0});
}
static void clear(Key key, uint8_t col) {
clear(key, 0, col);
}
static void clear(Key key) {
clear(key, 0, 2);
}
static void clear(uint16_t symbol, uint8_t row, uint8_t col) {
display(symbol, row, col, {0, 0, 0});
}
static void clear(uint16_t symbol, uint8_t col) {
clear(symbol, 0, col);
}
static void clear(uint16_t symbol) {
clear(symbol, 0, 2);
}
static cRGB color;
};
}
}
extern kaleidoscope::plugin::AlphaSquare AlphaSquare;

@ -0,0 +1,74 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-AlphaSquare -- 4x4 pixel LED alphabet
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope-LED-AlphaSquare.h>
namespace kaleidoscope {
namespace plugin {
uint16_t AlphaSquareEffect::length = 1000;
uint32_t AlphaSquareEffect::end_time_left_, AlphaSquareEffect::end_time_right_;
Key AlphaSquareEffect::last_key_left_, AlphaSquareEffect::last_key_right_;
void AlphaSquareEffect::update(void) {
if (end_time_left_ && millis() > end_time_left_) {
::AlphaSquare.clear(last_key_left_);
end_time_left_ = 0;
}
if (end_time_right_ && millis() > end_time_right_) {
::AlphaSquare.clear(last_key_right_, 10);
end_time_right_ = 0;
}
}
EventHandlerResult AlphaSquareEffect::onKeyswitchEvent(Key &mappedKey, byte row, byte col, uint8_t keyState) {
if (::LEDControl.get_mode() != &::AlphaSquareEffect)
return EventHandlerResult::OK;
if (keyState & INJECTED)
return EventHandlerResult::OK;
if (mappedKey < Key_A || mappedKey > Key_0)
return EventHandlerResult::OK;
if (!keyIsPressed(keyState))
return EventHandlerResult::OK;
uint8_t display_col = 2;
Key prev_key = last_key_left_;
if (col < COLS / 2) {
last_key_left_ = mappedKey;
end_time_left_ = millis() + length;
} else {
prev_key = last_key_right_;
last_key_right_ = mappedKey;
end_time_right_ = millis() + length;
display_col = 10;
}
if (prev_key != mappedKey)
::AlphaSquare.clear(prev_key, display_col);
::AlphaSquare.display(mappedKey, display_col);
return EventHandlerResult::OK;
}
}
}
kaleidoscope::plugin::AlphaSquareEffect AlphaSquareEffect;

@ -0,0 +1,43 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-AlphaSquare -- 4x4 pixel LED alphabet
* Copyright (C) 2017, 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/>.
*/
#pragma once
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
namespace kaleidoscope {
namespace plugin {
class AlphaSquareEffect : public LEDMode {
public:
AlphaSquareEffect(void) {}
static uint16_t length;
EventHandlerResult onKeyswitchEvent(Key &mappedKey, byte row, byte col, uint8_t keyState);
protected:
void update(void) final;
private:
static uint32_t end_time_left_, end_time_right_;
static Key last_key_left_, last_key_right_;
};
}
}
extern kaleidoscope::plugin::AlphaSquareEffect AlphaSquareEffect;

@ -0,0 +1,169 @@
/* Kaleidoscope-LED-AlphaSquare -- 3x4 pixel LED alphabet
* Copyright (C) 2017 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_LED_FONT
#define KALEIDOSCOPE_LED_FONT
#define ALPHASQUARE_SYMBOL_A SYM4x4(0, 1, 0, 0, \
1, 0, 1, 0, \
1, 1, 1, 0, \
1, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_B SYM4x4(1, 1, 0, 0, \
1, 1, 1, 0, \
1, 0, 1, 0, \
1, 1, 0, 0)
#define ALPHASQUARE_SYMBOL_C SYM4x4(0, 1, 1, 0, \
1, 0, 0, 0, \
1, 0, 0, 0, \
0, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_D SYM4x4(1, 1, 0, 0, \
1, 0, 1, 0, \
1, 0, 1, 0, \
1, 1, 0, 0)
#define ALPHASQUARE_SYMBOL_E SYM4x4(1, 1, 1, 0, \
1, 1, 0, 0, \
1, 0, 0, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_F SYM4x4(1, 1, 1, 0, \
1, 0, 0, 0, \
1, 1, 0, 0, \
1, 0, 0, 0)
#define ALPHASQUARE_SYMBOL_G SYM4x4(0, 1, 1, 0, \
1, 0, 0, 0, \
1, 0, 1, 0, \
0, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_H SYM4x4(1, 0, 1, 0, \
1, 1, 1, 0, \
1, 0, 1, 0, \
1, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_I SYM4x4(1, 1, 1, 0, \
0, 1, 0, 0, \
0, 1, 0, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_J SYM4x4(1, 1, 1, 0, \
0, 0, 1, 0, \
1, 0, 1, 0, \
0, 1, 0, 0)
#define ALPHASQUARE_SYMBOL_K SYM4x4(1, 0, 1, 0, \
1, 1, 0, 0, \
1, 1, 0, 0, \
1, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_L SYM4x4(1, 0, 0, 0, \
1, 0, 0, 0, \
1, 0, 0, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_M SYM4x4(1, 0, 1, 0, \
1, 1, 1, 0, \
1, 1, 1, 0, \
1, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_N SYM4x4(1, 0, 1, 0, \
1, 1, 1, 0, \
1, 0, 1, 0, \
1, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_O SYM4x4(0, 1, 0, 0, \
1, 0, 1, 0, \
1, 0, 1, 0, \
0, 1, 0, 0)
#define ALPHASQUARE_SYMBOL_P SYM4x4(1, 1, 0, 0, \
1, 0, 1, 0, \
1, 1, 0, 0, \
1, 0, 0, 0)
#define ALPHASQUARE_SYMBOL_Q SYM4x4(0, 1, 0, 0, \
1, 0, 1, 0, \
1, 0, 1, 0, \
0, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_R SYM4x4(1, 1, 0, 0, \
1, 0, 1, 0, \
1, 1, 0, 0, \
1, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_S SYM4x4(1, 1, 1, 0, \
1, 1, 0, 0, \
0, 0, 1, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_T SYM4x4(1, 1, 1, 0, \
0, 1, 0, 0, \
0, 1, 0, 0, \
0, 1, 0, 0)
#define ALPHASQUARE_SYMBOL_U SYM4x4(1, 0, 1, 0, \
1, 0, 1, 0, \
1, 0, 1, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_V SYM4x4(1, 0, 1, 0, \
1, 0, 1, 0, \
1, 0, 1, 0, \
0, 1, 0, 0)
#define ALPHASQUARE_SYMBOL_W SYM4x4(1, 0, 0, 0, \
1, 0, 1, 0, \
1, 1, 1, 0, \
1, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_X SYM4x4(1, 0, 1, 0, \
0, 1, 0, 0, \
0, 1, 0, 0, \
1, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_Y SYM4x4(1, 0, 1, 0, \
0, 1, 0, 0, \
0, 1, 0, 0, \
0, 1, 0, 0)
#define ALPHASQUARE_SYMBOL_Z SYM4x4(1, 1, 1, 0, \
0, 0, 1, 0, \
0, 1, 0, 0, \
1, 1, 1, 0)
// ---------------------
#define ALPHASQUARE_SYMBOL_1 SYM4x4(1, 1, 0, 0, \
0, 1, 0, 0, \
0, 1, 0, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_2 SYM4x4(1, 1, 0, 0, \
0, 0, 1, 0, \
0, 1, 0, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_3 SYM4x4(1, 1, 1, 0, \
0, 1, 1, 0, \
0, 0, 1, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_4 SYM4x4(1, 0, 1, 0, \
1, 1, 1, 0, \
0, 0, 1, 0, \
0, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_5 SYM4x4(1, 1, 1, 0, \
1, 1, 0, 0, \
0, 0, 1, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_6 SYM4x4(0, 1, 1, 0, \
1, 0, 0, 0, \
1, 1, 1, 0, \
0, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_7 SYM4x4(1, 1, 1, 0, \
0, 0, 1, 0, \
0, 0, 1, 0, \
0, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_8 SYM4x4(1, 1, 1, 0, \
1, 1, 1, 0, \
1, 0, 1, 0, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_9 SYM4x4(1, 1, 1, 0, \
1, 0, 1, 0, \
1, 1, 1, 0, \
0, 0, 1, 0)
#define ALPHASQUARE_SYMBOL_0 SYM4x4(1, 1, 1, 0, \
1, 0, 1, 0, \
1, 0, 1, 0, \
1, 1, 1, 0)
#endif

@ -0,0 +1,168 @@
/* Kaleidoscope-LED-AlphaSquare -- 4x4 pixel LED alphabet
* Copyright (C) 2017 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_LED_FONT
#define KALEIDOSCOPE_LED_FONT
#define ALPHASQUARE_SYMBOL_A SYM4x4(1, 1, 1, 1, \
1, 0, 0, 1, \
1, 1, 1, 1, \
1, 0, 0, 1)
#define ALPHASQUARE_SYMBOL_B SYM4x4(1, 1, 1, 1, \
1, 0, 1, 1, \
1, 1, 0, 1, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_C SYM4x4(1, 1, 1, 1, \
1, 0, 0, 0, \
1, 0, 0, 0, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_D SYM4x4(1, 1, 1, 0, \
1, 0, 0, 1, \
1, 0, 0, 1, \
1, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_E SYM4x4(1, 1, 1, 1, \
1, 1, 0, 0, \
1, 0, 0, 0, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_F SYM4x4(1, 1, 1, 1, \
1, 0, 0, 0, \
1, 1, 1, 0, \
1, 0, 0, 0)
#define ALPHASQUARE_SYMBOL_G SYM4x4(1, 1, 1, 0, \
1, 0, 0, 0, \
1, 0, 0, 1, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_H SYM4x4(1, 0, 0, 1, \
1, 1, 1, 1, \
1, 0, 0, 1, \
1, 0, 0, 1)
#define ALPHASQUARE_SYMBOL_I SYM4x4(1, 1, 1, 1, \
0, 1, 1, 0, \
0, 1, 1, 0, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_J SYM4x4(1, 1, 1, 1, \
0, 0, 0, 1, \
1, 0, 0, 1, \
0, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_K SYM4x4(1, 0, 0, 1, \
1, 1, 0, 0, \
1, 1, 0, 0, \
1, 0, 1, 1)
#define ALPHASQUARE_SYMBOL_L SYM4x4(1, 0, 0, 0, \
1, 0, 0, 0, \
1, 0, 0, 0, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_M SYM4x4(1, 0, 1, 1, \
1, 1, 1, 1, \
1, 1, 0, 1, \
1, 0, 0, 1)
#define ALPHASQUARE_SYMBOL_N SYM4x4(1, 0, 0, 1, \
1, 1, 0, 1, \
1, 0, 1, 1, \
1, 0, 0, 1)
#define ALPHASQUARE_SYMBOL_O SYM4x4(1, 1, 1, 1, \
1, 0, 0, 1, \
1, 0, 0, 1, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_P SYM4x4(1, 1, 1, 1, \
1, 0, 0, 1, \
1, 1, 1, 1, \
1, 0, 0, 0)
#define ALPHASQUARE_SYMBOL_Q SYM4x4(1, 1, 1, 1, \
1, 0, 0, 1, \
1, 0, 1, 1, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_R SYM4x4(1, 1, 1, 1, \
1, 0, 0, 1, \
1, 1, 1, 0, \
1, 0, 1, 1)
#define ALPHASQUARE_SYMBOL_S SYM4x4(1, 1, 1, 1, \
1, 1, 0, 0, \
0, 0, 1, 1, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_T SYM4x4(1, 1, 1, 1, \
0, 1, 1, 0, \
0, 1, 1, 0, \
0, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_U SYM4x4(1, 0, 0, 1, \
1, 0, 0, 1, \
1, 0, 0, 1, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_V SYM4x4(1, 0, 0, 1, \
1, 0, 0, 1, \
1, 0, 0, 1, \
0, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_W SYM4x4(1, 0, 0, 1, \
1, 0, 1, 1, \
1, 1, 1, 1, \
1, 0, 1, 1)
#define ALPHASQUARE_SYMBOL_X SYM4x4(1, 0, 0, 1, \
0, 1, 1, 0, \
0, 1, 1, 0, \
1, 0, 0, 1)
#define ALPHASQUARE_SYMBOL_Y SYM4x4(1, 0, 0, 1, \
1, 1, 1, 1, \
0, 1, 1, 0, \
0, 1, 1, 0)
#define ALPHASQUARE_SYMBOL_Z SYM4x4(1, 1, 1, 1, \
0, 0, 1, 1, \
1, 1, 0, 0, \
1, 1, 1, 1)
// ---------------------
#define ALPHASQUARE_SYMBOL_1 SYM4x4(0, 1, 1, 0, \
1, 0, 1, 0, \
0, 0, 1, 0, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_2 SYM4x4(0, 1, 1, 0, \
1, 0, 0, 1, \
0, 0, 1, 0, \
1, 1, 0, 1)
#define ALPHASQUARE_SYMBOL_3 SYM4x4(1, 1, 1, 1, \
0, 0, 1, 1, \
0, 0, 0, 1, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_4 SYM4x4(1, 0, 0, 1, \
1, 1, 1, 1, \
0, 0, 0, 1, \
0, 0, 0, 1)
#define ALPHASQUARE_SYMBOL_5 SYM4x4(1, 1, 1, 1, \
1, 0, 0, 0, \
0, 1, 1, 1, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_6 SYM4x4(0, 1, 1, 0, \
1, 0, 0, 0, \
1, 1, 1, 1, \
1, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_7 SYM4x4(1, 1, 1, 1, \
0, 0, 0, 1, \
0, 0, 1, 0, \
0, 1, 0, 0)
#define ALPHASQUARE_SYMBOL_8 SYM4x4(1, 1, 1, 0, \
1, 0, 1, 1, \
1, 1, 0, 1, \
0, 1, 1, 1)
#define ALPHASQUARE_SYMBOL_9 SYM4x4(1, 1, 1, 1, \
1, 0, 0, 1, \
1, 1, 1, 1, \
0, 0, 0, 1)
#define ALPHASQUARE_SYMBOL_0 SYM4x4(0, 1, 1, 0, \
1, 0, 0, 1, \
1, 0, 0, 1, \
0, 1, 1, 0)
#endif

@ -0,0 +1,39 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-AlphaSquare -- 4x4 pixel LED alphabet
* Copyright (C) 2017 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/LED-AlphaSquare.h>
namespace kaleidoscope {
namespace plugin {
namespace alpha_square {
namespace symbols {
/* λ */
static constexpr uint16_t Lambda = SYM4x4(1, 0, 0, 0,
0, 1, 0, 0,
0, 1, 1, 0,
1, 0, 0, 1);
}
}
}
// Backwards compatibility
namespace alpha_square = kaleidoscope::plugin::alpha_square;
}

@ -0,0 +1,144 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-Stalker -- Stalk keys pressed by lighting up and fading back the LED under them
* Copyright (C) 2017, 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/>.
*/
#include <Kaleidoscope-LED-Stalker.h>
namespace kaleidoscope {
namespace plugin {
uint8_t StalkerEffect::map_[ROWS][COLS];
StalkerEffect::ColorComputer *StalkerEffect::variant;
uint16_t StalkerEffect::step_length = 50;
uint16_t StalkerEffect::step_start_time_;
void StalkerEffect::onActivate(void) {
memset(map_, 0, sizeof(map_));
}
EventHandlerResult StalkerEffect::onKeyswitchEvent(Key &mapped_key, byte row, byte col, uint8_t keyState) {
if (row >= ROWS || col >= COLS)
return EventHandlerResult::OK;
if (keyIsPressed(keyState)) {
map_[row][col] = 0xff;
}
return EventHandlerResult::OK;
}
void StalkerEffect::update(void) {
if (!variant)
return;
uint16_t now = millis();
uint16_t elapsed = Kaleidoscope.millisAtCycleStart() - step_start_time_;
for (byte r = 0; r < ROWS; r++) {
for (byte c = 0; c < COLS; c++) {
uint8_t step = map_[r][c];
if (step) {
::LEDControl.setCrgbAt(r, c, variant->compute(&step));
}
if (elapsed > step_length) {
map_[r][c] = step;
}
if (!map_[r][c])
::LEDControl.setCrgbAt(r, c, (cRGB) {
0, 0, 0
});
}
}
if (elapsed > step_length)
step_start_time_ = Kaleidoscope.millisAtCycleStart();
}
namespace stalker {
cRGB Haunt::highlight_color_;
// Haunt
Haunt::Haunt(const cRGB highlight_color) {
highlight_color_ = highlight_color;
}
cRGB Haunt::compute(uint8_t *step) {
cRGB color = CRGB((uint8_t)min(*step * highlight_color_.r / 255, 255),
(uint8_t)min(*step * highlight_color_.g / 255, 255),
(uint8_t)min(*step * highlight_color_.b / 255, 255));
if (*step >= 0xf0)
*step -= 1;
else if (*step >= 0x40)
*step -= 16;
else if (*step >= 32)
*step -= 32;
else
*step = 0;
return color;
}
// BlazingTrail
BlazingTrail::BlazingTrail(void) {
}
cRGB BlazingTrail::compute(uint8_t *step) {
cRGB color;
if (*step >= 0xff - 30) {
color = hsvToRgb(0xff - *step, 255, 255);
} else {
color = hsvToRgb(30, 255, 255);
color.r = min(*step * color.r / 255, 255);
color.g = min(*step * color.g / 255, 255);
}
if (*step >= 0xff - 30)
*step -= 1;
else if (*step >= 0x40)
*step -= 16;
else if (*step >= 32)
*step -= 32;
else
*step = 0;
return color;
}
// Rainbow
Rainbow::Rainbow(void) {
}
cRGB Rainbow::compute(uint8_t *step) {
if (*step > 0)
*step -= 1;
else
*step = 0;
return hsvToRgb(255 - *step, 255, *step);
}
}
}
}
kaleidoscope::plugin::StalkerEffect StalkerEffect;

@ -0,0 +1,80 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LED-Stalker -- Stalk keys pressed by lighting up and fading back the LED under them
* Copyright (C) 2017, 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/>.
*/
#pragma once
#include <Kaleidoscope.h>
#include <Kaleidoscope-LEDControl.h>
#define STALKER(v, ...) ({static kaleidoscope::plugin::stalker::v _effect __VA_ARGS__; &_effect;})
namespace kaleidoscope {
namespace plugin {
class StalkerEffect : public LEDMode {
public:
class ColorComputer {
public:
virtual cRGB compute(uint8_t *step) = 0;
};
StalkerEffect(void) {}
static ColorComputer *variant;
static uint16_t step_length;
EventHandlerResult onKeyswitchEvent(Key &mapped_key, byte row, byte col, uint8_t keyState);
protected:
void onActivate(void) final;
void update(void) final;
private:
static uint16_t step_start_time_;
static uint8_t map_[ROWS][COLS];
};
namespace stalker {
class Haunt : public StalkerEffect::ColorComputer {
public:
explicit Haunt(const cRGB highlight_color);
Haunt(void) : Haunt(CRGB(0x40, 0x80, 0x80)) {}
cRGB compute(uint8_t *step) final;
private:
static cRGB highlight_color_;
};
class BlazingTrail : public StalkerEffect::ColorComputer {
public:
BlazingTrail(void);
cRGB compute(uint8_t *step) final;
};
class Rainbow : public StalkerEffect::ColorComputer {
public:
Rainbow(void);
cRGB compute(uint8_t *step) final;
};
}
}
}
extern kaleidoscope::plugin::StalkerEffect StalkerEffect;

@ -0,0 +1,282 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#include "Kaleidoscope-LEDControl.h"
#include "Kaleidoscope-FocusSerial.h"
namespace kaleidoscope {
namespace plugin {
LEDMode *LEDControl::modes[LED_MAX_MODES];
uint8_t LEDControl::mode;
uint16_t LEDControl::syncDelay = 16;
uint16_t LEDControl::syncTimer;
bool LEDControl::paused = false;
void LEDMode::activate(void) {
::LEDControl.activate(this);
}
kaleidoscope::EventHandlerResult LEDMode::onSetup() {
::LEDControl.mode_add(this);
setup();
return EventHandlerResult::OK;
}
LEDControl::LEDControl(void) {
mode = 0;
memset(modes, 0, LED_MAX_MODES * sizeof(modes[0]));
}
void LEDControl::next_mode(void) {
mode++;
if (mode >= LED_MAX_MODES || !modes[mode]) {
return set_mode(0);
}
return set_mode(mode);
}
void LEDControl::prev_mode(void) {
if (mode == 0) {
// wrap around
mode = LED_MAX_MODES - 1;
// then count down until reaching a valid mode
while (mode > 0 && !modes[mode]) mode--;
} else {
mode--;
}
return set_mode(mode);
}
void
LEDControl::set_mode(uint8_t mode_) {
if (mode_ >= LED_MAX_MODES)
return;
mode = mode_;
refreshAll();
}
uint8_t LEDControl::get_mode_index(void) {
return mode;
}
LEDMode *LEDControl::get_mode(void) {
return modes[mode];
}
void LEDControl::activate(LEDMode *mode) {
for (uint8_t i = 0; i < LED_MAX_MODES; i++) {
if (modes[i] == mode)
return set_mode(i);
}
}
int8_t LEDControl::mode_add(LEDMode *mode) {
for (int i = 0; i < LED_MAX_MODES; i++) {
if (modes[i])
continue;
modes[i] = mode;
return i;
}
return -1;
}
void LEDControl::set_all_leds_to(uint8_t r, uint8_t g, uint8_t b) {
cRGB color;
color.r = r;
color.g = g;
color.b = b;
set_all_leds_to(color);
}
void LEDControl::set_all_leds_to(cRGB color) {
for (uint8_t i = 0; i < LED_COUNT; i++) {
setCrgbAt(i, color);
}
}
void LEDControl::setCrgbAt(uint8_t i, cRGB crgb) {
KeyboardHardware.setCrgbAt(i, crgb);
}
void LEDControl::setCrgbAt(byte row, byte col, cRGB color) {
KeyboardHardware.setCrgbAt(row, col, color);
}
cRGB LEDControl::getCrgbAt(uint8_t i) {
return KeyboardHardware.getCrgbAt(i);
}
void LEDControl::syncLeds(void) {
KeyboardHardware.syncLeds();
}
kaleidoscope::EventHandlerResult LEDControl::onSetup() {
set_all_leds_to({0, 0, 0});
for (uint8_t i = 0; i < LED_MAX_MODES; i++) {
if (modes[i])
(modes[i]->setup)();
}
syncTimer = millis() + syncDelay;
return EventHandlerResult::OK;
}
kaleidoscope::EventHandlerResult LEDControl::onKeyswitchEvent(Key &mappedKey, byte row, byte col, uint8_t keyState) {
if (mappedKey.flags != (SYNTHETIC | IS_INTERNAL | LED_TOGGLE))
return kaleidoscope::EventHandlerResult::OK;
if (keyToggledOn(keyState)) {
if (mappedKey == Key_LEDEffectNext) {
next_mode();
} else if (mappedKey == Key_LEDEffectPrevious) {
prev_mode();
}
}
return kaleidoscope::EventHandlerResult::EVENT_CONSUMED;
}
kaleidoscope::EventHandlerResult LEDControl::beforeReportingState(void) {
if (paused)
return kaleidoscope::EventHandlerResult::OK;
// unsigned subtraction means that as syncTimer rolls over
// the same interval is kept
uint16_t elapsed = Kaleidoscope.millisAtCycleStart() - syncTimer;
// on some platforms, the subtraction in the comparison results in a signed
// operation, resulting in syncLeds() no longer getting called.
if (elapsed > syncDelay) {
syncLeds();
syncTimer += syncDelay;
}
update();
return kaleidoscope::EventHandlerResult::OK;
}
EventHandlerResult FocusLEDCommand::onFocusEvent(const char *command) {
enum {
SETALL,
MODE,
AT,
THEME,
} subCommand;
if (::Focus.handleHelp(command, PSTR("led.at\n"
"led.setAll\n"
"led.mode\n"
"led.theme")))
return EventHandlerResult::OK;
if (strncmp_P(command, PSTR("led."), 4) != 0)
return EventHandlerResult::OK;
if (strcmp_P(command + 4, PSTR("at")) == 0)
subCommand = AT;
else if (strcmp_P(command + 4, PSTR("setAll")) == 0)
subCommand = SETALL;
else if (strcmp_P(command + 4, PSTR("mode")) == 0)
subCommand = MODE;
else if (strcmp_P(command + 4, PSTR("theme")) == 0)
subCommand = THEME;
else
return EventHandlerResult::OK;
switch (subCommand) {
case AT: {
uint8_t idx = Serial.parseInt();
if (Serial.peek() == '\n') {
cRGB c = ::LEDControl.getCrgbAt(idx);
::Focus.printColor(c.r, c.g, c.b);
Serial.println();
} else {
cRGB c;
::Focus.readColor(c);
::LEDControl.setCrgbAt(idx, c);
}
break;
}
case SETALL: {
cRGB c;
::Focus.readColor(c);
::LEDControl.set_all_leds_to(c);
break;
}
case MODE: {
char peek = Serial.peek();
if (peek == '\n') {
Serial.println(::LEDControl.get_mode_index());
} else if (peek == 'n') {
::LEDControl.next_mode();
Serial.read();
} else if (peek == 'p') {
::LEDControl.prev_mode();
Serial.read();
} else {
uint8_t mode = Serial.parseInt();
::LEDControl.set_mode(mode);
}
break;
}
case THEME: {
if (Serial.peek() == '\n') {
for (uint8_t idx = 0; idx < LED_COUNT; idx++) {
cRGB c = ::LEDControl.getCrgbAt(idx);
::Focus.printColor(c.r, c.g, c.b);
::Focus.printSpace();
}
Serial.println();
break;
}
uint8_t idx = 0;
while (idx < LED_COUNT && Serial.peek() != '\n') {
cRGB color;
::Focus.readColor(color);
::LEDControl.setCrgbAt(idx, color);
idx++;
}
break;
}
}
return EventHandlerResult::EVENT_CONSUMED;
}
}
}
kaleidoscope::plugin::LEDControl LEDControl;
kaleidoscope::plugin::FocusLEDCommand FocusLEDCommand;

@ -0,0 +1,170 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#pragma once
#include <Kaleidoscope.h>
#define LED_MAX_MODES 24
#define LED_TOGGLE B00000001 // Synthetic, internal
#define Key_LEDEffectNext (Key) { 0, KEY_FLAGS | SYNTHETIC | IS_INTERNAL | LED_TOGGLE }
#define Key_LEDEffectPrevious (Key) { 1, KEY_FLAGS | SYNTHETIC | IS_INTERNAL | LED_TOGGLE }
namespace kaleidoscope {
namespace plugin {
/** Base class for LED modes.
*
* LED modes are a special kind of plugin, they are in charge of updating LED
* colors, setting a theme. While it is possible to have other plugins
* override the mode's colors, the LED mode is the baseline.
*
* Most of its functionality is called via @ref LEDControl, with only a few
* public methods.
*
* A LED mode **must** implement at least one of @ref onActivate or @ref
* update, and possibly @ref refreshAt too.
*/
class LEDMode : public kaleidoscope::Plugin {
friend class LEDControl;
protected:
// These methods should only be called by LEDControl.
/** One-time setup, called at keyboard boot.
*
* Any hooks that need registering, any one-time setup that needs to be
* performed, shall be done here. This is purely for preparation purposes, the
* LEDs should not be touched yet at this time.
*/
virtual void setup(void) {}
/** Function to call whenever the mode is activated.
*
* Like @ref setup, this method need not touch LEDs, @ref update will be
* called right after it. The purpose of this callback is to allow a plugin to
* do some preparation whenever it is activated, instead of only on boot, or
* always at each cycle.
*
* However, unlike @ref setup, this method can change LED colors, if so
* desired. Either to provide an initial state, or a static color set. In the
* latter case, consider implementing @ref refreshAt too, because other
* plugins may override some of the colors set at activation time, and @ref
* refreshAt can be used to restore them when needed.
*
* Before the callback runs, LEDs will be blanked.
*/
virtual void onActivate(void) {}
/** Update the LEDs once per cycle.
*
* Usually the brains of the plugin, which updates the LEDs each cycle. It is
* called after the matrix has been scanned, once per cycle.
*/
virtual void update(void) {}
/** Refresh the color of a given key.
*
* If we have another plugin that overrides colors set by the active LED mode
* (either at @onActivate time, or via @ref update), if that plugin wants to
* restore whatever color the mode would set the key color to, this is the
* method it will call.
*
* @param row is the row coordinate of the key to refresh the color of.
* @param col is the column coordinate of the key to refresh the color of.
*/
virtual void refreshAt(byte row, byte col) {}
public:
/** Activate the current object as the LED mode.
*/
void activate(void);
/** Plugin initialization.
*
* Called via `Kaleidoscope.use()`, registers the LED mode, and does the
* necessary initialization steps. Calls @ref setup at the end.
*/
kaleidoscope::EventHandlerResult onSetup();
};
class LEDControl : public kaleidoscope::Plugin {
public:
LEDControl(void);
static void next_mode(void);
static void prev_mode(void);
static void setup(void);
static void update(void) {
if (modes[mode])
modes[mode]->update();
}
static void refreshAt(byte row, byte col) {
if (modes[mode])
modes[mode]->refreshAt(row, col);
}
static void set_mode(uint8_t mode);
static uint8_t get_mode_index();
static LEDMode *get_mode();
static void refreshAll() {
if (paused)
return;
set_all_leds_to({0, 0, 0});
if (modes[mode])
modes[mode]->onActivate();
}
static int8_t mode_add(LEDMode *mode);
static void setCrgbAt(uint8_t i, cRGB crgb);
static void setCrgbAt(byte row, byte col, cRGB color);
static cRGB getCrgbAt(uint8_t i);
static void syncLeds(void);
static void set_all_leds_to(uint8_t r, uint8_t g, uint8_t b);
static void set_all_leds_to(cRGB color);
static void activate(LEDMode *mode);
static uint16_t syncDelay;
static bool paused;
kaleidoscope::EventHandlerResult onSetup();
kaleidoscope::EventHandlerResult onKeyswitchEvent(Key &mappedKey, byte row, byte col, uint8_t keyState);
kaleidoscope::EventHandlerResult beforeReportingState();
private:
static uint16_t syncTimer;
static LEDMode *modes[LED_MAX_MODES];
static uint8_t mode;
};
class FocusLEDCommand : public Plugin {
public:
FocusLEDCommand() {}
EventHandlerResult onFocusEvent(const char *command);
};
}
// Backwards compatibility
typedef plugin::LEDMode LEDMode;
}
extern kaleidoscope::plugin::LEDControl LEDControl;
extern kaleidoscope::plugin::FocusLEDCommand FocusLEDCommand;

@ -0,0 +1,51 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#include "kaleidoscope/plugin/LEDControl/BootAnimation.h"
#include "Kaleidoscope-LEDControl.h"
#ifdef ARDUINO_AVR_MODEL01
static void
type_letter(uint8_t letter) {
LEDControl.setCrgbAt(letter, {255, 0, 0});
LEDControl.syncLeds();
delay(250);
LEDControl.setCrgbAt(letter, {0, 0, 0});
LEDControl.syncLeds();
delay(10);
}
#endif
void
bootAnimation(void) {
#ifdef ARDUINO_AVR_MODEL01
LEDControl.set_all_leds_to(0, 0, 0);
type_letter(LED_K);
type_letter(LED_E);
type_letter(LED_Y);
type_letter(LED_B);
type_letter(LED_O);
type_letter(LED_A);
type_letter(LED_R);
type_letter(LED_D);
type_letter(LED_I);
type_letter(LED_O);
type_letter(LED_SPACE);
type_letter(LED_0);
type_letter(LED_PERIOD);
type_letter(LED_9);
#endif
}

@ -0,0 +1,19 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#pragma once
void bootAnimation(void);

@ -0,0 +1,31 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#include "kaleidoscope/plugin/LEDControl/LED-Off.h"
namespace kaleidoscope {
namespace plugin {
void LEDOff::onActivate(void) {
::LEDControl.set_all_leds_to({0, 0, 0});
}
void LEDOff::refreshAt(byte row, byte col) {
::LEDControl.setCrgbAt(row, col, {0, 0, 0});
}
}
}
kaleidoscope::plugin::LEDOff LEDOff;

@ -0,0 +1,34 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "Kaleidoscope-LEDControl.h"
namespace kaleidoscope {
namespace plugin {
class LEDOff : public LEDMode {
public:
LEDOff(void) { }
protected:
void onActivate(void) final;
void refreshAt(byte row, byte col) final;
};
}
}
extern kaleidoscope::plugin::LEDOff LEDOff;

@ -0,0 +1,104 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#include "kaleidoscope/plugin/LEDControl/LEDUtils.h"
cRGB
breath_compute(uint8_t hue, uint8_t saturation) {
// This code is adapted from FastLED lib8tion.h as of dd5d96c6b289cb6b4b891748a4aeef3ddceaf0e6
// Eventually, we should consider just using FastLED
// We do a bit shift here instead of division to ensure that there's no discontinuity
// in the output brightness when the integer overflows.
uint8_t i = (uint16_t)millis() >> 4;
if (i & 0x80) {
i = 255 - i;
}
i = i << 1;
uint8_t ii = (i * i) >> 8;
uint8_t iii = (ii * i) >> 8;
i = (((3 * (uint16_t)(ii)) - (2 * (uint16_t)(iii))) / 2) + 80;
return hsvToRgb(hue, saturation, i);
}
//For rgb to hsv, might take a look at: http://web.mit.edu/storborg/Public/hsvtorgb.c
// From http://web.mit.edu/storborg/Public/hsvtorgb.c - talk to Scott about licensing
cRGB
hsvToRgb(uint16_t h, uint16_t s, uint16_t v) {
cRGB color;
/* HSV to RGB conversion function with only integer
* math */
uint16_t region, fpart, p, q, t;
if (s == 0) {
/* color is grayscale */
color.r = color.g = color.b = v;
return color;
}
/* make hue 0-5 */
region = (h * 6) >> 8;
/* find remainder part, make it from 0-255 */
fpart = (h * 6) - (region << 8);
/* calculate temp vars, doing integer multiplication */
p = (v * (255 - s)) >> 8;
q = (v * (255 - ((s * fpart) >> 8))) >> 8;
t = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8;
/* assign temp vars based on color cone region */
switch (region) {
case 0:
color.r = v;
color.g = t;
color.b = p;
break;
case 1:
color.r = q;
color.g = v;
color.b = p;
break;
case 2:
color.r = p;
color.g = v;
color.b = t;
break;
case 3:
color.r = p;
color.g = q;
color.b = v;
break;
case 4:
color.r = t;
color.g = p;
color.b = v;
break;
default:
color.r = v;
color.g = p;
color.b = q;
break;
}
return color;
}

@ -0,0 +1,22 @@
/* Kaleidoscope-LEDControl - LED control plugin for Kaleidoscope
* Copyright (C) 2017-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/>.
*/
#pragma once
#include <Kaleidoscope.h>
cRGB breath_compute(uint8_t hue = 170, uint8_t saturation = 255);
cRGB hsvToRgb(uint16_t h, uint16_t s, uint16_t v);

@ -0,0 +1,94 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LEDEffect-BootGreeting -- Small greeting at boot time
* Copyright (C) 2017, 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/>.
*/
#include "Kaleidoscope-LEDEffect-BootGreeting.h"
namespace kaleidoscope {
namespace plugin {
bool BootGreetingEffect::done_ = false;
byte BootGreetingEffect::row_;
byte BootGreetingEffect::col_;
byte BootGreetingEffect::key_row = 255;
byte BootGreetingEffect::key_col = 255;
Key BootGreetingEffect::search_key = Key_LEDEffectNext;
uint8_t BootGreetingEffect::hue = 170;
uint16_t BootGreetingEffect::start_time = 0;
uint16_t BootGreetingEffect::timeout = 9200;
BootGreetingEffect::BootGreetingEffect(byte pos_row, byte pos_col) {
key_row = pos_row;
key_col = pos_col;
}
void BootGreetingEffect::findLed(void) {
if (key_col != 255 && key_row != 255) {
row_ = key_row;
col_ = key_col;
done_ = true;
return;
}
// Find the LED key.
for (uint8_t r = 0; r < ROWS; r++) {
for (uint8_t c = 0; c < COLS; c++) {
Key k = Layer.lookupOnActiveLayer(r, c);
if (k.raw == search_key.raw) {
row_ = r;
col_ = c;
return;
}
}
}
// We didn't find the LED key. Let's just pretend we're "done".
done_ = true;
}
EventHandlerResult BootGreetingEffect::afterEachCycle() {
//If already done or we're not in a ready state, bail
if (done_) {
return EventHandlerResult::OK;
}
//If the start time isn't set, set the start time and
//find the LEDs.
if (start_time == 0) {
start_time = millis();
findLed();
//the first time, don't do anything.
return EventHandlerResult::OK;
}
//Only run for 'timeout' milliseconds
if ((millis() - start_time) > timeout) {
done_ = true;
::LEDControl.refreshAt(row_, col_);
return EventHandlerResult::OK;
}
cRGB color = breath_compute(hue);
::LEDControl.setCrgbAt(row_, col_, color);
return EventHandlerResult::OK;
}
}
}
kaleidoscope::plugin::BootGreetingEffect BootGreetingEffect;

@ -0,0 +1,47 @@
/* -*- mode: c++ -*-
* Kaleidoscope-LEDEffect-BootGreeting -- Small greeting at boot time
* Copyright (C) 2017, 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/>.
*/
#pragma once
#include "Kaleidoscope-LEDControl.h"
namespace kaleidoscope {
namespace plugin {
class BootGreetingEffect : public kaleidoscope::Plugin {
public:
BootGreetingEffect(void) {}
BootGreetingEffect(byte, byte);
static byte key_row;
static byte key_col;
static Key search_key;
static uint8_t hue;
static uint16_t timeout;
EventHandlerResult afterEachCycle();
private:
static void findLed(void);
static bool done_;
static byte row_;
static byte col_;
static uint16_t start_time;
};
}
}
extern kaleidoscope::plugin::BootGreetingEffect BootGreetingEffect;

@ -0,0 +1,35 @@
/* Kaleidoscope-LEDEffect-Breathe - A breathing effect on the LEDs, for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#include "Kaleidoscope-LEDEffect-Breathe.h"
#define UPDATE_INTERVAL 50 // milliseconds between two LED updates to avoid overloading; 20 fps
namespace kaleidoscope {
namespace plugin {
void LEDBreatheEffect::update(void) {
uint16_t now = Kaleidoscope.millisAtCycleStart();
if ((now - last_update_) < UPDATE_INTERVAL)
return;
last_update_ = now;
cRGB color = breath_compute(hue, saturation);
::LEDControl.set_all_leds_to(color);
}
}
}
kaleidoscope::plugin::LEDBreatheEffect LEDBreatheEffect;

@ -0,0 +1,39 @@
/* Kaleidoscope-LEDEffect-Breathe - A breathing effect on the LEDs, for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "Kaleidoscope-LEDControl.h"
namespace kaleidoscope {
namespace plugin {
class LEDBreatheEffect : public LEDMode {
public:
LEDBreatheEffect(void) {}
uint8_t hue = 170;
uint8_t saturation = 255;
protected:
void update(void) final;
private:
uint16_t last_update_ = 0;
};
}
}
extern kaleidoscope::plugin::LEDBreatheEffect LEDBreatheEffect;

@ -0,0 +1,66 @@
/* Kaleidoscope-LEDEffect-Chase - A Chase LED effect for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#include "Kaleidoscope-LEDEffect-Chase.h"
namespace kaleidoscope {
namespace plugin {
void LEDChaseEffect::update(void) {
// Check to see if it's time to change the positions of the red and blue lights
if (current_chase_counter++ < chase_threshold) {
return;
}
current_chase_counter = 0;
// The red LED is at `pos`; the blue one follows behind. `chase_sign` is either +1 or
// -1; `chase_pixels` is the gap between them.
byte pos2 = pos - (chase_sign * chase_pixels);
// First, we turn off the LEDs that were turned on in the previous update. `pos` is
// always in the valid range (0 <= pos < LED_COUNT), but after it changes direction, for
// the first few updates, `pos2` will be out of bounds. Since it's an unsigned integer,
// even when it would have a value below zero, it underflows and so one test is good for
// both ends of the range.
::LEDControl.setCrgbAt(pos, {0, 0, 0});
if (pos2 < LED_COUNT)
::LEDControl.setCrgbAt(pos2, {0, 0, 0});
// Next, we adjust the red light's position. If the direction hasn't changed (the red
// light isn't out of bounds), we also adjust the blue light's position to match the red
// one. If the new position puts it out of bounds, we reverse the direction, and bring
// it back in bounds. When this happens, the blue light "jumps" behind the red one, and
// will be out of bounds. The simplest way to do this is to assign it a value that is
// known to be invalid (LED_COUNT).
pos += chase_sign;
if (pos < LED_COUNT) {
pos2 += chase_sign;
} else {
chase_sign = -chase_sign;
pos += chase_sign;
pos2 = LED_COUNT;
}
// Last, we turn on the LEDs at their new positions. As before, the blue light (pos2) is
// only set if it's in the valid LED range.
::LEDControl.setCrgbAt(pos, {0, 0, 255});
if (pos2 < LED_COUNT)
::LEDControl.setCrgbAt(pos2, {255, 0, 0});
}
}
}
kaleidoscope::plugin::LEDChaseEffect LEDChaseEffect;

@ -0,0 +1,40 @@
/* Kaleidoscope-LEDEffect-Chase - A Chase LED effect for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "Kaleidoscope-LEDControl.h"
namespace kaleidoscope {
namespace plugin {
class LEDChaseEffect : public LEDMode {
public:
LEDChaseEffect(void) {}
protected:
void update(void) final;
private:
uint8_t pos = 0;
int8_t chase_sign = 1; //negative values when it's going backwar
uint8_t chase_pixels = 5;
uint8_t current_chase_counter = 0;
static const uint8_t chase_threshold = 150;
};
}
}
extern kaleidoscope::plugin::LEDChaseEffect LEDChaseEffect;

@ -0,0 +1,84 @@
/* Kaleidoscope-LEDEffect-Rainbow - Rainbow LED effects for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#include "Kaleidoscope-LEDEffect-Rainbow.h"
namespace kaleidoscope {
namespace plugin {
void LEDRainbowEffect::update(void) {
uint16_t now = millis();
if ((now - rainbow_last_update) < rainbow_update_delay) {
return;
} else {
rainbow_last_update = now;
}
cRGB rainbow = hsvToRgb(rainbow_hue, rainbow_saturation, rainbow_value);
rainbow_hue += rainbow_steps;
if (rainbow_hue >= 255) {
rainbow_hue -= 255;
}
::LEDControl.set_all_leds_to(rainbow);
}
void LEDRainbowEffect::brightness(byte brightness) {
rainbow_value = brightness;
}
void LEDRainbowEffect::update_delay(byte delay) {
rainbow_update_delay = delay;
}
// ---------
void LEDRainbowWaveEffect::update(void) {
uint16_t now = millis();
if ((now - rainbow_last_update) < rainbow_update_delay) {
return;
} else {
rainbow_last_update = now;
}
for (uint8_t i = 0; i < LED_COUNT; i++) {
uint16_t key_hue = rainbow_hue + 16 * (i / 4);
if (key_hue >= 255) {
key_hue -= 255;
}
cRGB rainbow = hsvToRgb(key_hue, rainbow_saturation, rainbow_value);
::LEDControl.setCrgbAt(i, rainbow);
}
rainbow_hue += rainbow_wave_steps;
if (rainbow_hue >= 255) {
rainbow_hue -= 255;
}
}
void LEDRainbowWaveEffect::brightness(byte brightness) {
rainbow_value = brightness;
}
void LEDRainbowWaveEffect::update_delay(byte delay) {
rainbow_update_delay = delay;
}
}
}
kaleidoscope::plugin::LEDRainbowEffect LEDRainbowEffect;
kaleidoscope::plugin::LEDRainbowWaveEffect LEDRainbowWaveEffect;

@ -0,0 +1,77 @@
/* Kaleidoscope-LEDEffect-Rainbow - Rainbow LED effects for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include "Kaleidoscope-LEDControl.h"
namespace kaleidoscope {
namespace plugin {
class LEDRainbowEffect : public LEDMode {
public:
LEDRainbowEffect(void) {}
void brightness(byte);
byte brightness(void) {
return rainbow_value;
}
void update_delay(byte);
byte update_delay(void) {
return rainbow_update_delay;
}
void update(void) final;
private:
uint16_t rainbow_hue = 0; // stores 0 to 614
uint8_t rainbow_steps = 1; // number of hues we skip in a 360 range per update
uint16_t rainbow_last_update = 0;
uint16_t rainbow_update_delay = 40; // delay between updates (ms)
byte rainbow_saturation = 255;
byte rainbow_value = 50;
};
class LEDRainbowWaveEffect : public LEDMode {
public:
LEDRainbowWaveEffect(void) {}
void brightness(byte);
byte brightness(void) {
return rainbow_value;
}
void update_delay(byte);
byte update_delay(void) {
return rainbow_update_delay;
}
void update(void) final;
private:
uint16_t rainbow_hue = 0; // stores 0 to 614
uint8_t rainbow_wave_steps = 1; // number of hues we skip in a 360 range per update
uint16_t rainbow_last_update = 0;
uint16_t rainbow_update_delay = 40; // delay between updates (ms)
byte rainbow_saturation = 255;
byte rainbow_value = 50;
};
}
}
extern kaleidoscope::plugin::LEDRainbowEffect LEDRainbowEffect;
extern kaleidoscope::plugin::LEDRainbowWaveEffect LEDRainbowWaveEffect;

@ -0,0 +1,36 @@
/* Kaleidoscope-LEDEffect-SolidColor - Solid color LED effects for Kaleidoscope.
* Copyright (C) 2017 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-LEDEffect-SolidColor.h"
namespace kaleidoscope {
namespace plugin {
LEDSolidColor::LEDSolidColor(uint8_t r, uint8_t g, uint8_t b) {
this->r = r;
this->g = g;
this->b = b;
}
void LEDSolidColor::onActivate(void) {
::LEDControl.set_all_leds_to(r, g, b);
}
void LEDSolidColor::refreshAt(byte row, byte col) {
::LEDControl.setCrgbAt(row, col, CRGB(r, g, b));
}
}
}

@ -0,0 +1,39 @@
/* Kaleidoscope-LEDEffect-SolidColor - Solid color LED effects for Kaleidoscope.
* Copyright (C) 2017 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-LEDControl.h"
namespace kaleidoscope {
namespace plugin {
class LEDSolidColor : public LEDMode {
public:
LEDSolidColor(uint8_t r, uint8_t g, uint8_t b);
protected:
void onActivate(void) final;
void refreshAt(byte row, byte col) final;
private:
uint8_t r, g, b;
};
}
// Backwards compatibility
typedef plugin::LEDSolidColor LEDSolidColor;
}

@ -0,0 +1,244 @@
/* Kaleidoscope-Macros - Macro keys for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#include "Kaleidoscope-Macros.h"
#include "kaleidoscope/hid.h"
__attribute__((weak))
const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
return MACRO_NONE;
}
namespace kaleidoscope {
namespace plugin {
MacroKeyEvent Macros_::active_macros[];
byte Macros_::active_macro_count;
byte Macros_::row, Macros_::col;
void playMacroKeyswitchEvent(Key key, uint8_t keyswitch_state) {
handleKeyswitchEvent(key, UNKNOWN_KEYSWITCH_LOCATION, keyswitch_state | INJECTED);
kaleidoscope::hid::sendKeyboardReport();
kaleidoscope::hid::sendMouseReport();
}
static void readKeyCodeAndPlay(const macro_t *macro_p, uint8_t flags, uint8_t keyStates) {
Key key;
key.flags = flags;
key.keyCode = pgm_read_byte(macro_p++);
if (keyIsPressed(keyStates)) {
playMacroKeyswitchEvent(key, IS_PRESSED);
}
if (keyWasPressed(keyStates)) {
playMacroKeyswitchEvent(key, WAS_PRESSED);
}
}
void Macros_::play(const macro_t *macro_p) {
macro_t macro = MACRO_ACTION_END;
uint8_t interval = 0;
uint8_t flags;
if (!macro_p)
return;
while (true) {
switch (macro = pgm_read_byte(macro_p++)) {
case MACRO_ACTION_STEP_INTERVAL:
interval = pgm_read_byte(macro_p++);
break;
case MACRO_ACTION_STEP_WAIT: {
uint8_t wait = pgm_read_byte(macro_p++);
delay(wait);
break;
}
case MACRO_ACTION_STEP_KEYDOWN:
flags = pgm_read_byte(macro_p++);
readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED);
break;
case MACRO_ACTION_STEP_KEYUP:
flags = pgm_read_byte(macro_p++);
readKeyCodeAndPlay(macro_p++, flags, WAS_PRESSED);
break;
case MACRO_ACTION_STEP_TAP:
flags = pgm_read_byte(macro_p++);
readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED | WAS_PRESSED);
break;
case MACRO_ACTION_STEP_KEYCODEDOWN:
readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED);
break;
case MACRO_ACTION_STEP_KEYCODEUP:
readKeyCodeAndPlay(macro_p++, 0, WAS_PRESSED);
break;
case MACRO_ACTION_STEP_TAPCODE:
readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED | WAS_PRESSED);
break;
case MACRO_ACTION_END:
default:
return;
}
delay(interval);
}
}
static const Key ascii_to_key_map[] PROGMEM = {
// 0x21 - 0x30
LSHIFT(Key_1),
LSHIFT(Key_Quote),
LSHIFT(Key_3),
LSHIFT(Key_4),
LSHIFT(Key_5),
LSHIFT(Key_7),
Key_Quote,
LSHIFT(Key_9),
LSHIFT(Key_0),
LSHIFT(Key_8),
LSHIFT(Key_Equals),
Key_Comma,
Key_Minus,
Key_Period,
Key_Slash,
Key_0,
// 0x3a ... 0x40
LSHIFT(Key_Semicolon),
Key_Semicolon,
LSHIFT(Key_Comma),
Key_Equals,
LSHIFT(Key_Period),
LSHIFT(Key_Slash),
LSHIFT(Key_2),
// 0x5b ... 0x60
Key_LeftBracket,
Key_Backslash,
Key_RightBracket,
LSHIFT(Key_6),
LSHIFT(Key_Minus),
Key_Backtick,
// 0x7b ... 0x7e
LSHIFT(Key_LeftBracket),
LSHIFT(Key_Backslash),
LSHIFT(Key_RightBracket),
LSHIFT(Key_Backtick),
};
Key Macros_::lookupAsciiCode(uint8_t ascii_code) {
Key key = Key_NoKey;
switch (ascii_code) {
case 0x08 ... 0x09:
key.keyCode = Key_Backspace.keyCode + ascii_code - 0x08;
break;
case 0x0A:
key.keyCode = Key_Enter.keyCode;
break;
case 0x1B:
key.keyCode = Key_Escape.keyCode;
break;
case 0x20:
key.keyCode = Key_Spacebar.keyCode;
break;
case 0x21 ... 0x30:
key.raw = pgm_read_word(&ascii_to_key_map[ascii_code - 0x21]);
break;
case 0x31 ... 0x39:
key.keyCode = Key_1.keyCode + ascii_code - 0x31;
break;
case 0x3A ... 0x40:
key.raw = pgm_read_word(&ascii_to_key_map[ascii_code - 0x3A + 16]);
break;
case 0x41 ... 0x5A:
key.flags = SHIFT_HELD;
key.keyCode = Key_A.keyCode + ascii_code - 0x41;
break;
case 0x5B ... 0x60:
key.raw = pgm_read_word(&ascii_to_key_map[ascii_code - 0x5B + 23]);
break;
case 0x61 ... 0x7A:
key.keyCode = Key_A.keyCode + ascii_code - 0x61;
break;
case 0x7B ... 0x7E:
key.raw = pgm_read_word(&ascii_to_key_map[ascii_code - 0x7B + 29]);
break;
}
return key;
}
const macro_t *Macros_::type(const char *string) {
while (true) {
uint8_t ascii_code = pgm_read_byte(string++);
if (!ascii_code)
break;
Key key = lookupAsciiCode(ascii_code);
if (key.raw == Key_NoKey.raw)
continue;
playMacroKeyswitchEvent(key, IS_PRESSED);
playMacroKeyswitchEvent(key, WAS_PRESSED);
}
return MACRO_NONE;
}
EventHandlerResult Macros_::onKeyswitchEvent(Key &mappedKey, byte row, byte col, uint8_t keyState) {
if (mappedKey.flags != (SYNTHETIC | IS_MACRO))
return EventHandlerResult::OK;
byte key_id = (row * COLS) + col;
addActiveMacroKey(mappedKey.keyCode, key_id, keyState);
return EventHandlerResult::EVENT_CONSUMED;
}
EventHandlerResult Macros_::afterEachCycle() {
active_macro_count = 0;
return EventHandlerResult::OK;
}
EventHandlerResult Macros_::beforeReportingState() {
for (byte i = 0; i < active_macro_count; ++i) {
if (active_macros[i].key_id == 0xFF) {
// i.e. UNKNOWN_KEYSWITCH_LOCATION
row = 0xFF;
col = 0xFF;
} else {
row = active_macros[i].key_id / COLS;
col = active_macros[i].key_id % COLS;
}
const macro_t *m = macroAction(active_macros[i].key_code,
active_macros[i].key_state);
Macros.play(m);
}
return EventHandlerResult::OK;
}
}
}
kaleidoscope::plugin::Macros_ Macros;

@ -0,0 +1,86 @@
/* Kaleidoscope-Macros - Macro keys for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#include <Kaleidoscope.h>
#include "kaleidoscope/plugin/Macros/MacroKeyDefs.h"
#include "kaleidoscope/plugin/Macros/MacroSteps.h"
const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState);
#if !defined(MAX_CONCURRENT_MACROS)
#define MAX_CONCURRENT_MACROS 8
#endif
struct MacroKeyEvent {
byte key_code;
byte key_id;
byte key_state;
};
namespace kaleidoscope {
namespace plugin {
class Macros_ : public kaleidoscope::Plugin {
public:
Macros_(void) {}
static MacroKeyEvent active_macros[MAX_CONCURRENT_MACROS];
static byte active_macro_count;
static void addActiveMacroKey(byte key_code, byte key_id, byte key_state) {
// If we've got too many active macros, give up:
if (active_macro_count >= MAX_CONCURRENT_MACROS) {
return;
}
active_macros[active_macro_count].key_code = key_code;
active_macros[active_macro_count].key_id = key_id;
active_macros[active_macro_count].key_state = key_state;
++active_macro_count;
}
EventHandlerResult onKeyswitchEvent(Key &mappedKey, byte row, byte col, uint8_t keyState);
EventHandlerResult beforeReportingState();
EventHandlerResult afterEachCycle();
void play(const macro_t *macro_p);
/* What follows below, is a bit of template magic that allows us to use
Macros.type() with any number of arguments, without having to use a
sentinel. See the comments on Kaleidoscope.use() for more details - this is
the same trick.
*/
inline const macro_t *type() {
return MACRO_NONE;
}
const macro_t *type(const char *string);
template <typename... Strings>
const macro_t *type(const char *first, Strings&&... strings) {
type(first);
return type(strings...);
}
static byte row, col;
private:
Key lookupAsciiCode(uint8_t ascii_code);
};
}
}
extern kaleidoscope::plugin::Macros_ Macros;

@ -0,0 +1,31 @@
/* Kaleidoscope-Macros - Macro keys for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
#define IS_MACRO B00100000
#define M(n) (Key){ n, KEY_FLAGS|SYNTHETIC|IS_MACRO }
#define Key_macroKey1 M(1)
#define Key_macroKey2 M(2)
#define Key_macroKey3 M(3)
#define Key_macroKey4 M(4)
#define Key_macroKey5 M(5)
#define Key_macroKey6 M(6)
#define Key_macroKey7 M(7)
#define Key_macroKey8 M(8)
#define Key_macroKey9 M(9)
#define Key_macroKey10 M(10)

@ -0,0 +1,54 @@
/* Kaleidoscope-Macros - Macro keys for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#pragma once
typedef enum {
MACRO_ACTION_END,
MACRO_ACTION_STEP_INTERVAL,
MACRO_ACTION_STEP_WAIT,
MACRO_ACTION_STEP_KEYDOWN,
MACRO_ACTION_STEP_KEYUP,
MACRO_ACTION_STEP_TAP,
MACRO_ACTION_STEP_KEYCODEDOWN,
MACRO_ACTION_STEP_KEYCODEUP,
MACRO_ACTION_STEP_TAPCODE,
} MacroActionStepType;
typedef uint8_t macro_t;
#define MACRO_NONE 0
#define MACRO(...) ({static const macro_t __m[] PROGMEM = { __VA_ARGS__, MACRO_ACTION_END }; &__m[0]; })
#define MACRODOWN(...) (keyToggledOn(keyState) ? MACRO(__VA_ARGS__) : MACRO_NONE)
#define I(n) MACRO_ACTION_STEP_INTERVAL, n
#define W(n) MACRO_ACTION_STEP_WAIT, n
#define Dr(k) MACRO_ACTION_STEP_KEYDOWN, (k).flags, (k).keyCode
#define D(k) Dr(Key_ ## k)
#define Ur(k) MACRO_ACTION_STEP_KEYUP, (k).flags, (k).keyCode
#define U(k) Ur(Key_ ## k)
#define Tr(k) MACRO_ACTION_STEP_TAP, (k).flags, (k).keyCode
#define T(k) Tr(Key_ ## k)
#define Dc(k) MACRO_ACTION_STEP_KEYCODEDOWN, (Key_ ## k).keyCode
#define Uc(k) MACRO_ACTION_STEP_KEYCODEUP, (Key_ ## k).keyCode
#define Tc(k) MACRO_ACTION_STEP_TAPCODE, (Key_ ## k).keyCode
__attribute__((deprecated("END is no longer required to end macros"))) const MacroActionStepType END = MACRO_ACTION_END;

@ -0,0 +1,59 @@
/* -*- mode: c++ -*-
* Kaleidoscope-MagicCombo -- Magic combo framework
* Copyright (C) 2016, 2017, 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/>.
*/
#include <Kaleidoscope-MagicCombo.h>
namespace kaleidoscope {
namespace plugin {
uint16_t MagicCombo::min_interval = 500;
uint32_t MagicCombo::end_time_;
EventHandlerResult MagicCombo::beforeReportingState() {
for (byte i = 0; i < magiccombo::combos_length; i++) {
bool match = true;
byte j;
for (j = 0; j < MAX_COMBO_LENGTH; j++) {
int8_t comboKey = pgm_read_byte(&(magiccombo::combos[i].keys[j]));
if (comboKey == 0)
break;
match &= KeyboardHardware.isKeyswitchPressed(comboKey);
if (!match)
break;
}
if (j != KeyboardHardware.pressedKeyswitchCount())
match = false;
if (match && (millis() >= end_time_)) {
ComboAction action = (ComboAction) pgm_read_ptr(&(magiccombo::combos[i].action));
(*action)(i);
end_time_ = millis() + min_interval;
}
}
return EventHandlerResult::OK;
}
}
}
kaleidoscope::plugin::MagicCombo MagicCombo;

@ -0,0 +1,84 @@
/* -*- mode: c++ -*-
* Kaleidoscope-MagicCombo -- Magic combo framework
* Copyright (C) 2016, 2017, 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/>.
*/
#pragma once
#include <Kaleidoscope.h>
#define MAX_COMBO_LENGTH 5
#define USE_MAGIC_COMBOS(...) \
namespace kaleidoscope { \
namespace plugin { \
namespace magiccombo { \
const kaleidoscope::plugin::MagicCombo::Combo combos[] PROGMEM = \
{__VA_ARGS__}; \
\
const uint8_t combos_length = sizeof(combos) / sizeof(*combos); \
} \
} \
}
#define _MAGICCOMBO_API_CHANGE \
"The MagicCombo API changed in an incompatible way, you will need to\n" \
"upgrade.\n" \
"\n" \
"Please see the `UPGRADING.md` document shipped with the source:\n" \
" https://github.com/keyboardio/Kaleidoscope-MagicCombo/blob/master/UPGRADING.md"
namespace kaleidoscope {
namespace plugin {
class MagicCombo : public kaleidoscope::Plugin {
public:
typedef void (*ComboAction)(uint8_t combo_index);
typedef struct {
ComboAction action;
int8_t keys[MAX_COMBO_LENGTH + 1];
} Combo;
typedef struct combo_t {
uint32_t left_hand, right_hand;
template <typename T>
combo_t(T l, T r) {
static_assert(sizeof(T) < 0, _DEPRECATE(_MAGICCOMBO_API_CHANGE));
}
} combo_t;
MagicCombo(void) {}
static const combo_t *magic_combos;
static uint16_t min_interval;
EventHandlerResult beforeReportingState();
private:
static uint32_t end_time_;
};
namespace magiccombo {
extern const MagicCombo::Combo combos[];
extern const uint8_t combos_length;
}
}
// Backward compatibility
typedef plugin::MagicCombo MagicCombo;
}
extern kaleidoscope::plugin::MagicCombo MagicCombo;

@ -0,0 +1,166 @@
/* Kaleidoscope-Model01-TestMode - A factory test mode for the Model 01.
* Copyright (C) 2017-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/>.
*/
#include "Kaleidoscope.h"
#include "Kaleidoscope-Model01-TestMode.h"
#include "Kaleidoscope-LEDEffect-Rainbow.h"
namespace kaleidoscope {
namespace plugin {
constexpr uint8_t CHATTER_CYCLE_LIMIT = 30;
constexpr uint8_t TOGGLED_OFF = 2;
constexpr uint8_t TOGGLED_ON = 1;
constexpr uint8_t HELD = 3;
constexpr uint8_t RELEASED = 0;
EventHandlerResult TestMode::beforeReportingState() {
if (KeyboardHardware.isKeyswitchPressed(R0C0) &&
KeyboardHardware.isKeyswitchPressed(R0C6) &&
KeyboardHardware.isKeyswitchPressed(R3C6) &&
KeyboardHardware.pressedKeyswitchCount() == 3) {
run_tests();
}
return EventHandlerResult::OK;
}
void TestMode::waitForKeypress() {
for (uint8_t temp = 0; temp < 8; temp++) {
KeyboardHardware.readMatrix();
}
while (1) {
KeyboardHardware.readMatrix();
if (KeyboardHardware.isKeyswitchPressed(R3C6)
&& KeyboardHardware.pressedKeyswitchCount() == 1
&& KeyboardHardware.previousLeftHandState.all == 0) {
break;
}
}
}
void TestMode::set_leds(cRGB color) {
::LEDControl.set_all_leds_to(color);
::LEDControl.syncLeds();
waitForKeypress();
}
void TestMode::test_leds(void) {
constexpr cRGB red = CRGB(201, 0, 0);
constexpr cRGB blue = CRGB(0, 0, 201);
constexpr cRGB green = CRGB(0, 201, 0);
constexpr cRGB brightWhite = CRGB(160, 160, 160);
// make all the LEDs bright red
set_leds(red);
// make all the LEDs bright green
set_leds(green);
// make all the LEDs bright blue
set_leds(blue);
// make all the LEDs bright white (1.6A)
set_leds(brightWhite);
// rainbow for 10 seconds
for (auto i = 0; i < 1000; i++) {
::LEDRainbowEffect.update();
::LEDControl.syncLeds();
}
waitForKeypress();
}
void TestMode::handleKeyEvent(side_data_t *side, keydata_t *oldState, keydata_t *newState, uint8_t row, uint8_t col, uint8_t col_offset) {
constexpr cRGB red = CRGB(201, 0, 0);
constexpr cRGB blue = CRGB(0, 0, 201);
constexpr cRGB green = CRGB(0, 201, 0);
const uint8_t keynum = (row * 8) + (col);
const uint8_t keyState = ((bitRead(oldState->all, keynum) << 1) |
(bitRead(newState->all, keynum) << 0));
if (keyState == TOGGLED_ON) {
if (side->cyclesSinceStateChange[keynum] < CHATTER_CYCLE_LIMIT) {
bitSet(side->badKeys, keynum);
}
side->cyclesSinceStateChange[keynum] = 0;
} else if (side->cyclesSinceStateChange[keynum] <= CHATTER_CYCLE_LIMIT) {
side->cyclesSinceStateChange[keynum]++;
}
// If the key is held down
if (keyState == HELD) {
KeyboardHardware.setCrgbAt(row, col_offset - col, green);
}
// If we triggered chatter detection ever on this key
else if (bitRead(side->badKeys, keynum) == 1) {
KeyboardHardware.setCrgbAt(row, col_offset - col, red);
}
// If the key was just released
else if (keyState == TOGGLED_OFF) {
KeyboardHardware.setCrgbAt(row, col_offset - col, blue);
}
}
void TestMode::testMatrix() {
// Reset bad keys from previous tests.
side_data_t left = {{0}, 0};
side_data_t right = {{0}, 0};
::LEDControl.set_all_leds_to(200, 0, 0);
// Clear out the key event buffer so we don't get messed up information from
// taps during LED test mode.
while (1) {
KeyboardHardware.readMatrix();
if (KeyboardHardware.isKeyswitchPressed(R0C0) &&
KeyboardHardware.isKeyswitchPressed(R0C6) &&
KeyboardHardware.isKeyswitchPressed(R3C6) &&
KeyboardHardware.pressedKeyswitchCount() == 3) {
break;
}
for (byte row = 0; row < 4; row++) {
for (byte col = 0; col < 8; col++) {
handleKeyEvent(&left, &(KeyboardHardware.previousLeftHandState), &(KeyboardHardware.leftHandState), row, col, 7);
handleKeyEvent(&right, &(KeyboardHardware.previousRightHandState), &(KeyboardHardware.rightHandState), row, col, 15);
}
}
::LEDControl.syncLeds();
}
}
void TestMode::toggle_programming_leds_on() {
PORTD |= (1 << 5);
PORTB |= (1 << 0);
}
void TestMode::run_tests() {
// Serial.println("Running tests");
toggle_programming_leds_on();
// Disable debouncing
KeyboardHardware.setKeyscanInterval(2);
test_leds();
testMatrix();
// Serial.println("Done running tests");
}
}
}
kaleidoscope::plugin::TestMode TestMode;

@ -0,0 +1,53 @@
/* Kaleidoscope-Model01-TestMode - A factory test mode for the Model 01.
* Copyright (C) 2017-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/>.
*/
#pragma once
#ifndef ARDUINO_AVR_MODEL01
#error The Kaleidoscope-Model01-TestMode plugin was designed for the Keyboardio Model01, and does not work with any other hardware.
#endif
#include <Arduino.h>
#include "Kaleidoscope.h"
namespace kaleidoscope {
namespace plugin {
class TestMode : public kaleidoscope::Plugin {
public:
typedef struct {
uint8_t cyclesSinceStateChange[32];
uint32_t badKeys;
} side_data_t;
TestMode(void) {};
EventHandlerResult beforeReportingState();
private:
static void run_tests();
static void test_leds();
static void testMatrix();
static void toggle_programming_leds_on();
static void handleKeyEvent(side_data_t *side, keydata_t *oldState, keydata_t *newState, uint8_t row, uint8_t col, uint8_t col_offset);
static void waitForKeypress();
static void set_leds(cRGB color);
};
}
}
extern kaleidoscope::plugin::TestMode TestMode;

@ -0,0 +1,190 @@
/* Kaleidoscope-MouseKeys - Mouse keys for Kaleidoscope.
* Copyright (C) 2017-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/>.
*/
#include <Arduino.h>
#include "Kaleidoscope.h"
#include "Kaleidoscope-MouseKeys.h"
namespace kaleidoscope {
namespace plugin {
uint8_t MouseKeys_::mouseMoveIntent;
uint8_t MouseKeys_::speed = 1;
uint16_t MouseKeys_::speedDelay = 1;
uint8_t MouseKeys_::accelSpeed = 1;
uint16_t MouseKeys_::accelDelay = 64;
uint8_t MouseKeys_::wheelSpeed = 1;
uint16_t MouseKeys_::wheelDelay = 50;
uint32_t MouseKeys_::accelEndTime;
uint32_t MouseKeys_::endTime;
uint32_t MouseKeys_::wheelEndTime;
void MouseKeys_::setWarpGridSize(uint8_t grid_size) {
MouseWrapper.warp_grid_size = grid_size;
}
void MouseKeys_::setSpeedLimit(uint8_t speed_limit) {
MouseWrapper.speedLimit = speed_limit;
}
void MouseKeys_::scrollWheel(uint8_t keyCode) {
if (millis() < wheelEndTime)
return;
wheelEndTime = millis() + wheelDelay;
if (keyCode & KEY_MOUSE_UP)
kaleidoscope::hid::moveMouse(0, 0, wheelSpeed);
else if (keyCode & KEY_MOUSE_DOWN)
kaleidoscope::hid::moveMouse(0, 0, -wheelSpeed);
else if (keyCode & KEY_MOUSE_LEFT)
kaleidoscope::hid::moveMouse(0, 0, 0, -wheelSpeed);
else if (keyCode & KEY_MOUSE_RIGHT)
kaleidoscope::hid::moveMouse(0, 0, 0, wheelSpeed);
}
EventHandlerResult MouseKeys_::afterEachCycle() {
kaleidoscope::hid::sendMouseReport();
kaleidoscope::hid::releaseAllMouseButtons();
mouseMoveIntent = 0;
return EventHandlerResult::OK;
}
EventHandlerResult MouseKeys_::beforeReportingState() {
if (mouseMoveIntent == 0) {
MouseWrapper.accelStep = 0;
endTime = 0;
accelEndTime = 0;
return EventHandlerResult::OK;
}
if (millis() < endTime)
return EventHandlerResult::OK;
endTime = millis() + speedDelay;
int8_t moveX = 0, moveY = 0;
if (millis() >= accelEndTime) {
if (MouseWrapper.accelStep < 255 - accelSpeed) {
MouseWrapper.accelStep += accelSpeed;
}
accelEndTime = millis() + accelDelay;
}
if (mouseMoveIntent & KEY_MOUSE_UP)
moveY = -speed;
else if (mouseMoveIntent & KEY_MOUSE_DOWN)
moveY = speed;
if (mouseMoveIntent & KEY_MOUSE_LEFT)
moveX = -speed;
else if (mouseMoveIntent & KEY_MOUSE_RIGHT)
moveX = speed;
MouseWrapper.move(moveX, moveY);
return EventHandlerResult::OK;
}
EventHandlerResult MouseKeys_::onKeyswitchEvent(Key &mappedKey, byte row, byte col, uint8_t keyState) {
if (mappedKey.flags != (SYNTHETIC | IS_MOUSE_KEY))
return EventHandlerResult::OK;
if (mappedKey.keyCode & KEY_MOUSE_BUTTON && !(mappedKey.keyCode & KEY_MOUSE_WARP)) {
uint8_t button = mappedKey.keyCode & ~KEY_MOUSE_BUTTON;
if (keyIsPressed(keyState)) {
// Reset warp state on initial mouse button key-down only so we can use
// warp keys to drag-and-drop:
if (keyToggledOn(keyState)) {
MouseWrapper.reset_warping();
}
MouseWrapper.pressButton(button);
} else if (keyToggledOff(keyState)) {
MouseWrapper.release_button(button);
}
} else if (!(mappedKey.keyCode & KEY_MOUSE_WARP)) {
if (keyToggledOn(keyState)) {
endTime = millis() + speedDelay;
accelEndTime = millis() + accelDelay;
wheelEndTime = 0;
}
if (keyIsPressed(keyState)) {
if (mappedKey.keyCode & KEY_MOUSE_WHEEL) {
scrollWheel(mappedKey.keyCode);
} else {
mouseMoveIntent |= mappedKey.keyCode;
}
} else if (keyToggledOff(keyState)) {
/* If a mouse key toggles off, we want to explicitly stop moving (or
* scrolling) in that direction. We want to do this to support use-cases
* where we send multiple reports per cycle (such as macros), and can't
* rely on the main loop clearing the report for us. We do not want to
* clear the whole report either, because we want any other mouse keys
* to still have their desired effect. Therefore, we selectively stop
* movement or scrolling. */
mouseMoveIntent &= ~mappedKey.keyCode;
bool x = false, y = false, vWheel = false, hWheel = false;
if (mappedKey.keyCode & KEY_MOUSE_UP ||
mappedKey.keyCode & KEY_MOUSE_DOWN) {
if (mappedKey.keyCode & KEY_MOUSE_WHEEL) {
vWheel = true;
} else {
y = true;
}
} else if (mappedKey.keyCode & KEY_MOUSE_LEFT ||
mappedKey.keyCode & KEY_MOUSE_RIGHT) {
if (mappedKey.keyCode & KEY_MOUSE_WHEEL) {
hWheel = true;
} else {
x = true;
}
}
kaleidoscope::hid::stopMouse(x, y, vWheel, hWheel);
}
} else if (keyToggledOn(keyState)) {
if (mappedKey.keyCode & KEY_MOUSE_WARP && mappedKey.flags & IS_MOUSE_KEY) {
MouseWrapper.warp(((mappedKey.keyCode & KEY_MOUSE_WARP_END) ? WARP_END : 0x00) |
((mappedKey.keyCode & KEY_MOUSE_UP) ? WARP_UP : 0x00) |
((mappedKey.keyCode & KEY_MOUSE_DOWN) ? WARP_DOWN : 0x00) |
((mappedKey.keyCode & KEY_MOUSE_LEFT) ? WARP_LEFT : 0x00) |
((mappedKey.keyCode & KEY_MOUSE_RIGHT) ? WARP_RIGHT : 0x00));
}
}
return EventHandlerResult::EVENT_CONSUMED;
}
EventHandlerResult MouseKeys_::onSetup(void) {
MouseWrapper.begin();
return EventHandlerResult::OK;
}
}
}
kaleidoscope::plugin::MouseKeys_ MouseKeys;

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

Loading…
Cancel
Save