1
0
Fork 0

Macros in JSON keymaps (#14374)

* macros in json keymaps

* add advanced macro support to json

* add a note about escaping macro strings

* add simple examples

* format json

* add support for language specific keymap extras

* switch to dictionaries instead of inline text for macros

* use SS_TAP on the innermost tap keycode

* add the new macro format to the schema

* document the macro limit

* add the json keyword for syntax highlighting

* fix format that vscode screwed up

* Update feature_macros.md

* add tests for macros

* change ding to beep

* add json support for SENDSTRING_BELL

* update doc based on feedback from sigprof

* document host_layout

* remove unused var

* improve carriage return handling

* support tab characters as well

* Update docs/feature_macros.md

Co-authored-by: Nick Brassel <nick@tzarc.org>

* escape backslash characters

* format

* flake8

* Update quantum/quantum_keycodes.h

Co-authored-by: Nick Brassel <nick@tzarc.org>
This commit is contained in:
Zach White 2021-11-22 11:11:35 -08:00 committed by GitHub
parent 8181b155db
commit 08ce0142ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 319 additions and 33 deletions

View file

@ -4,7 +4,107 @@ Macros allow you to send multiple keystrokes when pressing just one key. QMK has
!> **Security Note**: While it is possible to use macros to send passwords, credit card numbers, and other sensitive information it is a supremely bad idea to do so. Anyone who gets a hold of your keyboard will be able to access that information by opening a text editor.
## `SEND_STRING()` & `process_record_user`
## Using Macros In JSON Keymaps
You can define up to 32 macros in a `keymap.json` file, as used by [Configurator](newbs_building_firmware_configurator.md), and `qmk compile`. You can define these macros in a list under the `macros` keyword, like this:
```json
{
"keyboard": "handwired/my_macropad",
"keymap": "my_keymap",
"macros": [
[
{"action":"down", "keycodes": ["LSFT"]},
"hello world1",
{"action": "up","keycodes": ["LSFT"]}
],
[
{"action":"tap", "keycodes": ["LCTL", "LALT", "DEL"]}
],
[
"ding!",
{"action":"beep"}
],
[
{"action":"tap", "keycodes": ["F1"]},
{"action":"delay", "duration": "1000"},
{"action":"tap", "keycodes": ["PGDN"]}
]
],
"layout": "LAYOUT_all",
"layers": [
["MACRO_0", "MACRO_1", "MACRO_2", "MACRO_3"]
]
}
```
### Selecting Your Host Keyboard Layout
If you type in a language other than English, or use a non-QWERTY layout like Colemak, Dvorak, or Workman, you may have set your computer's input language to match this layout. This presents a challenge when creating macros- you may need to type different keys to get the same letters! To address this you can add the `host_language` key to your keymap.json, like so:
```json
{
"keyboard": "handwired/my_macropad",
"keymap": "my_keymap",
"host_layout": "dvorak",
"macros": [
["Hello, World!"]
],
"layout": "LAYOUT_all",
"layers": [
["MACRO_0"]
]
}
```
The current list of available languages is:
| belgian | bepo | br_abnt2 | canadian_multilingual |
|:-------:|:----:|:--------:|:---------------------:|
| **colemak** | **croatian** | **czech** | **danish** |
| **dvorak_fr** | **dvorak** | **dvp** | **estonian** |
| **finnish** | **fr_ch** | **french_afnor** | **french** |
| **french_osx** | **german_ch** | **german** | **german_osx** |
| **hungarian** | **icelandic** | **italian** | **italian_osx_ansi** |
| **italian_osx_iso** | **jis** | **latvian** | **lithuanian_azerty** |
| **lithuanian_qwerty** | **norman** | **norwegian** | **portuguese** |
| **portuguese_osx_iso** | **romanian** | **serbian_latin** | **slovak** |
| **slovenian** | **spanish_dvorak** | **spanish** | **swedish** |
| **turkish_f** | **turkish_q** | **uk** | **us_international** |
| **workman** | **workman_zxcvm** |
### Macro Basics
Each macro is an array consisting of strings and objects (dictionaries.) Strings are typed to your computer while objects allow you to control how your macro is typed out.
#### Object Format
All objects have one required key: `action`. This tells QMK what the object does. There are currently 5 actions: beep, delay, down, tap, up
Only basic keycodes (prefixed by `KC_`) are supported. Do not include the `KC_` prefix when listing keycodes.
* `beep`
* Play a bell if the keyboard has [audio enabled](feature_audio.md).
* Example: `{"action": "beep"}`
* `delay`
* Pause macro playback. Duration is specified in milliseconds (ms).
* Example: `{"action": "delay", "duration": 500}`
* `down`
* Send a key down event for one or more keycodes.
* Example, single key: `{"action":"down", "keycodes": ["LSFT"]}`
* Example, multiple keys: `{"action":"down", "keycodes": ["CTRL", "LSFT"]}`
* `tap`
* Type a chord, which sends a down event for each key followed by an up event for each key.
* Example, single key: `{"action":"tap", "keycodes": ["F13"]}`
* Example, multiple keys: `{"action":"tap", "keycodes": ["CTRL", "LALT", "DEL"]}`
* `up`
* Send a key up event for one or more keycodes.
* Example, single key: `{"action":"up", "keycodes": ["LSFT"]}`
* Example, multiple keys: `{"action":"up", "keycodes": ["CTRL", "LSFT"]}`
## Using Macros in C Keymaps
### `SEND_STRING()` & `process_record_user`
Sometimes you want a key to type out words or phrases. For the most common situations, we've provided `SEND_STRING()`, which will type out a string (i.e. a sequence of characters) for you. All ASCII characters that are easily translatable to a keycode are supported (e.g. `qmk 123\n\t`).
@ -91,7 +191,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
};
```
### Advanced Macros
#### Advanced Macros
In addition to the `process_record_user()` function, is the `post_process_record_user()` function. This runs after `process_record` and can be used to do things after a keystroke has been sent. This is useful if you want to have a key pressed before and released after a normal key, for instance.
@ -131,7 +231,7 @@ void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
```
### TAP, DOWN and UP
#### TAP, DOWN and UP
You may want to use keys in your macros that you can't write down, such as `Ctrl` or `Home`.
You can send arbitrary keycodes by wrapping them in:
@ -178,7 +278,7 @@ They can be used like this:
Which would send Left Control+`a` (Left Control down, `a`, Left Control up) - notice that they take strings (eg `"k"`), and not the `X_K` keycodes.
### Alternative Keymaps
#### Alternative Keymaps
By default, it assumes a US keymap with a QWERTY layout; if you want to change that (e.g. if your OS uses software Colemak), include this somewhere in your keymap:
@ -186,7 +286,7 @@ By default, it assumes a US keymap with a QWERTY layout; if you want to change t
#include "sendstring_colemak.h"
```
### Strings in Memory
#### Strings in Memory
If for some reason you're manipulating strings and need to print out something you just generated (instead of being a literal, constant string), you can use `send_string()`, like this:
@ -205,13 +305,13 @@ SEND_STRING(".."SS_TAP(X_END));
```
## Advanced Macro Functions
### Advanced Macro Functions
There are some functions you may find useful in macro-writing. Keep in mind that while you can write some fairly advanced code within a macro, if your functionality gets too complex you may want to define a custom keycode instead. Macros are meant to be simple.
?> You can also use the functions described in [Useful function](ref_functions.md) and [Checking modifier state](feature_advanced_keycodes#checking-modifier-state) for additional functionality. For example, `reset_keyboard()` allows you to reset the keyboard as part of a macro and `get_mods() & MOD_MASK_SHIFT` lets you check for the existence of active shift modifiers.
### `record->event.pressed`
#### `record->event.pressed`
This is a boolean value that can be tested to see if the switch is being pressed or released. An example of this is
@ -223,15 +323,15 @@ This is a boolean value that can be tested to see if the switch is being pressed
}
```
### `register_code(<kc>);`
#### `register_code(<kc>);`
This sends the `<kc>` keydown event to the computer. Some examples would be `KC_ESC`, `KC_C`, `KC_4`, and even modifiers such as `KC_LSFT` and `KC_LGUI`.
### `unregister_code(<kc>);`
#### `unregister_code(<kc>);`
Parallel to `register_code` function, this sends the `<kc>` keyup event to the computer. If you don't use this, the key will be held down until it's sent.
### `tap_code(<kc>);`
#### `tap_code(<kc>);`
Sends `register_code(<kc>)` and then `unregister_code(<kc>)`. This is useful if you want to send both the press and release events ("tap" the key, rather than hold it).
@ -239,31 +339,31 @@ If `TAP_CODE_DELAY` is defined (default 0), this function waits that many millis
If the keycode is `KC_CAPS`, it waits `TAP_HOLD_CAPS_DELAY` milliseconds instead (default 80), as macOS prevents accidental Caps Lock activation by waiting for the key to be held for a certain amount of time.
### `tap_code_delay(<kc>, <delay>);`
#### `tap_code_delay(<kc>, <delay>);`
Like `tap_code(<kc>)`, but with a `delay` parameter for specifying arbitrary intervals before sending the unregister event.
### `register_code16(<kc>);`, `unregister_code16(<kc>);` and `tap_code16(<kc>);`
#### `register_code16(<kc>);`, `unregister_code16(<kc>);` and `tap_code16(<kc>);`
These functions work similar to their regular counterparts, but allow you to use modded keycodes (with Shift, Alt, Control, and/or GUI applied to them).
Eg, you could use `register_code16(S(KC_5));` instead of registering the mod, then registering the keycode.
### `clear_keyboard();`
#### `clear_keyboard();`
This will clear all mods and keys currently pressed.
### `clear_mods();`
#### `clear_mods();`
This will clear all mods currently pressed.
### `clear_keyboard_but_mods();`
#### `clear_keyboard_but_mods();`
This will clear all keys besides the mods currently pressed.
## Advanced Example:
### Advanced Example:
### Super ALT↯TAB
#### Super ALT↯TAB
This macro will register `KC_LALT` and tap `KC_TAB`, then wait for 1000ms. If the key is tapped again, it will send another `KC_TAB`; if there is no tap, `KC_LALT` will be unregistered, thus allowing you to cycle through windows.