diff --git a/README.md b/README.md index a357e99c..8d724250 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,180 @@ # Kaleidoscope-Macros -This is a plugin for [Kaleidoscope][fw], that adds support for macros. +![status][st:stable] [![Build Status][travis:image]][travis:status] - [fw]: https://github.com/keyboardio/Kaleidoscope + [travis:image]: https://travis-ci.org/keyboardio/Kaleidoscope-Macros.svg?branch=master + [travis:status]: https://travis-ci.org/keyboardio/Kaleidoscope-Macros + + [st:stable]: https://img.shields.io/badge/stable-✔-black.svg?style=flat&colorA=44cc11&colorB=494e52 + [st:broken]: https://img.shields.io/badge/broken-X-black.svg?style=flat&colorA=e05d44&colorB=494e52 + [st:experimental]: https://img.shields.io/badge/experimental----black.svg?style=flat&colorA=dfb317&colorB=494e52 + +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 are many 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! + +## Using the plugin + +To use the plugin, we need to include the header, make sure we 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), + END); + case MACRO_HELLO: + if (key_toggled_on(keyState)) { + Macros.type(PSTR("Hello world!")); + } + break; + case MACRO_SPECIAL: + if (key_toggled_on(keyState)) { + // Do something special + } + break; + } + return MACRO_NONE; +} + +void setup() { + Kaleidoscope.use(&Macros); + + Kaleidoscope.setup (); +} +``` + +## Keymap markup + +### `M(id)` + +> Places a macro key on the keymap, with the `id` 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 macros, 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(string)` + +> In cases where we only want to type a string, it is far more convenient to use +> this method: we do not have to use the `MACRO()` helper, but just give this +> one a string, and it will type it for us on the keyboard. +> +> The string is limited to a sequence of printable ASCII characters. No +> international symbols, or unicode, or anything like it: just plain ASCII. +> +> The `string` argument 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, that is. 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. + +## 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. +> +> The sequence must end with the `END` step, otherwise the playback will not be +> able to stop, and will have unpredictable behaviour. + +### `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. +> +> Can only be used from the `macroAction()` overrideable method. + +## `MACRO` steps + +Macro steps can be divided into three 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 two variants: one that prefixes its argument with `Key_`, +and one that does not. The latter are the `Dr`, `Ur`, and `Tr` variants. In most +cases, one is likely to 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), END)` +instead of `MACRO(Tr(Key_X), END)` - making the macro definition shorter, and +more readable. + +* `D(key)`, `Dr(key)`: Simulates a key being pressed (pushed down). +* `U(key)`, `Ur(key)`: Simulates a key being released (going up). +* `T(key)`, `Tr(key)`: Simulates a key being tapped (pressed first, then released). + +### The End + +* `END`: Signals the end of the macro. Anything past this step will be ignored. + But without this step, the plugin will continue trying to play the macro + further, and have unpredictable results. + +## 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.