diff --git a/bin/focus-test b/bin/focus-test new file mode 100755 index 00000000..dc8cef81 --- /dev/null +++ b/bin/focus-test @@ -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 . + +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 diff --git a/doc/model01_coordinates.png b/doc/model01_coordinates.png new file mode 100644 index 00000000..00cfb979 Binary files /dev/null and b/doc/model01_coordinates.png differ diff --git a/doc/plugin/EEPROM-Keymap.md b/doc/plugin/EEPROM-Keymap.md new file mode 100644 index 00000000..be343bec --- /dev/null +++ b/doc/plugin/EEPROM-Keymap.md @@ -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 +#include +#include + +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 diff --git a/doc/plugin/EEPROM-Settings.md b/doc/plugin/EEPROM-Settings.md new file mode 100644 index 00000000..598e7ae3 --- /dev/null +++ b/doc/plugin/EEPROM-Settings.md @@ -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 +#include + +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 diff --git a/doc/plugin/FocusSerial.md b/doc/plugin/FocusSerial.md new file mode 100644 index 00000000..8b94a81f --- /dev/null +++ b/doc/plugin/FocusSerial.md @@ -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 +#include + +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. diff --git a/doc/plugin/Hardware-Model01.md b/doc/plugin/Hardware-Model01.md new file mode 100644 index 00000000..b0b985b8 --- /dev/null +++ b/doc/plugin/Hardware-Model01.md @@ -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/ diff --git a/doc/plugin/HostPowerManagement.md b/doc/plugin/HostPowerManagement.md new file mode 100644 index 00000000..bd9973f3 --- /dev/null +++ b/doc/plugin/HostPowerManagement.md @@ -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 +#include + +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 diff --git a/doc/plugin/LED-AlphaSquare.md b/doc/plugin/LED-AlphaSquare.md new file mode 100644 index 00000000..cb9384f9 --- /dev/null +++ b/doc/plugin/LED-AlphaSquare.md @@ -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 +#include +#include + +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. diff --git a/doc/plugin/LED-Stalker.md b/doc/plugin/LED-Stalker.md new file mode 100644 index 00000000..5cf51cf4 --- /dev/null +++ b/doc/plugin/LED-Stalker.md @@ -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 +#include +#include + +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 diff --git a/doc/plugin/LEDControl.md b/doc/plugin/LEDControl.md new file mode 100644 index 00000000..2a99e8d2 --- /dev/null +++ b/doc/plugin/LEDControl.md @@ -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 +``, 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. diff --git a/doc/plugin/LEDEffect-BootGreeting.md b/doc/plugin/LEDEffect-BootGreeting.md new file mode 100644 index 00000000..6e07bf0f --- /dev/null +++ b/doc/plugin/LEDEffect-BootGreeting.md @@ -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 +#include +#include + +KALEIDOSCOPE_INIT_PLUGINS(LEDControl, + BootGreetingEffect + LEDOff); + +void setup() { + Kaleidoscope.setup(); +} +``` + +You may also set optional parameters. + +### Specify by search key +```c++ +#include +#include +#include + +KALEIDOSCOPE_INIT_PLUGINS(LEDControl, + BootGreetingEffect + LEDOff); + +void setup() { + Kaleidoscope.setup(); + + BootGreetingEffect.search_key = Key_M; +} +``` + +### Specify by position +```c++ +#include +#include +#include + +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 +#include +#include + +KALEIDOSCOPE_INIT_PLUGINS(LEDControl, + BootGreetingEffect + LEDOff); + +void setup() { + Kaleidoscope.setup(); + + //Butterfly key + BootGreetingEffect.timeout = 15000; +} +``` + +### Specify different color +```c++ +#include +#include +#include + +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) diff --git a/doc/plugin/LEDEffect-Breathe.md b/doc/plugin/LEDEffect-Breathe.md new file mode 100644 index 00000000..72a2c346 --- /dev/null +++ b/doc/plugin/LEDEffect-Breathe.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 +#include + +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) diff --git a/doc/plugin/LEDEffect-Chase.md b/doc/plugin/LEDEffect-Chase.md new file mode 100644 index 00000000..739cd450 --- /dev/null +++ b/doc/plugin/LEDEffect-Chase.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 +#include + +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) diff --git a/doc/plugin/LEDEffect-Rainbow.md b/doc/plugin/LEDEffect-Rainbow.md new file mode 100644 index 00000000..e1b5eebf --- /dev/null +++ b/doc/plugin/LEDEffect-Rainbow.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 +#include + +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) diff --git a/doc/plugin/LEDEffect-SolidColor.md b/doc/plugin/LEDEffect-SolidColor.md new file mode 100644 index 00000000..963bf0f2 --- /dev/null +++ b/doc/plugin/LEDEffect-SolidColor.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 + +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. diff --git a/doc/plugin/Macros.md b/doc/plugin/Macros.md new file mode 100644 index 00000000..0fdd07b3 --- /dev/null +++ b/doc/plugin/Macros.md @@ -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 +#include + +// 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. diff --git a/doc/plugin/MagicCombo.md b/doc/plugin/MagicCombo.md new file mode 100644 index 00000000..2e240222 --- /dev/null +++ b/doc/plugin/MagicCombo.md @@ -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 +#include +#include + +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. diff --git a/doc/plugin/MouseKeys.md b/doc/plugin/MouseKeys.md new file mode 100644 index 00000000..a095a726 --- /dev/null +++ b/doc/plugin/MouseKeys.md @@ -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 +#include + +// 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 G 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 esc 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 W warps the pointer into the top-left sector, and +pressing V 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` diff --git a/doc/plugin/NumPad.md b/doc/plugin/NumPad.md new file mode 100644 index 00000000..83bc5629 --- /dev/null +++ b/doc/plugin/NumPad.md @@ -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 diff --git a/doc/plugin/USB-Quirks.md b/doc/plugin/USB-Quirks.md new file mode 100644 index 00000000..a28f44c6 --- /dev/null +++ b/doc/plugin/USB-Quirks.md @@ -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 +#include +#include + +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. diff --git a/examples/AppSwitcher/AppSwitcher.ino b/examples/AppSwitcher/AppSwitcher.ino index c8776583..1dcdad29 100644 --- a/examples/AppSwitcher/AppSwitcher.ino +++ b/examples/AppSwitcher/AppSwitcher.ino @@ -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() { diff --git a/examples/EEPROM-Keymap/EEPROM-Keymap.ino b/examples/EEPROM-Keymap/EEPROM-Keymap.ino new file mode 100644 index 00000000..f9158099 --- /dev/null +++ b/examples/EEPROM-Keymap/EEPROM-Keymap.ino @@ -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 . + */ + +#include +#include +#include + +// *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(); +} diff --git a/examples/EEPROM-Settings/EEPROM-Settings.ino b/examples/EEPROM-Settings/EEPROM-Settings.ino new file mode 100644 index 00000000..0d2b1850 --- /dev/null +++ b/examples/EEPROM-Settings/EEPROM-Settings.ino @@ -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 . + */ + +#include +#include + +// *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(); +} diff --git a/examples/FocusSerial/FocusSerial.ino b/examples/FocusSerial/FocusSerial.ino new file mode 100644 index 00000000..c83910ca --- /dev/null +++ b/examples/FocusSerial/FocusSerial.ino @@ -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 . + */ + +#include +#include + +// *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(); +} diff --git a/examples/HostPowerManagement/HostPowerManagement.ino b/examples/HostPowerManagement/HostPowerManagement.ino new file mode 100644 index 00000000..72d6f9df --- /dev/null +++ b/examples/HostPowerManagement/HostPowerManagement.ino @@ -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 . + */ + +#include +#include +#include + +// *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(); +} diff --git a/examples/Kaleidoscope/Kaleidoscope.ino b/examples/Kaleidoscope/Kaleidoscope.ino index 61f02fd2..12bb6e6c 100644 --- a/examples/Kaleidoscope/Kaleidoscope.ino +++ b/examples/Kaleidoscope/Kaleidoscope.ino @@ -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" diff --git a/examples/LED-AlphaSquare/LED-AlphaSquare.ino b/examples/LED-AlphaSquare/LED-AlphaSquare.ino new file mode 100644 index 00000000..c4a3eb51 --- /dev/null +++ b/examples/LED-AlphaSquare/LED-AlphaSquare.ino @@ -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 . + */ + +#include +#include +#include +#include + +// *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(); +} diff --git a/examples/LED-Stalker/LED-Stalker.ino b/examples/LED-Stalker/LED-Stalker.ino new file mode 100644 index 00000000..050fcfe8 --- /dev/null +++ b/examples/LED-Stalker/LED-Stalker.ino @@ -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 . + */ + +#include +#include +#include + +// *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(); +} diff --git a/examples/LEDEffect-BootGreeting/LEDEffect-BootGreeting.ino b/examples/LEDEffect-BootGreeting/LEDEffect-BootGreeting.ino new file mode 100644 index 00000000..a7ad3224 --- /dev/null +++ b/examples/LEDEffect-BootGreeting/LEDEffect-BootGreeting.ino @@ -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 . + */ + +#include +#include +#include + +// *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(); +} diff --git a/examples/MagicCombo/MagicCombo.ino b/examples/MagicCombo/MagicCombo.ino new file mode 100644 index 00000000..7a45ccbb --- /dev/null +++ b/examples/MagicCombo/MagicCombo.ino @@ -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 . + */ + +#include +#include +#include + +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(); +} diff --git a/src/Kaleidoscope-EEPROM-Keymap.h b/src/Kaleidoscope-EEPROM-Keymap.h new file mode 100644 index 00000000..3dd4be9e --- /dev/null +++ b/src/Kaleidoscope-EEPROM-Keymap.h @@ -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 . + */ + +#pragma once + +#include diff --git a/src/Kaleidoscope-EEPROM-Settings.h b/src/Kaleidoscope-EEPROM-Settings.h new file mode 100644 index 00000000..ed93eec9 --- /dev/null +++ b/src/Kaleidoscope-EEPROM-Settings.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 . + */ + +#pragma once + +#include diff --git a/src/Kaleidoscope-FocusSerial.h b/src/Kaleidoscope-FocusSerial.h new file mode 100644 index 00000000..7eab4ff4 --- /dev/null +++ b/src/Kaleidoscope-FocusSerial.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 . + */ + +#pragma once + +#include diff --git a/src/Kaleidoscope-Hardware-Model01.h b/src/Kaleidoscope-Hardware-Model01.h new file mode 100644 index 00000000..5671a34d --- /dev/null +++ b/src/Kaleidoscope-Hardware-Model01.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 . + */ + +#pragma once + +#include "kaleidoscope/hardware/Model01.h" diff --git a/src/Kaleidoscope-HostPowerManagement.h b/src/Kaleidoscope-HostPowerManagement.h new file mode 100644 index 00000000..f6e56935 --- /dev/null +++ b/src/Kaleidoscope-HostPowerManagement.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 . + */ + +#pragma once + +#include diff --git a/src/Kaleidoscope-LED-AlphaSquare.h b/src/Kaleidoscope-LED-AlphaSquare.h new file mode 100644 index 00000000..2a279780 --- /dev/null +++ b/src/Kaleidoscope-LED-AlphaSquare.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 . + */ + +#pragma once + +#include +#include +#include diff --git a/src/Kaleidoscope-LED-Stalker.h b/src/Kaleidoscope-LED-Stalker.h new file mode 100644 index 00000000..5eabcc3f --- /dev/null +++ b/src/Kaleidoscope-LED-Stalker.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 . + */ + +#pragma once + +#include diff --git a/src/Kaleidoscope-LEDControl.h b/src/Kaleidoscope-LEDControl.h new file mode 100644 index 00000000..3564aa5a --- /dev/null +++ b/src/Kaleidoscope-LEDControl.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 . + */ + +#pragma once + +#include +#include +#include diff --git a/src/Kaleidoscope-LEDEffect-BootGreeting.h b/src/Kaleidoscope-LEDEffect-BootGreeting.h new file mode 100644 index 00000000..a08ef1c9 --- /dev/null +++ b/src/Kaleidoscope-LEDEffect-BootGreeting.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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/LEDEffect-BootGreeting.h" diff --git a/src/Kaleidoscope-LEDEffect-Breathe.h b/src/Kaleidoscope-LEDEffect-Breathe.h new file mode 100644 index 00000000..028e40d3 --- /dev/null +++ b/src/Kaleidoscope-LEDEffect-Breathe.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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/LEDEffect-Breathe.h" diff --git a/src/Kaleidoscope-LEDEffect-Chase.h b/src/Kaleidoscope-LEDEffect-Chase.h new file mode 100644 index 00000000..e755e738 --- /dev/null +++ b/src/Kaleidoscope-LEDEffect-Chase.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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/LEDEffect-Chase.h" diff --git a/src/Kaleidoscope-LEDEffect-Rainbow.h b/src/Kaleidoscope-LEDEffect-Rainbow.h new file mode 100644 index 00000000..348f9562 --- /dev/null +++ b/src/Kaleidoscope-LEDEffect-Rainbow.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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/LEDEffect-Rainbow.h" diff --git a/src/Kaleidoscope-LEDEffect-SolidColor.h b/src/Kaleidoscope-LEDEffect-SolidColor.h new file mode 100644 index 00000000..1fc4259b --- /dev/null +++ b/src/Kaleidoscope-LEDEffect-SolidColor.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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/LEDEffect-SolidColor.h" diff --git a/src/Kaleidoscope-Macros.h b/src/Kaleidoscope-Macros.h new file mode 100644 index 00000000..0aa76885 --- /dev/null +++ b/src/Kaleidoscope-Macros.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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/Macros.h" diff --git a/src/Kaleidoscope-MagicCombo.h b/src/Kaleidoscope-MagicCombo.h new file mode 100644 index 00000000..ed5c3699 --- /dev/null +++ b/src/Kaleidoscope-MagicCombo.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 . + */ + +#pragma once + +#include diff --git a/src/Kaleidoscope-Model01-TestMode.h b/src/Kaleidoscope-Model01-TestMode.h new file mode 100644 index 00000000..55ed92cb --- /dev/null +++ b/src/Kaleidoscope-Model01-TestMode.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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/Model01-TestMode.h" diff --git a/src/Kaleidoscope-MouseKeys.h b/src/Kaleidoscope-MouseKeys.h new file mode 100644 index 00000000..b948baea --- /dev/null +++ b/src/Kaleidoscope-MouseKeys.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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/MouseKeys.h" diff --git a/src/Kaleidoscope-NumPad.h b/src/Kaleidoscope-NumPad.h new file mode 100644 index 00000000..be0c76f6 --- /dev/null +++ b/src/Kaleidoscope-NumPad.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 . + */ + +#pragma once + +#include "kaleidoscope/plugin/NumPad.h" diff --git a/src/Kaleidoscope-USB-Quirks.h b/src/Kaleidoscope-USB-Quirks.h new file mode 100644 index 00000000..953169e7 --- /dev/null +++ b/src/Kaleidoscope-USB-Quirks.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 . + */ + +#pragma once + +#include diff --git a/src/LED-Off.h b/src/LED-Off.h new file mode 100644 index 00000000..eeb13372 --- /dev/null +++ b/src/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 . + */ + +#pragma once + +#warning The "LED-Off.h" header is deprecated, the mode is included by default when using . It can be safely removed. + +#include "kaleidoscope/plugin/LEDControl/LED-Off.h" diff --git a/src/LEDUtils.h b/src/LEDUtils.h new file mode 100644 index 00000000..803e882e --- /dev/null +++ b/src/LEDUtils.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 . + */ + +#pragma once + +#warning The "LEDUtils.h" header is deprecated, the mode is included by default when using . It can be safely removed. + +#include "kaleidoscope/plugin/LEDControl/LEDUtils.h" diff --git a/src/MouseWrapper.h b/src/MouseWrapper.h new file mode 100644 index 00000000..ad127ce7 --- /dev/null +++ b/src/MouseWrapper.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 . + */ + +#pragma once + +#warning The "MouseWrapper.h" header is deprecated, the same functionality is included by default when using . It can be safely removed. + +#include "kaleidoscope/plugin/MouseKeys/MouseWrapper.h" diff --git a/src/kaleidoscope/hardware/Model01.cpp b/src/kaleidoscope/hardware/Model01.cpp new file mode 100644 index 00000000..7c9dc4c0 --- /dev/null +++ b/src/kaleidoscope/hardware/Model01.cpp @@ -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 . + */ + +#include +#include +#include + +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(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; diff --git a/src/kaleidoscope/hardware/Model01.h b/src/kaleidoscope/hardware/Model01.h new file mode 100644 index 00000000..7cb9717a --- /dev/null +++ b/src/kaleidoscope/hardware/Model01.h @@ -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 . + */ + +#pragma once + +#include + +#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__)}, \ + } diff --git a/src/kaleidoscope/plugin/EEPROM-Keymap.cpp b/src/kaleidoscope/plugin/EEPROM-Keymap.cpp new file mode 100644 index 00000000..bb415be2 --- /dev/null +++ b/src/kaleidoscope/plugin/EEPROM-Keymap.cpp @@ -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 . + */ + +#include +#include +#include + +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; diff --git a/src/kaleidoscope/plugin/EEPROM-Keymap.h b/src/kaleidoscope/plugin/EEPROM-Keymap.h new file mode 100644 index 00000000..ae72e8e9 --- /dev/null +++ b/src/kaleidoscope/plugin/EEPROM-Keymap.h @@ -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 . + */ + +#pragma once + +#include +#include + +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; diff --git a/src/kaleidoscope/plugin/EEPROM-Settings.cpp b/src/kaleidoscope/plugin/EEPROM-Settings.cpp new file mode 100644 index 00000000..9e0e4d72 --- /dev/null +++ b/src/kaleidoscope/plugin/EEPROM-Settings.cpp @@ -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 . + */ + +#include +#include +#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; diff --git a/src/kaleidoscope/plugin/EEPROM-Settings.h b/src/kaleidoscope/plugin/EEPROM-Settings.h new file mode 100644 index 00000000..34c0bcda --- /dev/null +++ b/src/kaleidoscope/plugin/EEPROM-Settings.h @@ -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 . + */ + +#pragma once + +#include +#include + +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; diff --git a/src/kaleidoscope/plugin/EEPROM-Settings/crc.cpp b/src/kaleidoscope/plugin/EEPROM-Settings/crc.cpp new file mode 100644 index 00000000..0c199695 --- /dev/null +++ b/src/kaleidoscope/plugin/EEPROM-Settings/crc.cpp @@ -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 . + * + * 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; diff --git a/src/kaleidoscope/plugin/EEPROM-Settings/crc.h b/src/kaleidoscope/plugin/EEPROM-Settings/crc.h new file mode 100644 index 00000000..0eb1aec4 --- /dev/null +++ b/src/kaleidoscope/plugin/EEPROM-Settings/crc.h @@ -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 . + * + * 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 + +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; diff --git a/src/kaleidoscope/plugin/FocusSerial.cpp b/src/kaleidoscope/plugin/FocusSerial.cpp new file mode 100644 index 00000000..9c240963 --- /dev/null +++ b/src/kaleidoscope/plugin/FocusSerial.cpp @@ -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 . + */ + +#include + +#ifdef __AVR__ +#include +#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; diff --git a/src/kaleidoscope/plugin/FocusSerial.h b/src/kaleidoscope/plugin/FocusSerial.h new file mode 100644 index 00000000..3f600c54 --- /dev/null +++ b/src/kaleidoscope/plugin/FocusSerial.h @@ -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 . + */ + +#pragma once + +#include + +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; diff --git a/src/kaleidoscope/plugin/HostPowerManagement.cpp b/src/kaleidoscope/plugin/HostPowerManagement.cpp new file mode 100644 index 00000000..ce4c9826 --- /dev/null +++ b/src/kaleidoscope/plugin/HostPowerManagement.cpp @@ -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 . + */ + +#include +#include +#include + +// 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; diff --git a/src/kaleidoscope/plugin/HostPowerManagement.h b/src/kaleidoscope/plugin/HostPowerManagement.h new file mode 100644 index 00000000..2dbb36f7 --- /dev/null +++ b/src/kaleidoscope/plugin/HostPowerManagement.h @@ -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 . + */ + +#pragma once + +#include + +#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; diff --git a/src/kaleidoscope/plugin/LED-AlphaSquare.cpp b/src/kaleidoscope/plugin/LED-AlphaSquare.cpp new file mode 100644 index 00000000..0eadb246 --- /dev/null +++ b/src/kaleidoscope/plugin/LED-AlphaSquare.cpp @@ -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 . + */ + +#include +#include + +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; diff --git a/src/kaleidoscope/plugin/LED-AlphaSquare.h b/src/kaleidoscope/plugin/LED-AlphaSquare.h new file mode 100644 index 00000000..296a7ca7 --- /dev/null +++ b/src/kaleidoscope/plugin/LED-AlphaSquare.h @@ -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 . + */ + +#pragma once + +#include +#include + +#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; diff --git a/src/kaleidoscope/plugin/LED-AlphaSquare/Effect.cpp b/src/kaleidoscope/plugin/LED-AlphaSquare/Effect.cpp new file mode 100644 index 00000000..025ec20d --- /dev/null +++ b/src/kaleidoscope/plugin/LED-AlphaSquare/Effect.cpp @@ -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 . + */ + +#include + +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; diff --git a/src/kaleidoscope/plugin/LED-AlphaSquare/Effect.h b/src/kaleidoscope/plugin/LED-AlphaSquare/Effect.h new file mode 100644 index 00000000..3227afdf --- /dev/null +++ b/src/kaleidoscope/plugin/LED-AlphaSquare/Effect.h @@ -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 . + */ + +#pragma once + +#include +#include + +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; diff --git a/src/kaleidoscope/plugin/LED-AlphaSquare/Font-3x4.h b/src/kaleidoscope/plugin/LED-AlphaSquare/Font-3x4.h new file mode 100644 index 00000000..2fae3bf0 --- /dev/null +++ b/src/kaleidoscope/plugin/LED-AlphaSquare/Font-3x4.h @@ -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 . + */ + + +#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 diff --git a/src/kaleidoscope/plugin/LED-AlphaSquare/Font-4x4.h b/src/kaleidoscope/plugin/LED-AlphaSquare/Font-4x4.h new file mode 100644 index 00000000..f33e3388 --- /dev/null +++ b/src/kaleidoscope/plugin/LED-AlphaSquare/Font-4x4.h @@ -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 . + */ + +#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 diff --git a/src/kaleidoscope/plugin/LED-AlphaSquare/Symbols.h b/src/kaleidoscope/plugin/LED-AlphaSquare/Symbols.h new file mode 100644 index 00000000..e829a81d --- /dev/null +++ b/src/kaleidoscope/plugin/LED-AlphaSquare/Symbols.h @@ -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 . + */ + +#pragma once + +#include + +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; + +} diff --git a/src/kaleidoscope/plugin/LED-Stalker.cpp b/src/kaleidoscope/plugin/LED-Stalker.cpp new file mode 100644 index 00000000..4f64913c --- /dev/null +++ b/src/kaleidoscope/plugin/LED-Stalker.cpp @@ -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 . + */ + +#include + +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; diff --git a/src/kaleidoscope/plugin/LED-Stalker.h b/src/kaleidoscope/plugin/LED-Stalker.h new file mode 100644 index 00000000..029895fa --- /dev/null +++ b/src/kaleidoscope/plugin/LED-Stalker.h @@ -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 . + */ + +#pragma once + +#include +#include + +#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; diff --git a/src/kaleidoscope/plugin/LEDControl.cpp b/src/kaleidoscope/plugin/LEDControl.cpp new file mode 100644 index 00000000..cc710eb0 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDControl.cpp @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDControl.h b/src/kaleidoscope/plugin/LEDControl.h new file mode 100644 index 00000000..246edfc8 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDControl.h @@ -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 . + */ + +#pragma once + +#include + +#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; diff --git a/src/kaleidoscope/plugin/LEDControl/BootAnimation.cpp b/src/kaleidoscope/plugin/LEDControl/BootAnimation.cpp new file mode 100644 index 00000000..2e7c0ba7 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDControl/BootAnimation.cpp @@ -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 . + */ + +#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 +} diff --git a/src/kaleidoscope/plugin/LEDControl/BootAnimation.h b/src/kaleidoscope/plugin/LEDControl/BootAnimation.h new file mode 100644 index 00000000..5da98af2 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDControl/BootAnimation.h @@ -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 . + */ + +#pragma once + +void bootAnimation(void); diff --git a/src/kaleidoscope/plugin/LEDControl/LED-Off.cpp b/src/kaleidoscope/plugin/LEDControl/LED-Off.cpp new file mode 100644 index 00000000..175ccab1 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDControl/LED-Off.cpp @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDControl/LED-Off.h b/src/kaleidoscope/plugin/LEDControl/LED-Off.h new file mode 100644 index 00000000..3a931e9d --- /dev/null +++ b/src/kaleidoscope/plugin/LEDControl/LED-Off.h @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDControl/LEDUtils.cpp b/src/kaleidoscope/plugin/LEDControl/LEDUtils.cpp new file mode 100644 index 00000000..9f7f9c83 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDControl/LEDUtils.cpp @@ -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 . + */ + +#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; +} diff --git a/src/kaleidoscope/plugin/LEDControl/LEDUtils.h b/src/kaleidoscope/plugin/LEDControl/LEDUtils.h new file mode 100644 index 00000000..1de96922 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDControl/LEDUtils.h @@ -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 . + */ + +#pragma once + +#include + +cRGB breath_compute(uint8_t hue = 170, uint8_t saturation = 255); +cRGB hsvToRgb(uint16_t h, uint16_t s, uint16_t v); diff --git a/src/kaleidoscope/plugin/LEDEffect-BootGreeting.cpp b/src/kaleidoscope/plugin/LEDEffect-BootGreeting.cpp new file mode 100644 index 00000000..ac435c0f --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-BootGreeting.cpp @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDEffect-BootGreeting.h b/src/kaleidoscope/plugin/LEDEffect-BootGreeting.h new file mode 100644 index 00000000..aeeae501 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-BootGreeting.h @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDEffect-Breathe.cpp b/src/kaleidoscope/plugin/LEDEffect-Breathe.cpp new file mode 100644 index 00000000..ba77c1f9 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-Breathe.cpp @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDEffect-Breathe.h b/src/kaleidoscope/plugin/LEDEffect-Breathe.h new file mode 100644 index 00000000..ade1e7dc --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-Breathe.h @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDEffect-Chase.cpp b/src/kaleidoscope/plugin/LEDEffect-Chase.cpp new file mode 100644 index 00000000..ae8426e1 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-Chase.cpp @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDEffect-Chase.h b/src/kaleidoscope/plugin/LEDEffect-Chase.h new file mode 100644 index 00000000..6174eae5 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-Chase.h @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDEffect-Rainbow.cpp b/src/kaleidoscope/plugin/LEDEffect-Rainbow.cpp new file mode 100644 index 00000000..c9f0dc61 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-Rainbow.cpp @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDEffect-Rainbow.h b/src/kaleidoscope/plugin/LEDEffect-Rainbow.h new file mode 100644 index 00000000..3bc8f654 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-Rainbow.h @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/LEDEffect-SolidColor.cpp b/src/kaleidoscope/plugin/LEDEffect-SolidColor.cpp new file mode 100644 index 00000000..d030e86d --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-SolidColor.cpp @@ -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 . + */ + +#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)); +} + +} +} diff --git a/src/kaleidoscope/plugin/LEDEffect-SolidColor.h b/src/kaleidoscope/plugin/LEDEffect-SolidColor.h new file mode 100644 index 00000000..b79bbf72 --- /dev/null +++ b/src/kaleidoscope/plugin/LEDEffect-SolidColor.h @@ -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 . + */ + +#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; + +} diff --git a/src/kaleidoscope/plugin/Macros.cpp b/src/kaleidoscope/plugin/Macros.cpp new file mode 100644 index 00000000..de67e540 --- /dev/null +++ b/src/kaleidoscope/plugin/Macros.cpp @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/Macros.h b/src/kaleidoscope/plugin/Macros.h new file mode 100644 index 00000000..e0dc9e13 --- /dev/null +++ b/src/kaleidoscope/plugin/Macros.h @@ -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 . + */ + +#pragma once + +#include + +#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 + 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; diff --git a/src/kaleidoscope/plugin/Macros/MacroKeyDefs.h b/src/kaleidoscope/plugin/Macros/MacroKeyDefs.h new file mode 100644 index 00000000..ae4fbb7d --- /dev/null +++ b/src/kaleidoscope/plugin/Macros/MacroKeyDefs.h @@ -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 . + */ + +#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) diff --git a/src/kaleidoscope/plugin/Macros/MacroSteps.h b/src/kaleidoscope/plugin/Macros/MacroSteps.h new file mode 100644 index 00000000..39bf2a64 --- /dev/null +++ b/src/kaleidoscope/plugin/Macros/MacroSteps.h @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/MagicCombo.cpp b/src/kaleidoscope/plugin/MagicCombo.cpp new file mode 100644 index 00000000..3dcd3ac5 --- /dev/null +++ b/src/kaleidoscope/plugin/MagicCombo.cpp @@ -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 . + */ + +#include + +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; diff --git a/src/kaleidoscope/plugin/MagicCombo.h b/src/kaleidoscope/plugin/MagicCombo.h new file mode 100644 index 00000000..35706c26 --- /dev/null +++ b/src/kaleidoscope/plugin/MagicCombo.h @@ -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 . + */ + +#pragma once + +#include + +#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 + 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; diff --git a/src/kaleidoscope/plugin/Model01-TestMode.cpp b/src/kaleidoscope/plugin/Model01-TestMode.cpp new file mode 100644 index 00000000..b7bf3cce --- /dev/null +++ b/src/kaleidoscope/plugin/Model01-TestMode.cpp @@ -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 . + */ + +#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; diff --git a/src/kaleidoscope/plugin/Model01-TestMode.h b/src/kaleidoscope/plugin/Model01-TestMode.h new file mode 100644 index 00000000..a3cbae0c --- /dev/null +++ b/src/kaleidoscope/plugin/Model01-TestMode.h @@ -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 . + */ + +#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 +#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; diff --git a/src/kaleidoscope/plugin/MouseKeys.cpp b/src/kaleidoscope/plugin/MouseKeys.cpp new file mode 100644 index 00000000..52fbe618 --- /dev/null +++ b/src/kaleidoscope/plugin/MouseKeys.cpp @@ -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 . + */ + +#include + +#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; diff --git a/src/kaleidoscope/plugin/MouseKeys.h b/src/kaleidoscope/plugin/MouseKeys.h new file mode 100644 index 00000000..71ba3fd4 --- /dev/null +++ b/src/kaleidoscope/plugin/MouseKeys.h @@ -0,0 +1,56 @@ +/* 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 . + */ + +#pragma once + +#include "Kaleidoscope.h" +#include "kaleidoscope/plugin/MouseKeys/MouseKeyDefs.h" +#include "kaleidoscope/plugin/MouseKeys/MouseWarpModes.h" +#include "kaleidoscope/plugin/MouseKeys/MouseWrapper.h" + +namespace kaleidoscope { +namespace plugin { +class MouseKeys_ : public kaleidoscope::Plugin { + public: + MouseKeys_(void) {} + + static uint8_t speed; + static uint16_t speedDelay; + static uint8_t accelSpeed; + static uint16_t accelDelay; + static uint8_t wheelSpeed; + static uint16_t wheelDelay; + + static void setWarpGridSize(uint8_t grid_size); + static void setSpeedLimit(uint8_t speed_limit); + + EventHandlerResult onSetup(); + EventHandlerResult beforeReportingState(); + EventHandlerResult afterEachCycle(); + EventHandlerResult onKeyswitchEvent(Key &mappedKey, byte row, byte col, uint8_t keyState); + + private: + static uint8_t mouseMoveIntent; + static uint32_t endTime; + static uint32_t accelEndTime; + static uint32_t wheelEndTime; + + static void scrollWheel(uint8_t keyCode); +}; +} +} + +extern kaleidoscope::plugin::MouseKeys_ MouseKeys; diff --git a/src/kaleidoscope/plugin/MouseKeys/MouseKeyDefs.h b/src/kaleidoscope/plugin/MouseKeys/MouseKeyDefs.h new file mode 100644 index 00000000..a6e8c6b7 --- /dev/null +++ b/src/kaleidoscope/plugin/MouseKeys/MouseKeyDefs.h @@ -0,0 +1,67 @@ +/* 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 . + */ + +#pragma once + +#define IS_MOUSE_KEY B00010000 + +// Synthetic, not internal +#define KEY_MOUSE_BTN_L MOUSE_LEFT // Synthetic key +#define KEY_MOUSE_BTN_M MOUSE_MIDDLE // Synthetic key +#define KEY_MOUSE_BTN_R MOUSE_RIGHT // Synthetic key +#define KEY_MOUSE_BTN_P MOUSE_PREV +#define KEY_MOUSE_BTN_N MOUSE_NEXT + +#define KEY_MOUSE_UP B0000001 +#define KEY_MOUSE_DOWN B0000010 +#define KEY_MOUSE_LEFT B0000100 +#define KEY_MOUSE_RIGHT B0001000 +#define KEY_MOUSE_WHEEL B0010000 +#define KEY_MOUSE_WARP B0100000 +#define KEY_MOUSE_WARP_END B1000000 +// all buttons end warp. also, we're out of bits +#define KEY_MOUSE_BUTTON B1000000 + + +#define Key_mouseWarpNW (Key) { KEY_MOUSE_WARP| KEY_MOUSE_UP | KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseWarpN (Key) { KEY_MOUSE_WARP| KEY_MOUSE_UP, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseWarpNE (Key) { KEY_MOUSE_WARP| KEY_MOUSE_UP | KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseWarpW (Key) { KEY_MOUSE_WARP| KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseWarpIn (Key) { KEY_MOUSE_WARP| KEY_MOUSE_UP | KEY_MOUSE_DOWN, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseWarpE (Key) { KEY_MOUSE_WARP| KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseWarpSW (Key) { KEY_MOUSE_WARP| KEY_MOUSE_DOWN | KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseWarpS (Key) { KEY_MOUSE_WARP| KEY_MOUSE_DOWN, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseWarpSE (Key) { KEY_MOUSE_WARP| KEY_MOUSE_DOWN | KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseWarpEnd (Key) { KEY_MOUSE_WARP| KEY_MOUSE_WARP_END, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } + + +#define Key_mouseUpL (Key) { KEY_MOUSE_UP | KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseUp (Key) { KEY_MOUSE_UP, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseUpR (Key) { KEY_MOUSE_UP | KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseL (Key) { KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseR (Key) { KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseDnL (Key) { KEY_MOUSE_DOWN | KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseDn (Key) { KEY_MOUSE_DOWN, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseDnR (Key) { KEY_MOUSE_DOWN | KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseScrollUp (Key) { KEY_MOUSE_WHEEL | KEY_MOUSE_UP, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseScrollDn (Key) { KEY_MOUSE_WHEEL | KEY_MOUSE_DOWN, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseScrollL (Key) { KEY_MOUSE_WHEEL | KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseScrollR (Key) { KEY_MOUSE_WHEEL | KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY } +#define Key_mouseBtnL (Key) { KEY_MOUSE_BUTTON | KEY_MOUSE_BTN_L, KEY_FLAGS | SYNTHETIC | IS_MOUSE_KEY } +#define Key_mouseBtnM (Key) { KEY_MOUSE_BUTTON | KEY_MOUSE_BTN_M, KEY_FLAGS | SYNTHETIC | IS_MOUSE_KEY } +#define Key_mouseBtnR (Key) { KEY_MOUSE_BUTTON | KEY_MOUSE_BTN_R, KEY_FLAGS | SYNTHETIC | IS_MOUSE_KEY } +#define Key_mouseBtnP (Key) { KEY_MOUSE_BUTTON | KEY_MOUSE_BTN_P, KEY_FLAGS | SYNTHETIC | IS_MOUSE_KEY } +#define Key_mouseBtnN (Key) { KEY_MOUSE_BUTTON | KEY_MOUSE_BTN_N, KEY_FLAGS | SYNTHETIC | IS_MOUSE_KEY } diff --git a/src/kaleidoscope/plugin/MouseKeys/MouseWarpModes.h b/src/kaleidoscope/plugin/MouseKeys/MouseWarpModes.h new file mode 100644 index 00000000..a81355ac --- /dev/null +++ b/src/kaleidoscope/plugin/MouseKeys/MouseWarpModes.h @@ -0,0 +1,26 @@ +/* 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 . + */ + +#pragma once + +// Warp modes determine how the plugin jumps the mouse pointer to a screen +// location when pressing a warp key. + + +// Grid Based - the constant represents the number of cells in a row or column: + +#define MOUSE_WARP_GRID_2X2 2 +#define MOUSE_WARP_GRID_3X3 3 diff --git a/src/kaleidoscope/plugin/MouseKeys/MouseWrapper.cpp b/src/kaleidoscope/plugin/MouseKeys/MouseWrapper.cpp new file mode 100644 index 00000000..b52fb2c1 --- /dev/null +++ b/src/kaleidoscope/plugin/MouseKeys/MouseWrapper.cpp @@ -0,0 +1,182 @@ +/* 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 . + */ + + +// Mouse-related methods +// +// +#include "kaleidoscope/plugin/MouseKeys/MouseWrapper.h" +#include "kaleidoscope/hid.h" + +namespace kaleidoscope { +namespace plugin { + +uint8_t MouseWrapper_::warp_grid_size = MOUSE_WARP_GRID_2X2; +uint16_t MouseWrapper_::next_width; +uint16_t MouseWrapper_::next_height; +uint16_t MouseWrapper_::section_top; +uint16_t MouseWrapper_::section_left; +boolean MouseWrapper_::is_warping; + +uint8_t MouseWrapper_::accelStep; +uint8_t MouseWrapper_::speedLimit = 127; +uint8_t MouseWrapper_::subpixelsPerPixel = 16; + +MouseWrapper_::MouseWrapper_(void) { +} + +void MouseWrapper_::begin(void) { + kaleidoscope::hid::initializeMouse(); + kaleidoscope::hid::initializeAbsoluteMouse(); +} + +void MouseWrapper_::pressButton(uint8_t button) { + kaleidoscope::hid::pressMouseButtons(button); +} + +void MouseWrapper_::release_button(uint8_t button) { + kaleidoscope::hid::releaseMouseButtons(button); + end_warping(); +} + +void MouseWrapper_::warp_jump(uint16_t left, uint16_t top, uint16_t height, uint16_t width) { + uint16_t x_center = left + width / 2; + uint16_t y_center = top + height / 2; + kaleidoscope::hid::moveAbsoluteMouseTo(x_center, y_center, 0); +} + +void MouseWrapper_::begin_warping() { + section_left = WARP_ABS_LEFT; + section_top = WARP_ABS_TOP; + next_width = MAX_WARP_WIDTH; + next_height = MAX_WARP_HEIGHT; + is_warping = true; +} + +void MouseWrapper_::end_warping() { + is_warping = false; +} + +void MouseWrapper_::reset_warping() { + if (is_warping == true) { + begin_warping(); + } +} + +void MouseWrapper_::warp(uint8_t warp_cmd) { + if (is_warping == false) { + begin_warping(); + } + + if (warp_cmd & WARP_END) { + end_warping(); + return; + } + + next_width /= warp_grid_size; + next_height /= warp_grid_size; + + // WARP_UP + WARP_DOWN means "zoom in" to center sector + if (warp_cmd & WARP_UP && warp_cmd & WARP_DOWN) { + section_left += next_width; + section_top += next_height; + + warp_jump(section_left, section_top, next_height, next_width); + + return; + } + + if (warp_cmd & WARP_DOWN) { + section_top += next_height * (warp_grid_size - 1); + } else if (!(warp_cmd & WARP_UP)) { + section_top += next_height; + } + + if (warp_cmd & WARP_RIGHT) { + section_left += next_width * (warp_grid_size - 1); + } else if (!(warp_cmd & WARP_LEFT)) { + section_left += next_width; + } + + warp_jump(section_left, section_top, next_height, next_width); +} + +// cubic wave function based on code from FastLED +// produces a shape similar to a sine curve from 0 to 255 +// (slow growth at 0, fast growth in the middle, slow growth at 255) +// http://www.wolframalpha.com/input/?i=((3((x)**2)%2F256)+-+((2((x)(x)(x%2F256))%2F256)))+%2B+1 +uint8_t MouseWrapper_::acceleration(uint8_t cycles) { + uint16_t i = cycles; + + uint16_t ii = (i * i) >> 8; + uint16_t iii = (ii * i) >> 8; + + i = ((3 * ii) - (2 * iii)) + 1; + + // Just in case (may go up to 256 at peak) + if (i > 255) i = 255; + + return i; +} + +// Get the diagonalized version of a value, i.e. value * sqrt(2) / 2. If the +// value ends up being zero, return the original value instead. +static int16_t diagonalize(int16_t value) { + // 99 / 140 closely approximates sqrt(2) / 2. Since integer division + // truncates towards zero we do not need to worry about truncation errors. + int16_t diagonalValue = value * 99 / 140; + return (diagonalValue == 0 ? value : diagonalValue); +} + +void MouseWrapper_::move(int8_t x, int8_t y) { + int16_t moveX = 0; + int16_t moveY = 0; + static int8_t remainderX = 0; + static int8_t remainderY = 0; + int16_t effectiveSpeedLimit = speedLimit; + + if (x != 0 && y != 0) { + // For diagonal movements, we apply a diagonalized speed limit. The + // effective speed limit is set based on whether we are moving diagonally. + effectiveSpeedLimit = diagonalize(effectiveSpeedLimit); + + x = diagonalize(x); + y = diagonalize(y); + } + + if (x != 0) { + moveX = remainderX + (x * acceleration(accelStep)); + if (moveX > effectiveSpeedLimit) moveX = effectiveSpeedLimit; + else if (moveX < -effectiveSpeedLimit) moveX = -effectiveSpeedLimit; + } + + if (y != 0) { + moveY = remainderY + (y * acceleration(accelStep)); + if (moveY > effectiveSpeedLimit) moveY = effectiveSpeedLimit; + else if (moveY < -effectiveSpeedLimit) moveY = -effectiveSpeedLimit; + } + + end_warping(); + // move by whole pixels, not subpixels + kaleidoscope::hid::moveMouse(moveX / subpixelsPerPixel, moveY / subpixelsPerPixel, 0); + // save leftover subpixel movements for later + remainderX = moveX - moveX / subpixelsPerPixel * subpixelsPerPixel; + remainderY = moveY - moveY / subpixelsPerPixel * subpixelsPerPixel; +} +} +} + +kaleidoscope::plugin::MouseWrapper_ MouseWrapper; diff --git a/src/kaleidoscope/plugin/MouseKeys/MouseWrapper.h b/src/kaleidoscope/plugin/MouseKeys/MouseWrapper.h new file mode 100644 index 00000000..c2641771 --- /dev/null +++ b/src/kaleidoscope/plugin/MouseKeys/MouseWrapper.h @@ -0,0 +1,74 @@ +/* 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 . + */ + +#pragma once + +#include "Arduino.h" +#include "kaleidoscope/plugin/MouseKeys/MouseWarpModes.h" + +// Warping commands + +#define WARP_END 1 +#define WARP_UP 2 +#define WARP_DOWN 4 +#define WARP_LEFT 8 +#define WARP_RIGHT 16 + +// apparently, the mac discards 15% of the value space for mouse movement. +// need to test this on other platforms + +#define MAX_WARP_WIDTH 32767 +#define MAX_WARP_HEIGHT 32767 + +#define WARP_ABS_TOP 0 +#define WARP_ABS_LEFT 0 + +// Mouse acceleration + +namespace kaleidoscope { +namespace plugin { + +class MouseWrapper_ { + public: + MouseWrapper_(void); + + static void begin(void); + static void move(int8_t x, int8_t y); + static void warp(uint8_t warp_cmd); + static void reset_warping(); + static void pressButton(uint8_t button); + static void release_button(uint8_t button); + static uint8_t accelStep; + static uint8_t speedLimit; + static uint8_t subpixelsPerPixel; + static uint8_t warp_grid_size; + + private: + static uint16_t next_width; + static uint16_t next_height; + static uint16_t section_top; + static uint16_t section_left; + static boolean is_warping; + + static uint8_t acceleration(uint8_t cycles); + static void begin_warping(); + static void end_warping(); + static void warp_jump(uint16_t left, uint16_t top, uint16_t height, uint16_t width); +}; +} +} + +extern kaleidoscope::plugin::MouseWrapper_ MouseWrapper; diff --git a/src/kaleidoscope/plugin/NumPad.cpp b/src/kaleidoscope/plugin/NumPad.cpp new file mode 100644 index 00000000..6b49ae05 --- /dev/null +++ b/src/kaleidoscope/plugin/NumPad.cpp @@ -0,0 +1,105 @@ +/* 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 . + */ + +#include "Kaleidoscope-NumPad.h" + +namespace kaleidoscope { +namespace plugin { + +byte NumPad::numpadLayerToggleKeyRow = 255, NumPad::numpadLayerToggleKeyCol = 255; +uint8_t NumPad::numPadLayer; +bool NumPad::numlockUnsynced = false; +bool NumPad::originalNumLockState = false; +cRGB NumPad::color = CRGB(160, 0, 0); +uint8_t NumPad::lock_hue = 170; + +EventHandlerResult NumPad::onSetup(void) { + originalNumLockState = getNumlockState(); + return EventHandlerResult::OK; +} + +bool NumPad::getNumlockState() { + return !!(kaleidoscope::hid::getKeyboardLEDs() & LED_NUM_LOCK); +} + +void NumPad::syncNumlockState(bool state) { + bool numLockLEDState = getNumlockState(); + if (numLockLEDState != state) { + kaleidoscope::hid::pressKey(Key_KeypadNumLock); + } +} + + + +void NumPad::cleanupNumlockState() { + if (!numlockUnsynced) { + bool numLockLEDState = getNumlockState(); + ::LEDControl.set_mode(::LEDControl.get_mode_index()); + if (!originalNumLockState) { + syncNumlockState(false); + numLockLEDState = false; + } + originalNumLockState = numLockLEDState; + numlockUnsynced = true; + } + +} + +void NumPad::setKeyboardLEDColors(void) { + ::LEDControl.set_mode(::LEDControl.get_mode_index()); + + for (uint8_t r = 0; r < ROWS; r++) { + for (uint8_t c = 0; c < COLS; c++) { + Key k = Layer.lookupOnActiveLayer(r, c); + Key layer_key = Layer.getKey(numPadLayer, r, c); + + if (k == LockLayer(numPadLayer)) { + numpadLayerToggleKeyRow = r; + numpadLayerToggleKeyCol = c; + } + + if ((k != layer_key) || (k == Key_NoKey) || (k.flags != KEY_FLAGS)) { + ::LEDControl.refreshAt(r, c); + } else { + ::LEDControl.setCrgbAt(r, c, color); + } + } + } + + if ((numpadLayerToggleKeyRow <= ROWS) && (numpadLayerToggleKeyCol <= COLS)) { + cRGB lock_color = breath_compute(lock_hue); + ::LEDControl.setCrgbAt(numpadLayerToggleKeyRow, numpadLayerToggleKeyCol, lock_color); + } +} + +EventHandlerResult NumPad::afterEachCycle() { + if (!Layer.isOn(numPadLayer)) { + cleanupNumlockState(); + } else { + if (numlockUnsynced) { + // If it's the first time we're in this loop after toggling the Numpad mode on + syncNumlockState(true); + numlockUnsynced = false; + } + setKeyboardLEDColors(); + } + return EventHandlerResult::OK; +} + +} +} + +kaleidoscope::plugin::NumPad NumPad; diff --git a/src/kaleidoscope/plugin/NumPad.h b/src/kaleidoscope/plugin/NumPad.h new file mode 100644 index 00000000..8735cd84 --- /dev/null +++ b/src/kaleidoscope/plugin/NumPad.h @@ -0,0 +1,50 @@ +/* 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 . + */ + +#pragma once + +#include "Kaleidoscope-LEDControl.h" + +namespace kaleidoscope { +namespace plugin { + +class NumPad : public kaleidoscope::Plugin { + public: + NumPad(void) {} + + static uint8_t numPadLayer; + static cRGB color; + static uint8_t lock_hue; + + EventHandlerResult onSetup(void); + EventHandlerResult afterEachCycle(); + + private: + + void cleanupNumlockState(void); + void setKeyboardLEDColors(void); + bool getNumlockState(void); + void syncNumlockState(bool); + + static uint8_t numpadLayerToggleKeyRow; + static uint8_t numpadLayerToggleKeyCol; + static bool numlockUnsynced; + static bool originalNumLockState; +}; +} +} + +extern kaleidoscope::plugin::NumPad NumPad; diff --git a/src/kaleidoscope/plugin/USB-Quirks.cpp b/src/kaleidoscope/plugin/USB-Quirks.cpp new file mode 100644 index 00000000..e308bb8c --- /dev/null +++ b/src/kaleidoscope/plugin/USB-Quirks.cpp @@ -0,0 +1,41 @@ +/* -*- 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 . + */ + +#include + +namespace kaleidoscope { +namespace plugin { + +void USBQuirks::toggleKeyboardProtocol() { + +#if KALEIDOSCOPE_HIDADAPTOR_ENABLE_KEYBOARD_BOOT_PROTOCOL + uint8_t new_protocol = !BootKeyboard.getProtocol(); + + Kaleidoscope.detachFromHost(); + BootKeyboard.default_protocol = new_protocol; + BootKeyboard.setProtocol(new_protocol); + delay(1000); + Kaleidoscope.attachToHost(); +#endif + +} + +} +} + +kaleidoscope::plugin::USBQuirks USBQuirks; diff --git a/src/kaleidoscope/plugin/USB-Quirks.h b/src/kaleidoscope/plugin/USB-Quirks.h new file mode 100644 index 00000000..9f7ce378 --- /dev/null +++ b/src/kaleidoscope/plugin/USB-Quirks.h @@ -0,0 +1,34 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +namespace kaleidoscope { +namespace plugin { +class USBQuirks: public kaleidoscope::Plugin { + public: + USBQuirks() {} + + void toggleKeyboardProtocol(); +}; +} +} + +extern kaleidoscope::plugin::USBQuirks USBQuirks;