summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/ChangeLog/20230528/PR20584.md3
-rw-r--r--docs/_summary.md2
-rw-r--r--docs/cli_commands.md19
-rw-r--r--docs/config_options.md11
-rw-r--r--docs/feature_caps_word.md20
-rw-r--r--docs/feature_combo.md33
-rw-r--r--docs/feature_converters.md8
-rw-r--r--docs/feature_dynamic_macros.md2
-rw-r--r--docs/feature_encoders.md16
-rw-r--r--docs/feature_layers.md48
-rw-r--r--docs/feature_led_matrix.md8
-rw-r--r--docs/feature_oled_driver.md119
-rw-r--r--docs/feature_pointing_device.md26
-rw-r--r--docs/feature_repeat_key.md457
-rw-r--r--docs/feature_rgb_matrix.md100
-rw-r--r--docs/feature_rgblight.md13
-rw-r--r--docs/feature_split_keyboard.md6
-rw-r--r--docs/feature_stenography.md2
-rw-r--r--docs/feature_swap_hands.md11
-rw-r--r--docs/getting_started_vagrant.md56
-rw-r--r--docs/ja/_summary.md2
-rw-r--r--docs/ja/config_options.md5
-rw-r--r--docs/ja/feature_combo.md6
-rw-r--r--docs/ja/feature_dynamic_macros.md2
-rw-r--r--docs/ja/feature_stenography.md2
-rw-r--r--docs/ja/getting_started_vagrant.md61
-rw-r--r--docs/ja/tap_hold.md28
-rw-r--r--docs/keycodes.md9
-rw-r--r--docs/mod_tap.md2
-rw-r--r--docs/newbs_building_firmware_workflow.md2
-rw-r--r--docs/quantum_painter.md24
-rw-r--r--docs/squeezing_avr.md1
-rw-r--r--docs/tap_hold.md89
-rw-r--r--docs/understanding_qmk.md2
-rw-r--r--docs/ws2812_driver.md8
-rw-r--r--docs/zh-cn/_summary.md4
-rw-r--r--docs/zh-cn/getting_started_vagrant.md61
-rw-r--r--docs/zh-cn/mod_tap.md2
38 files changed, 836 insertions, 434 deletions
diff --git a/docs/ChangeLog/20230528/PR20584.md b/docs/ChangeLog/20230528/PR20584.md
new file mode 100644
index 0000000000..e9e49f5730
--- /dev/null
+++ b/docs/ChangeLog/20230528/PR20584.md
@@ -0,0 +1,3 @@
+Two new boolean callback functions, `pre_process_record_kb` and `pre_process_record_user`, are added in this change. They are called at the beginning of `process_record`, right before `process_combo`.
+
+Similar to existing `*_kb` and `*_user` callback functions, returning `false` will halt further processing of key events. The `pre_process_record_user` function will allow user space opportunity to handle or capture an input before it undergoes quantum processing. For example, while action tapping is still resolving the tap or hold output of a mod-tap key, `pre_process_record_user` can capture the next key record of an input event that follows. That key record can be used to influence the [decision of the mod-tap](https://docs.qmk.fm/#/tap_hold) key that is currently undergoing quantum processing.
diff --git a/docs/_summary.md b/docs/_summary.md
index 01808bd675..3d9bde6b17 100644
--- a/docs/_summary.md
+++ b/docs/_summary.md
@@ -41,7 +41,6 @@
* [Keymap Overview](keymap.md)
* Development Environments
* [Docker Guide](getting_started_docker.md)
- * [Vagrant Guide](getting_started_vagrant.md)
* Flashing
* [Flashing](flashing.md)
* [Flashing ATmega32A (ps2avrgb)](flashing_bootloadhid.md)
@@ -71,6 +70,7 @@
* [Macros](feature_macros.md)
* [Mouse Keys](feature_mouse_keys.md)
* [Programmable Button](feature_programmable_button.md)
+ * [Repeat Key](feature_repeat_key.md)
* [Space Cadet Shift](feature_space_cadet.md)
* [US ANSI Shifted Keys](keycodes_us_ansi_shifted.md)
diff --git a/docs/cli_commands.md b/docs/cli_commands.md
index d759c9c35a..79fd9de575 100644
--- a/docs/cli_commands.md
+++ b/docs/cli_commands.md
@@ -165,16 +165,31 @@ qmk find -f 'processor=STM32F411'
qmk find -f 'processor=STM32F411' -f 'features.rgb_matrix=true'
```
+The following filter expressions are also supported:
+
+ - `exists(key)`: Match targets where `key` is present.
+ - `absent(key)`: Match targets where `key` is not present.
+ - `contains(key, value)`: Match targets where `key` contains `value`. Can be used for strings, arrays and object keys.
+ - `length(key, value)`: Match targets where the length of `key` is `value`. Can be used for strings, arrays and objects.
+
+You can also list arbitrary values for each matched target with `--print`:
+
+```
+qmk find -f 'processor=STM32F411' -p 'keyboard_name' -p 'features.rgb_matrix'
+```
+
**Usage**:
```
-qmk find [-h] [-km KEYMAP] [-f FILTER]
+qmk find [-h] [-km KEYMAP] [-p PRINT] [-f FILTER]
options:
-km KEYMAP, --keymap KEYMAP
The keymap name to build. Default is 'default'.
+ -p PRINT, --print PRINT
+ For each matched target, print the value of the supplied info.json key. May be passed multiple times.
-f FILTER, --filter FILTER
- Filter the list of keyboards based on the supplied value in rules.mk. Matches info.json structure, and accepts the formats 'features.rgblight=true' or 'exists(matrix_pins.direct)'. May be passed multiple times, all filters need to match. Value may include wildcards such as '*' and '?'.
+ Filter the list of keyboards based on their info.json data. Accepts the formats key=value, function(key), or function(key,value), eg. 'features.rgblight=true'. Valid functions are 'absent', 'contains', 'exists' and 'length'. May be passed multiple times; all filters need to match. Value may include wildcards such as '*' and '?'.
```
## `qmk console`
diff --git a/docs/config_options.md b/docs/config_options.md
index 5bfb7c5d58..4698260118 100644
--- a/docs/config_options.md
+++ b/docs/config_options.md
@@ -150,7 +150,7 @@ If you define these options you will enable the associated feature, which may in
* `#define TAPPING_TERM_PER_KEY`
* enables handling for per key `TAPPING_TERM` settings
* `#define RETRO_TAPPING`
- * tap anyway, even after TAPPING_TERM, if there was no other key interruption between press and release
+ * tap anyway, even after `TAPPING_TERM`, if there was no other key interruption between press and release
* See [Retro Tapping](tap_hold.md#retro-tapping) for details
* `#define RETRO_TAPPING_PER_KEY`
* enables handling for per key `RETRO_TAPPING` settings
@@ -161,9 +161,6 @@ If you define these options you will enable the associated feature, which may in
* See [Permissive Hold](tap_hold.md#permissive-hold) for details
* `#define PERMISSIVE_HOLD_PER_KEY`
* enabled handling for per key `PERMISSIVE_HOLD` settings
-* `#define IGNORE_MOD_TAP_INTERRUPT`
- * makes it possible to do rolling combos (zx) with keys that convert to other keys on hold, by enforcing the `TAPPING_TERM` for both keys.
- * See [Ignore Mod Tap Interrupt](tap_hold.md#ignore-mod-tap-interrupt) for details
* `#define QUICK_TAP_TERM 100`
* tap-then-hold timing to use a dual role key to repeat keycode
* See [Quick Tap Term](tap_hold.md#quick-tap-term)
@@ -189,8 +186,6 @@ If you define these options you will enable the associated feature, which may in
* how long before oneshot times out
* `#define ONESHOT_TAP_TOGGLE 2`
* how many taps before oneshot toggle is triggered
-* `#define COMBO_COUNT 2`
- * Set this to the number of combos that you're using in the [Combo](feature_combo.md) feature. Or leave it undefined and programmatically set the count.
* `#define COMBO_TERM 200`
* how long for the Combo keys to be detected. Defaults to `TAPPING_TERM` if not defined.
* `#define COMBO_MUST_HOLD_MODS`
@@ -217,7 +212,7 @@ If you define these options you will enable the associated feature, which may in
## RGB Light Configuration
-* `#define RGB_DI_PIN D7`
+* `#define WS2812_DI_PIN D7`
* pin the DI on the WS2812 is hooked-up to
* `#define RGBLIGHT_LAYERS`
* Lets you define [lighting layers](feature_rgblight.md?id=lighting-layers) that can be toggled on or off. Great for showing the current keyboard layer or caps lock state.
@@ -233,7 +228,7 @@ If you define these options you will enable the associated feature, which may in
* `#define RGBLIGHT_SPLIT`
* Needed if both halves of the board have RGB LEDs wired directly to the RGB output pin on the controllers instead of passing the output of the left half to the input of the right half
* `#define RGBLED_SPLIT { 6, 6 }`
- * number of LEDs connected that are directly wired to `RGB_DI_PIN` on each half of a split keyboard
+ * number of LEDs connected that are directly wired to the RGB pin on each half of a split keyboard
* First value indicates number of LEDs for left half, second value is for the right half
* When RGBLED_SPLIT is defined, RGBLIGHT_SPLIT is implicitly defined.
* `#define RGBLIGHT_HUE_STEP 12`
diff --git a/docs/feature_caps_word.md b/docs/feature_caps_word.md
index c58d1a56e2..7f726b059d 100644
--- a/docs/feature_caps_word.md
+++ b/docs/feature_caps_word.md
@@ -90,6 +90,26 @@ by defining `IS_COMMAND()` in config.h:
## Customizing Caps Word :id=customizing-caps-word
+### Invert on shift :id=invert-on-shift
+
+By default, Caps Word turns off when Shift keys are pressed, considering them as
+word-breaking. Alternatively with the `CAPS_WORD_INVERT_ON_SHIFT` option,
+pressing the Shift key continues Caps Word and inverts the shift state. This
+is convenient for uncapitalizing one or a few letters within a word, for
+example with Caps Word on, typing "D, B, Shift+A, Shift+A, S" produces "DBaaS",
+or typing "P, D, F, Shift+S" produces "PDFs".
+
+Enable it by adding in config.h
+
+```c
+#define CAPS_WORD_INVERT_ON_SHIFT
+```
+
+This option works with regular Shift keys `KC_LSFT` and `KC_RSFT`, mod-tap Shift
+keys, and one-shot Shift keys. Note that while Caps Word is on, one-shot Shift
+keys behave like regular Shift keys, and have effect only while they are held.
+
+
### Idle timeout :id=idle-timeout
Caps Word turns off automatically if no keys are pressed for
diff --git a/docs/feature_combo.md b/docs/feature_combo.md
index 075fe252ae..fd241061fb 100644
--- a/docs/feature_combo.md
+++ b/docs/feature_combo.md
@@ -4,15 +4,12 @@ The Combo feature is a chording type solution for adding custom actions. It lets
To enable this feature, you need to add `COMBO_ENABLE = yes` to your `rules.mk`.
-Additionally, in your `config.h`, you'll need to specify the number of combos that you'll be using, by adding `#define COMBO_COUNT 1` (replacing 1 with the number that you're using). It is also possible to not define this and instead set the variable `COMBO_LEN` yourself. There's a trick where we don't need to think about this variable at all. More on this later.
-
-
Then, in your `keymap.c` file, you'll need to define a sequence of keys, terminated with `COMBO_END`, and a structure to list the combination of keys, and its resulting action.
```c
const uint16_t PROGMEM test_combo1[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM test_combo2[] = {KC_C, KC_D, COMBO_END};
-combo_t key_combos[COMBO_COUNT] = {
+combo_t key_combos[] = {
COMBO(test_combo1, KC_ESC),
COMBO(test_combo2, LCTL(KC_Z)), // keycodes with modifiers are possible too!
};
@@ -33,7 +30,7 @@ It is possible to overlap combos. Before, with the example below both combos wou
```c
const uint16_t PROGMEM test_combo1[] = {LSFT_T(KC_A), LT(1, KC_B), COMBO_END};
const uint16_t PROGMEM test_combo2[] = {LSFT_T(KC_A), LT(1, KC_B), KC_C, COMBO_END};
-combo_t key_combos[COMBO_COUNT] = {
+combo_t key_combos[] = {
COMBO(test_combo1, KC_ESC)
COMBO(test_combo2, KC_TAB)
};
@@ -41,17 +38,15 @@ combo_t key_combos[COMBO_COUNT] = {
## Examples
-A long list of combos can be defined in an `enum` list that ends with `COMBO_LENGTH` and you can leave `COMBO_COUNT` undefined:
+A long list of combos can be defined in an `enum` list:
```c
enum combos {
AB_ESC,
JK_TAB,
QW_SFT,
- SD_LAYER,
- COMBO_LENGTH
+ SD_LAYER
};
-uint16_t COMBO_LEN = COMBO_LENGTH; // remove the COMBO_COUNT define and use this instead!
const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM jk_combo[] = {KC_J, KC_K, COMBO_END};
@@ -72,9 +67,7 @@ For a more complicated implementation, you can use the `process_combo_event` fun
enum combo_events {
EM_EMAIL,
BSPC_LSFT_CLEAR,
- COMBO_LENGTH
};
-uint16_t COMBO_LEN = COMBO_LENGTH; // remove the COMBO_COUNT define and use this instead!
const uint16_t PROGMEM email_combo[] = {KC_E, KC_M, COMBO_END};
const uint16_t PROGMEM clear_line_combo[] = {KC_BSPC, KC_LSFT, COMBO_END};
@@ -259,18 +252,6 @@ bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode
}
```
-### Variable Length Combos
-If you leave `COMBO_COUNT` undefined in `config.h`, it allows you to programmatically declare the size of the Combo data structure and avoid updating `COMBO_COUNT`. Instead a variable called `COMBO_LEN` has to be set. It can be set with something similar to the following in `keymap.c`: `uint16_t COMBO_LEN = ARRAY_SIZE(key_combos);` or by adding `COMBO_LENGTH` as the *last* entry in the combo enum and then `uint16_t COMBO_LEN = COMBO_LENGTH;` as such:
-```c
-enum myCombos {
- ...,
- COMBO_LENGTH
-};
-uint16_t COMBO_LEN = COMBO_LENGTH;
-```
-Regardless of the method used to declare `COMBO_LEN`, this also requires to convert the `combo_t key_combos[COMBO_COUNT] = {...};` line to `combo_t key_combos[] = {...};`.
-
-
### Combo timer
Normally, the timer is started on the first key press and then reset on every subsequent key press within the `COMBO_TERM`.
@@ -300,10 +281,8 @@ Here's an example where a combo resolves to two modifiers, and on key releases t
```c
enum combos {
- AB_MODS,
- COMBO_LENGTH
+ AB_MODS
};
-uint16_t COMBO_LEN = COMBO_LENGTH;
const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
@@ -415,6 +394,4 @@ SUBS(TH_THE, "the", KC_T, KC_H) // SUBS uses SEND_STRING to output the give
...
```
-Now, you can update only one place to add or alter combos. You don't even need to remember to update the `COMBO_COUNT` or the `COMBO_LEN` variables at all. Everything is taken care of. Magic!
-
For small to huge ready made dictionaries of combos, you can check out http://combos.gboards.ca/.
diff --git a/docs/feature_converters.md b/docs/feature_converters.md
index ec1f3915ee..b1abfa373a 100644
--- a/docs/feature_converters.md
+++ b/docs/feature_converters.md
@@ -20,11 +20,13 @@ Currently the following converters are available:
| `promicro` | `rp2040_ce` |
| `promicro` | `elite_pi` |
| `promicro` | `helios` |
+| `promicro` | `liatris` |
| `promicro` | `michi` |
| `elite_c` | `stemcell` |
| `elite_c` | `rp2040_ce` |
| `elite_c` | `elite_pi` |
| `elite_c` | `helios` |
+| `elite_c` | `liatris` |
See below for more in depth information on each converter.
@@ -87,6 +89,7 @@ If a board currently supported in QMK uses a [Pro Micro](https://www.sparkfun.co
| [customMK Bonsai C4](https://shop.custommk.com/products/bonsai-c4-microcontroller-board) | `bonsai_c4` |
| [Elite-Pi](https://keeb.io/products/elite-pi-usb-c-pro-micro-replacement-rp2040) | `elite_pi` |
| [0xCB Helios](https://keeb.supply/products/0xcb-helios) | `helios` |
+| [Liatris](https://splitkb.com/products/liatris) | `liatris` |
| [Michi](https://github.com/ci-bus/michi-promicro-rp2040) | `michi` |
Converter summary:
@@ -103,6 +106,7 @@ Converter summary:
| `rp2040_ce` | `-e CONVERT_TO=rp2040_ce` | `CONVERT_TO=rp2040_ce` | `#ifdef CONVERT_TO_RP2040_CE` |
| `elite_pi` | `-e CONVERT_TO=elite_pi` | `CONVERT_TO=elite_pi` | `#ifdef CONVERT_TO_ELITE_PI` |
| `helios` | `-e CONVERT_TO=helios` | `CONVERT_TO=helios` | `#ifdef CONVERT_TO_HELIOS` |
+| `liatris` | `-e CONVERT_TO=liatris` | `CONVERT_TO=liatris` | `#ifdef CONVERT_TO_LIATRIS` |
| `michi` | `-e CONVERT_TO=michi` | `CONVERT_TO=michi` | `#ifdef CONVERT_TO_MICHI` |
### Proton C :id=proton_c
@@ -167,7 +171,7 @@ The Bonsai C4 only has one on-board LED (B2), and by default, both the Pro Micro
#define B0 PAL_LINE(GPIOA, 9)
```
-### RP2040 Community Edition - Elite-Pi and Helios :id=rp2040_ce
+### RP2040 Community Edition - Elite-Pi, Helios, and Liatris :id=rp2040_ce
Feature set currently identical to [Adafruit KB2040](#kb2040).
@@ -184,6 +188,7 @@ If a board currently supported in QMK uses an [Elite-C](https://keeb.io/products
| [STeMCell](https://github.com/megamind4089/STeMCell) | `stemcell` |
| [Elite-Pi](https://keeb.io/products/elite-pi-usb-c-pro-micro-replacement-rp2040) | `elite_pi` |
| [0xCB Helios](https://keeb.supply/products/0xcb-helios) | `helios` |
+| [Liatris](https://splitkb.com/products/liatris) | `liatris` |
Converter summary:
@@ -193,6 +198,7 @@ Converter summary:
| `rp2040_ce` | `-e CONVERT_TO=rp2040_ce` | `CONVERT_TO=rp2040_ce` | `#ifdef CONVERT_TO_RP2040_CE` |
| `elite_pi` | `-e CONVERT_TO=elite_pi` | `CONVERT_TO=elite_pi` | `#ifdef CONVERT_TO_ELITE_PI` |
| `helios` | `-e CONVERT_TO=helios` | `CONVERT_TO=helios` | `#ifdef CONVERT_TO_HELIOS` |
+| `liatris` | `-e CONVERT_TO=liatris` | `CONVERT_TO=liatris` | `#ifdef CONVERT_TO_LIATRIS` |
### STeMCell :id=stemcell_elite
diff --git a/docs/feature_dynamic_macros.md b/docs/feature_dynamic_macros.md
index f5a6952b6b..8ab1bad61c 100644
--- a/docs/feature_dynamic_macros.md
+++ b/docs/feature_dynamic_macros.md
@@ -59,7 +59,7 @@ There are a number of hooks that you can use to add custom functionality and fee
Note, that direction indicates which macro it is, with `1` being Macro 1, `-1` being Macro 2, and 0 being no macro.
-* `dynamic_macro_record_start_user(void)` - Triggered when you start recording a macro.
+* `dynamic_macro_record_start_user(int8_t direction)` - Triggered when you start recording a macro.
* `dynamic_macro_play_user(int8_t direction)` - Triggered when you play back a macro.
* `dynamic_macro_record_key_user(int8_t direction, keyrecord_t *record)` - Triggered on each keypress while recording a macro.
* `dynamic_macro_record_end_user(int8_t direction)` - Triggered when the macro recording is stopped.
diff --git a/docs/feature_encoders.md b/docs/feature_encoders.md
index 1c521a4eff..891baeefa1 100644
--- a/docs/feature_encoders.md
+++ b/docs/feature_encoders.md
@@ -81,7 +81,7 @@ Your `keymap.c` will then need an encoder mapping defined (for four layers and t
```c
#if defined(ENCODER_MAP_ENABLE)
-const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
[_BASE] = { ENCODER_CCW_CW(KC_MS_WH_UP, KC_MS_WH_DOWN), ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[_LOWER] = { ENCODER_CCW_CW(RGB_HUD, RGB_HUI), ENCODER_CCW_CW(RGB_SAD, RGB_SAI) },
[_RAISE] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI), ENCODER_CCW_CW(RGB_SPD, RGB_SPI) },
@@ -102,9 +102,9 @@ Using encoder mapping pumps events through the normal QMK keycode processing pip
## Callbacks
-When not using `ENCODER_MAP_ENABLE = yes`, the callback functions can be inserted into your `<keyboard>.c`:
+?> [**Default Behaviour**](https://github.com/qmk/qmk_firmware/blob/master/quantum/encoder.c#L79-#L98): all encoders installed will function as volume up (`KC_VOLU`) on clockwise rotation and volume down (`KC_VOLD`) on counter-clockwise rotation. If you do not wish to override this, no further configuration is necessary.
-?> Those who are adding new keyboard support where encoders are enabled at the keyboard level should include basic encoder functionality at the keyboard level (`<keyboard>.c`) using the `encoder_update_kb()` function, that way it works for QMK Configuator users and exists in general.
+If you would like the alter the default behaviour, and are not using `ENCODER_MAP_ENABLE = yes`, the callback functions can be inserted into your `<keyboard>.c`:
```c
bool encoder_update_kb(uint8_t index, bool clockwise) {
@@ -113,9 +113,9 @@ bool encoder_update_kb(uint8_t index, bool clockwise) {
}
if (index == 0) { /* First encoder */
if (clockwise) {
- tap_code_delay(KC_VOLU, 10);
+ tap_code(KC_PGDN);
} else {
- tap_code_delay(KC_VOLD, 10);
+ tap_code(KC_PGUP);
}
} else if (index == 1) { /* Second encoder */
if (clockwise) {
@@ -134,9 +134,9 @@ or `keymap.c`:
bool encoder_update_user(uint8_t index, bool clockwise) {
if (index == 0) { /* First encoder */
if (clockwise) {
- tap_code_delay(KC_VOLU, 10);
+ tap_code(KC_PGDN);
} else {
- tap_code_delay(KC_VOLD, 10);
+ tap_code(KC_PGUP);
}
} else if (index == 1) { /* Second encoder */
if (clockwise) {
@@ -149,7 +149,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) {
}
```
-!> If you return `true` in the keymap level `_user` function, it will allow the keyboard level encoder code to run on top of your own. Returning `false` will override the keyboard level function, if setup correctly. This is generally the safest option to avoid confusion.
+!> If you return `true` in the keymap level `_user` function, it will allow the keyboard/core level encoder code to run on top of your own. Returning `false` will override the keyboard level function, if setup correctly. This is generally the safest option to avoid confusion.
## Hardware
diff --git a/docs/feature_layers.md b/docs/feature_layers.md
index f8cb53eda4..8503603ffe 100644
--- a/docs/feature_layers.md
+++ b/docs/feature_layers.md
@@ -127,6 +127,54 @@ layer_state_t layer_state_set_user(layer_state_t state) {
}
```
+### Example: Keycode to cycle through layers
+
+This example shows how to implement a custom keycode to cycle through a range of layers.
+
+```c
+// Define the keycode, `QK_USER` avoids collisions with existing keycodes
+enum keycodes {
+ KC_CYCLE_LAYERS = QK_USER,
+};
+
+// 1st layer on the cycle
+#define LAYER_CYCLE_START 0
+// Last layer on the cycle
+#define LAYER_CYCLE_END 4
+
+// Add the behaviour of this new keycode
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+ case KC_CYCLE_LAYERS:
+ // Our logic will happen on presses, nothing is done on releases
+ if (!record->event.pressed) {
+ // We've already handled the keycode (doing nothing), let QMK know so no further code is run unnecessarily
+ return false;
+ }
+
+ uint8_t current_layer = get_highest_layer(layer_state);
+
+ // Check if we are within the range, if not quit
+ if (curent_layer > LAYER_CYCLE_END || current_layer < LAYER_CYCLE_START) {
+ return false;
+ }
+
+ uint8_t next_layer = current_layer + 1;
+ if (next_layer > LAYER_CYCLE_END) {
+ next_layer = LAYER_CYCLE_START;
+ }
+ layer_move(next_layer);
+ return false;
+
+ // Process other keycodes normally
+ default:
+ return true;
+ }
+}
+
+// Place `KC_CYCLE_LAYERS` as a keycode in your keymap
+```
+
Use the `IS_LAYER_ON_STATE(state, layer)` and `IS_LAYER_OFF_STATE(state, layer)` macros to check the status of a particular layer.
Outside of `layer_state_set_*` functions, you can use the `IS_LAYER_ON(layer)` and `IS_LAYER_OFF(layer)` macros to check global layer state.
diff --git a/docs/feature_led_matrix.md b/docs/feature_led_matrix.md
index 1cde9b66e1..bc86099f1f 100644
--- a/docs/feature_led_matrix.md
+++ b/docs/feature_led_matrix.md
@@ -378,13 +378,7 @@ For inspiration and examples, check out the built-in effects under `quantum/led_
## EEPROM storage :id=eeprom-storage
-The EEPROM for it is currently shared with the RGB Matrix system (it's generally assumed only one feature would be used at a time), but could be configured to use its own 32bit address with:
-
-```c
-#define EECONFIG_LED_MATRIX (uint32_t *)28
-```
-
-Where `28` is an unused index from `eeconfig.h`.
+The EEPROM for it is currently shared with the RGB Matrix system (it's generally assumed only one feature would be used at a time).
### Direct Operation :id=direct-operation
|Function |Description |
diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md
index dea9cb8074..a62294b23a 100644
--- a/docs/feature_oled_driver.md
+++ b/docs/feature_oled_driver.md
@@ -2,15 +2,18 @@
## Supported Hardware
-OLED modules using SSD1306 or SH1106 driver ICs, communicating over I2C.
+OLED modules using SSD1306, SH1106 or SH1107 driver ICs, communicating over I2C or SPI.
Tested combinations:
-|IC |Size |Platform|Notes |
-|---------|------|--------|------------------------|
-|SSD1306 |128x32|AVR |Primary support |
-|SSD1306 |128x64|AVR |Verified working |
-|SSD1306 |128x32|Arm | |
-|SH1106 |128x64|AVR |No rotation or scrolling|
+|IC |Size |Platform|Notes |
+|---------|-------|--------|------------------------|
+|SSD1306 |128x32 |AVR |Primary support |
+|SSD1306 |128x64 |AVR |Verified working |
+|SSD1306 |128x32 |Arm | |
+|SH1106 |128x64 |AVR |No scrolling |
+|SH1107 |64x128 |AVR |No scrolling |
+|SH1107 |64x128 |Arm |No scrolling |
+|SH1107 |128x128|Arm |No scrolling |
Hardware configurations using Arm-based microcontrollers or different sizes of OLED modules may be compatible, but are untested.
@@ -23,15 +26,26 @@ OLED_ENABLE = yes
```
## OLED type
-|OLED Driver |Supported Device |
-|-------------------|---------------------------|
-|SSD1306 (default) |For both SSD1306 and SH1106|
+
+|OLED Driver |Supported Device |
+|-------------------|------------------------------------|
+|SSD1306 (default) |For both SSD1306, SH1106, and SH1107|
e.g.
```make
OLED_DRIVER = SSD1306
```
+|OLED Transport | |
+|---------------|------------------------------------------------|
+|i2c (default) | Uses I2C for communication with the OLED panel |
+|spi | Uses SPI for communication with the OLED panel |
+
+e.g.
+```make
+OLED_TRANSPORT = i2c
+```
+
Then in your `keymap.c` file, implement the OLED task call. This example assumes your keymap has three layers named `_QWERTY`, `_FN` and `_ADJ`:
```c
@@ -159,32 +173,57 @@ These configuration options should be placed in `config.h`. Example:
#define OLED_BRIGHTNESS 128
```
+|Define |Default |Description |
+|---------------------------|-------------------------------|---------------------------------------------------------------------------------------------------------------------|
+|`OLED_BRIGHTNESS` |`255` |The default brightness level of the OLED, from 0 to 255. |
+|`OLED_COLUMN_OFFSET` |`0` |Shift output to the right this many pixels.<br />Useful for 128x64 displays centered on a 132x64 SH1106 IC. |
+|`OLED_DISPLAY_CLOCK` |`0x80` |Set the display clock divide ratio/oscillator frequency. |
+|`OLED_FONT_H` |`"glcdfont.c"` |The font code file to use for custom fonts |
+|`OLED_FONT_START` |`0` |The starting character index for custom fonts |
+|`OLED_FONT_END` |`223` |The ending character index for custom fonts |
+|`OLED_FONT_WIDTH` |`6` |The font width |
+|`OLED_FONT_HEIGHT` |`8` |The font height (untested) |
+|`OLED_IC` |`OLED_IC_SSD1306` |Set to `OLED_IC_SH1106` or `OLED_IC_SH1107` if the corresponding controller chip is used. |
+|`OLED_FADE_OUT` |*Not defined* |Enables fade out animation. Use together with `OLED_TIMEOUT`. |
+|`OLED_FADE_OUT_INTERVAL` |`0` |The speed of fade out animation, from 0 to 15. Larger values are slower. |
+|`OLED_SCROLL_TIMEOUT` |`0` |Scrolls the OLED screen after 0ms of OLED inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
+|`OLED_SCROLL_TIMEOUT_RIGHT`|*Not defined* |Scroll timeout direction is right when defined, left when undefined. |
+|`OLED_TIMEOUT` |`60000` |Turns off the OLED screen after 60000ms of screen update inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
+|`OLED_UPDATE_INTERVAL` |`0` (`50` for split keyboards) |Set the time interval for updating the OLED display in ms. This will improve the matrix scan rate. |
+|`OLED_UPDATE_PROCESS_LIMIT'|`1` |Set the number of dirty blocks to render per loop. Increasing may degrade performance. |
+
+### I2C Configuration
|Define |Default |Description |
|---------------------------|-----------------|--------------------------------------------------------------------------------------------------------------------------|
|`OLED_DISPLAY_ADDRESS` |`0x3C` |The i2c address of the OLED Display |
-|`OLED_FONT_H` |`"glcdfont.c"` |The font code file to use for custom fonts |
-|`OLED_FONT_START` |`0` |The starting character index for custom fonts |
-|`OLED_FONT_END` |`223` |The ending character index for custom fonts |
-|`OLED_FONT_WIDTH` |`6` |The font width |
-|`OLED_FONT_HEIGHT` |`8` |The font height (untested) |
-|`OLED_TIMEOUT` |`60000` |Turns off the OLED screen after 60000ms of screen update inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
-|`OLED_FADE_OUT` |*Not defined* |Enables fade out animation. Use together with `OLED_TIMEOUT`. |
-|`OLED_FADE_OUT_INTERVAL` |`0` |The speed of fade out animation, from 0 to 15. Larger values are slower. |
-|`OLED_SCROLL_TIMEOUT` |`0` |Scrolls the OLED screen after 0ms of OLED inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
-|`OLED_SCROLL_TIMEOUT_RIGHT`|*Not defined* |Scroll timeout direction is right when defined, left when undefined. |
-|`OLED_IC` |`OLED_IC_SSD1306`|Set to `OLED_IC_SH1106` if you're using the SH1106 OLED controller. |
-|`OLED_COLUMN_OFFSET` |`0` |(SH1106 only.) Shift output to the right this many pixels.<br />Useful for 128x64 displays centered on a 132x64 SH1106 IC.|
-|`OLED_BRIGHTNESS` |`255` |The default brightness level of the OLED, from 0 to 255. |
-|`OLED_UPDATE_INTERVAL` |`0` |Set the time interval for updating the OLED display in ms. This will improve the matrix scan rate. |
-
- ## 128x64 & Custom sized OLED Displays
-
- The default display size for this feature is 128x32 and all necessary defines are precalculated with that in mind. We have added a define, `OLED_DISPLAY_128X64`, to switch all the values to be used in a 128x64 display, as well as added a custom define, `OLED_DISPLAY_CUSTOM`, that allows you to provide the necessary values to the driver.
+
+### SPI Configuration
+
+|Define |Default |Description |
+|---------------------------|-----------------|--------------------------------------------------------------------------------------------------------------------------|
+|`OLED_DC_PIN` | Required |The pin used for the DC connection of the OLED Display. |
+|`OLED_CS_PIN` | Required |The pin used for the CS connection of the OLED Display. |
+|`OLED_RST_PIN` | *Not defined* |The pin used for the RST connection of the OLED Display (may be left undefined if the RST pin is not connected). |
+|`OLED_SPI_MODE` |`3` (default) |The SPI Mode for the OLED Display (not typically changed). |
+|`OLED_SPI_DIVISOR` |`2` (default) |The SPI Multiplier to use for the OLED Display. |
+
+## 128x64 & Custom sized OLED Displays
+
+ The default display size for this feature is 128x32, and the defaults are set with that in mind. However, there are a number of additional presets for common sizes that we have added. You can define one of these values to use the presets. If your display doesn't match one of these presets, you can define `OLED_DISPLAY_CUSTOM` to manually specify all of the values.
+
+|Define |Default |Description |
+|----------------------|---------------|---------------------------------------------------------------------------------------------------------------------------------------|
+|`OLED_DISPLAY_128X64` |*Not defined* |Changes the display defines for use with 128x64 displays. |
+|`OLED_DISPLAY_64X32` |*Not defined* |Changes the display defines for use with 64x32 displays. |
+|`OLED_DISPLAY_64X48` |*Not defined* |Changes the display defines for use with 64x48 displays. |
+|`OLED_DISPLAY_64X128` |*Not defined* |Changes the display defines for use with 64x128 displays. |
+|`OLED_DISPLAY_128X128`|*Not defined* |Changes the display defines for use with 128x128 displays. |
+|`OLED_DISPLAY_CUSTOM` |*Not defined* |Changes the display defines for use with custom displays.<br>Requires user to implement the below defines. |
+
+!> 64x128 and 128x128 displays default to the SH1107 IC type, as these heights are not supported by the other IC types.
|Define |Default |Description |
-|---------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------|
-|`OLED_DISPLAY_128X64`|*Not defined* |Changes the display defines for use with 128x64 displays. |
-|`OLED_DISPLAY_CUSTOM`|*Not defined* |Changes the display defines for use with custom displays.<br>Requires user to implement the below defines. |
+| --------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------|
|`OLED_DISPLAY_WIDTH` |`128` |The width of the OLED display. |
|`OLED_DISPLAY_HEIGHT`|`32` |The height of the OLED display. |
|`OLED_MATRIX_SIZE` |`512` |The local buffer size to allocate.<br>`(OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)`. |
@@ -192,14 +231,13 @@ These configuration options should be placed in `config.h`. Example:
|`OLED_BLOCK_COUNT` |`16` |The number of blocks the display is divided into for dirty rendering.<br>`(sizeof(OLED_BLOCK_TYPE) * 8)`. |
|`OLED_BLOCK_SIZE` |`32` |The size of each block for dirty rendering<br>`(OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)`. |
|`OLED_COM_PINS` |`COM_PINS_SEQ` |How the SSD1306 chip maps it's memory to display.<br>Options are `COM_PINS_SEQ`, `COM_PINS_ALT`, `COM_PINS_SEQ_LR`, & `COM_PINS_ALT_LR`.|
+|`OLED_COM_PIN_COUNT` |*Not defined* |Number of COM pins supported by the controller.<br>If not defined, the value appropriate for the defined `OLED_IC` is used. |
+|`OLED_COM_PIN_OFFSET`|`0` |Number of the first COM pin used by the OLED matrix. |
|`OLED_SOURCE_MAP` |`{ 0, ... N }` |Precalculated source array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
|`OLED_TARGET_MAP` |`{ 24, ... N }`|Precalculated target array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
-
### 90 Degree Rotation - Technical Mumbo Jumbo
-!> Rotation is unsupported on the SH1106.
-
```c
// OLED Rotation enum values are flags
typedef enum {
@@ -210,7 +248,7 @@ typedef enum {
} oled_rotation_t;
```
-OLED displays driven by SSD1306 drivers only natively support in hardware 0 degree and 180 degree rendering. This feature is done in software and not free. Using this feature will increase the time to calculate what data to send over i2c to the OLED. If you are strapped for cycles, this can cause keycodes to not register. In testing however, the rendering time on an ATmega32U4 board only went from 2ms to 5ms and keycodes not registering was only noticed once we hit 15ms.
+OLED displays driven by SSD1306, SH1106 or SH1107 drivers only natively support in hardware 0 degree and 180 degree rendering. This feature is done in software and not free. Using this feature will increase the time to calculate what data to send over i2c to the OLED. If you are strapped for cycles, this can cause keycodes to not register. In testing however, the rendering time on an ATmega32U4 board only went from 2ms to 5ms and keycodes not registering was only noticed once we hit 15ms.
90 degree rotation is achieved by using bitwise operations to rotate each 8 block of memory and uses two precalculated arrays to remap buffer memory to OLED memory. The memory map defines are precalculated for remap performance and are calculated based on the display height, width, and block size. For example, in the 128x32 implementation with a `uint8_t` block type, we have a 64 byte block size. This gives us eight 8 byte blocks that need to be rotated and rendered. The OLED renders horizontally two 8 byte blocks before moving down a page, e.g:
@@ -232,6 +270,8 @@ However the local buffer is stored as if it was Height x Width display instead o
So those precalculated arrays just index the memory offsets in the order in which each one iterates its data.
+Rotation on SH1106 and SH1107 is noticeably less efficient than on SSD1306, because these controllers do not support the “horizontal addressing mode”, which allows transferring the data for the whole rotated block at once; instead, separate address setup commands for every page in the block are required. The screen refresh time for SH1107 is therefore about 45% higher than for a same size screen with SSD1306 when using STM32 MCUs (on AVR the slowdown is about 20%, because the code which actually rotates the bitmap consumes more time).
+
## OLED API
```c
@@ -253,6 +293,11 @@ bool oled_init(oled_rotation_t rotation);
oled_rotation_t oled_init_kb(oled_rotation_t rotation);
oled_rotation_t oled_init_user(oled_rotation_t rotation);
+// Send commands/data to screen
+bool oled_send_cmd(const uint8_t *data, uint16_t size);
+bool oled_send_cmd_P(const uint8_t *data, uint16_t size);
+bool oled_send_data(const uint8_t *data, uint16_t size);
+
// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
void oled_clear(void);
@@ -386,7 +431,9 @@ uint8_t oled_max_chars(void);
uint8_t oled_max_lines(void);
```
-!> Scrolling and rotation are unsupported on the SH1106.
+!> Scrolling is unsupported on the SH1106 and SH1107.
+
+!> Scrolling does not work properly on the SSD1306 if the display width is smaller than 128.
## SSD1306.h Driver Conversion Guide
diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md
index 4da5d64a1a..909eff826d 100644
--- a/docs/feature_pointing_device.md
+++ b/docs/feature_pointing_device.md
@@ -197,6 +197,24 @@ The Pimoroni Trackball module is a I2C based breakout board with an RGB enable t
| `PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` |
| `PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` |
+### PMW3320 Sensor
+
+To use the PMW3320 sensor, add this to your `rules.mk`
+
+```make
+POINTING_DEVICE_DRIVER = pmw3320
+```
+
+The PMW3320 sensor uses a serial type protocol for communication, and requires an additional light source (it could work without one, but expect it to be out of service early).
+
+| Setting | Description | Default |
+| ------------------- | ------------------------------------------------------------------- | -------------------------- |
+| `PMW3320_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. | `POINTING_DEVICE_SCLK_PIN` |
+| `PMW3320_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. | `POINTING_DEVICE_SDIO_PIN` |
+| `PMW3320_CS_PIN` | (Required) The pin connected to the cable select pin of the sensor. | `POINTING_DEVICE_CS_PIN` |
+
+The CPI range is 500-3500, in increments of 250. Defaults to 1000 CPI.
+
### PMW 3360 and PMW 3389 Sensor
This drivers supports both the PMW 3360 and PMW 3389 sensor as well as multiple sensors of the same type _per_ controller, so 2 can be attached at the same side for split keyboards (or unsplit keyboards).
@@ -671,6 +689,10 @@ There are several functions that allow for more advanced interaction with the au
| `auto_mouse_layer_off(void)` | Disable target layer if appropriate will call (makes call to `layer_state_set`) | | `void`(None) |
| `auto_mouse_toggle(void)` | Toggle on/off target toggle state (disables layer deactivation when true) | | `void`(None) |
| `get_auto_mouse_toggle(void)` | Return value of toggling state variable | | `bool` |
+| `set_auto_mouse_timeout(uint16_t timeout)` | Change/set the timeout for turing off the layer | | `void`(None) |
+| `get_auto_mouse_timeout(void)` | Return the current timeout for turing off the layer | | `uint16_t` |
+| `set_auto_mouse_debounce(uint16_t timeout)` | Change/set the debounce for preventing layer activation | | `void`(None) |
+| `get_auto_mouse_debounce(void)` | Return the current debounce for preventing layer activation | | `uint8_t` |
_NOTES:_
- _Due to the nature of how some functions work, the `auto_mouse_trigger_reset`, and `auto_mouse_layer_off` functions should never be called in the `layer_state_set_*` stack as this can cause indefinite loops._
@@ -782,7 +804,7 @@ _Note: The Cirque pinnacle track pad already implements a custom activation func
When using a custom pointing device (overwriting `pointing_device_task`) the following code should be somewhere in the `pointing_device_task_*` stack:
```c
-void pointing_device_task(void) {
+bool pointing_device_task(void) {
//...Custom pointing device task code
// handle automatic mouse layer (needs report_mouse_t as input)
@@ -790,7 +812,7 @@ void pointing_device_task(void) {
//...More custom pointing device task code
- pointing_device_send();
+ return pointing_device_send();
}
```
diff --git a/docs/feature_repeat_key.md b/docs/feature_repeat_key.md
new file mode 100644
index 0000000000..6fa8a724ef
--- /dev/null
+++ b/docs/feature_repeat_key.md
@@ -0,0 +1,457 @@
+# Repeat Key
+
+The Repeat Key performs the action of the last pressed key. Tapping the Repeat
+Key after tapping the <kbd>Z</kbd> key types another "`z`." This is useful for
+typing doubled letters, like the `z` in "`dazzle`": a double tap on <kbd>Z</kbd>
+can instead be a roll from <kbd>Z</kbd> to <kbd>Repeat</kbd>, which is
+potentially faster and more comfortable. The Repeat Key is also useful for
+hotkeys, like repeating Ctrl + Shift + Right Arrow to select by word.
+
+Repeat Key remembers mods that were active with the last key press. These mods
+are combined with any additional mods while pressing the Repeat Key. If the last
+press key was <kbd>Ctrl</kbd> + <kbd>Z</kbd>, then <kbd>Shift</kbd> +
+<kbd>Repeat</kbd> performs Ctrl + Shift + `Z`.
+
+## How do I enable Repeat Key
+
+In your `rules.mk`, add:
+
+```make
+REPEAT_KEY_ENABLE = yes
+```
+
+Then pick a key in your keymap and assign it the keycode `QK_REPEAT_KEY` (short
+alias `QK_REP`). Optionally, use the keycode `QK_ALT_REPEAT_KEY` (short alias
+`QK_AREP`) on another key.
+
+## Keycodes
+
+|Keycode |Aliases |Description |
+|-----------------------|---------|-------------------------------------|
+|`QK_REPEAT_KEY` |`QK_REP` |Repeat the last pressed key |
+|`QK_ALT_REPEAT_KEY` |`QK_AREP`|Perform alternate of the last key |
+
+## Alternate Repeating
+
+The Alternate Repeat Key performs the "alternate" action of the last pressed key
+if it is defined. By default, Alternate Repeat is defined for navigation keys to
+act in the reverse direction. When the last key is the common "select by word"
+hotkey Ctrl + Shift + Right Arrow, the Alternate Repeat Key performs Ctrl +
+Shift + Left Arrow, which together with the Repeat Key enables convenient
+selection by words in either direction.
+
+Alternate Repeat is enabled with the Repeat Key by default. Optionally, to
+reduce firmware size, Alternate Repeat may be disabled by adding in config.h:
+
+```c
+#define NO_ALT_REPEAT_KEY
+```
+
+The following alternate keys are defined by default. See
+`get_alt_repeat_key_keycode_user()` below for how to change or add to these
+definitions. Where it makes sense, these definitions also include combinations
+with mods, like Ctrl + Left &harr; Ctrl + Right Arrow.
+
+**Navigation**
+
+|Keycodes |Description |
+|-----------------------------------|-----------------------------------|
+|`KC_LEFT` &harr; `KC_RGHT` | Left &harr; Right Arrow |
+|`KC_UP` &harr; `KC_DOWN` | Up &harr; Down Arrow |
+|`KC_HOME` &harr; `KC_END` | Home &harr; End |
+|`KC_PGUP` &harr; `KC_PGDN` | Page Up &harr; Page Down |
+|`KC_MS_L` &harr; `KC_MS_R` | Mouse Cursor Left &harr; Right |
+|`KC_MS_U` &harr; `KC_MS_D` | Mouse Cursor Up &harr; Down |
+|`KC_WH_L` &harr; `KC_WH_R` | Mouse Wheel Left &harr; Right |
+|`KC_WH_U` &harr; `KC_WH_D` | Mouse Wheel Up &harr; Down |
+
+**Misc**
+
+|Keycodes |Description |
+|-----------------------------------|-----------------------------------|
+|`KC_BSPC` &harr; `KC_DEL` | Backspace &harr; Delete |
+|`KC_LBRC` &harr; `KC_RBRC` | `[` &harr; `]` |
+|`KC_LCBR` &harr; `KC_RCBR` | `{` &harr; `}` |
+
+**Media**
+
+|Keycodes |Description |
+|-----------------------------------|-----------------------------------|
+|`KC_WBAK` &harr; `KC_WFWD` | Browser Back &harr; Forward |
+|`KC_MNXT` &harr; `KC_MPRV` | Next &harr; Previous Media Track |
+|`KC_MFFD` &harr; `KC_MRWD` | Fast Forward &harr; Rewind Media |
+|`KC_VOLU` &harr; `KC_VOLD` | Volume Up &harr; Down |
+|`KC_BRIU` &harr; `KC_BRID` | Brightness Up &harr; Down |
+
+**Hotkeys in Vim, Emacs, and other programs**
+
+|Keycodes |Description |
+|-----------------------------------|-----------------------------------|
+|mod + `KC_F` &harr; mod + `KC_B` | Forward &harr; Backward |
+|mod + `KC_D` &harr; mod + `KC_U` | Down &harr; Up |
+|mod + `KC_N` &harr; mod + `KC_P` | Next &harr; Previous |
+|mod + `KC_A` &harr; mod + `KC_E` | Home &harr; End |
+|mod + `KC_O` &harr; mod + `KC_I` | Vim jump list Older &harr; Newer |
+|`KC_J` &harr; `KC_K` | Down &harr; Up |
+|`KC_H` &harr; `KC_L` | Left &harr; Right |
+|`KC_W` &harr; `KC_B` | Forward &harr; Backward by Word |
+
+(where above, "mod" is Ctrl, Alt, or GUI)
+
+
+## Defining alternate keys
+
+Use the `get_alt_repeat_key_keycode_user()` callback to define the "alternate"
+for additional keys or override the default definitions. For example, to define
+Ctrl + Y as the alternate of Ctrl + Z, and vice versa, add the following in
+keymap.c:
+
+```c
+uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
+ if ((mods & MOD_MASK_CTRL)) { // Was Ctrl held?
+ switch (keycode) {
+ case KC_Y: return C(KC_Z); // Ctrl + Y reverses to Ctrl + Z.
+ case KC_Z: return C(KC_Y); // Ctrl + Z reverses to Ctrl + Y.
+ }
+ }
+
+ return KC_TRNS; // Defer to default definitions.
+}
+```
+
+The `keycode` and `mods` args are the keycode and mods that were active with the
+last pressed key. The meaning of the return value from this function is:
+
+* `KC_NO` &ndash; do nothing (any predefined alternate key is not used);
+* `KC_TRNS` &ndash; use the default alternate key if it exists;
+* anything else &ndash; use the specified keycode. Any keycode may be returned
+ as an alternate key, including custom keycodes.
+
+Another example, defining Shift + Tab as the alternate of Tab, and vice versa:
+
+```c
+uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
+ bool shifted = (mods & MOD_MASK_SHIFT); // Was Shift held?
+ switch (keycode) {
+ case KC_TAB:
+ if (shifted) { // If the last key was Shift + Tab,
+ return KC_TAB; // ... the reverse is Tab.
+ } else { // Otherwise, the last key was Tab,
+ return S(KC_TAB); // ... and the reverse is Shift + Tab.
+ }
+ }
+
+ return KC_TRNS;
+}
+```
+
+#### Eliminating SFBs
+
+Alternate Repeat can be configured more generally to perform an action that
+"complements" the last key. Alternate Repeat is not limited to reverse
+repeating, and it need not be symmetric. You can use it to eliminate cases of
+same-finger bigrams in your layout, that is, pairs of letters typed by the same
+finger. The following addresses the top 5 same-finger bigrams in English on
+QWERTY, so that for instance "`ed`" may be typed as <kbd>E</kbd>, <kbd>Alt
+Repeat</kbd>.
+
+```c
+uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
+ switch (keycode) {
+ case KC_E: return KC_D; // For "ED" bigram.
+ case KC_D: return KC_E; // For "DE" bigram.
+ case KC_C: return KC_E; // For "CE" bigram.
+ case KC_L: return KC_O; // For "LO" bigram.
+ case KC_U: return KC_N; // For "UN" bigram.
+ }
+
+ return KC_TRNS;
+}
+```
+
+#### Typing shortcuts
+
+A useful possibility is having Alternate Repeat press [a
+macro](feature_macros.md). This way macros can be used without having to
+dedicate keys to them. The following defines a couple shortcuts.
+
+* Typing <kbd>K</kbd>, <kbd>Alt Repeat</kbd> produces "`keyboard`," with the
+ initial "`k`" typed as usual and the "`eybord`" produced by the macro.
+* Typing <kbd>.</kbd>, <kbd>Alt Repeat</kbd> produces "`../`," handy for "up
+ directory" on the shell. Similary, <kbd>.</kbd> types the initial "`.`" and
+ "`./`" is produced by the macro.
+
+```c
+enum custom_keycodes {
+ M_KEYBOARD = SAFE_RANGE,
+ M_UPDIR,
+ // Other custom keys...
+};
+
+uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
+ switch (keycode) {
+ case KC_K: return M_KEYBOARD;
+ case KC_DOT: return M_UPDIR;
+ }
+
+ return KC_TRNS;
+}
+
+bool process_record_user(uint16_t keycode, keyrecord_t* record) {
+ switch (keycode) {
+ case M_KEYBOARD: SEND_STRING(/*k*/"eyboard"); break;
+ case M_UPDIR: SEND_STRING(/*.*/"./"); break;
+ }
+ return true;
+}
+```
+
+## Ignoring certain keys and mods
+
+In tracking what is "the last key" to be repeated or alternate repeated,
+modifier and layer switch keys are always ignored. This makes it possible to set
+some mods and change layers between pressing a key and repeating it. By default,
+all other (non-modifier, non-layer switch) keys are remembered so that they are
+eligible for repeating. To configure additional keys to be ignored, define
+`remember_last_key_user()` in your keymap.c.
+
+#### Ignoring a key
+
+The following ignores the Backspace key:
+
+```c
+bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
+ uint8_t* remembered_mods) {
+ switch (keycode) {
+ case KC_BSPC:
+ return false; // Ignore backspace.
+ }
+
+ return true; // Other keys can be repeated.
+}
+```
+
+Then for instance, the Repeat key in <kbd>Left Arrow</kbd>,
+<kbd>Backspace</kbd>, <kbd>Repeat</kbd> sends Left Arrow again instead of
+repeating Backspace.
+
+The `remember_last_key_user()` callback is called on every key press excluding
+modifiers and layer switches. Returning true indicates the key is remembered,
+while false means it is ignored.
+
+#### Filtering remembered mods
+
+The `remembered_mods` arg represents the mods that will be remembered with
+this key. It can be modified to forget certain mods. This may be
+useful to forget capitalization when repeating shifted letters, so that "Aaron"
+does not becom "AAron":
+
+```c
+bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
+ uint8_t* remembered_mods) {
+ // Forget Shift on letter keys when Shift or AltGr are the only mods.
+ switch (keycode) {
+ case KC_A ... KC_Z:
+ if ((*remembered_mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_RALT))) == 0) {
+ *remembered_mods &= ~MOD_MASK_SHIFT;
+ }
+ break;
+ }
+
+ return true;
+}
+```
+
+#### Further conditions
+
+Besides checking the keycode, this callback could also make conditions based on
+the current layer state (with `IS_LAYER_ON(layer)`) or mods (`get_mods()`). For
+example, the following ignores keys on layer 2 as well as key combinations
+involving GUI:
+
+```c
+bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
+ uint8_t* remembered_mods) {
+ if (IS_LAYER_ON(2) || (get_mods() & MOD_MASK_GUI)) {
+ return false; // Ignore layer 2 keys and GUI chords.
+ }
+
+ return true; // Other keys can be repeated.
+}
+```
+
+?> See [Layer Functions](feature_layers.md#functions) and [Checking Modifier
+State](feature_advanced_keycodes.md#checking-modifier-state) for further
+details.
+
+
+## Handle how a key is repeated
+
+By default, pressing the Repeat Key will simply behave as if the last key
+were pressed again. This also works with macro keys with custom handlers,
+invoking the macro again. In case fine-tuning is needed for sensible repetition,
+you can handle how a key is repeated with `get_repeat_key_count()` within
+`process_record_user()`.
+
+The `get_repeat_key_count()` function returns a signed count of times the key
+has been repeated or alternate repeated. When a key is pressed as usual,
+`get_repeat_key_count()` is 0. On the first repeat, it is 1, then the second
+repeat, 2, and so on. Negative counts are used similarly for alternate
+repeating. For instance supposing `MY_MACRO` is a custom keycode used in the
+layout:
+
+```c
+bool process_record_user(uint16_t keycode, keyrecord_t* record) {
+ switch (keycode) {
+ case MY_MACRO:
+ if (get_repeat_key_count() > 0) {
+ // MY_MACRO is being repeated!
+ if (record->event.pressed) {
+ SEND_STRING("repeat!");
+ }
+ } else {
+ // MY_MACRO is being used normally.
+ if (record->event.pressed) {
+ SEND_STRING("macro");
+ }
+ }
+ return false;
+
+ // Other macros...
+ }
+ return true;
+}
+```
+
+## Handle how a key is alternate repeated
+
+Pressing the Alternate Repeat Key behaves as if the "alternate" of the last
+pressed key were pressed, if an alternate is defined. To define how a particular
+key is alternate repeated, use the `get_alt_repeat_key_keycode_user()` callback
+as described above to define which keycode to use as its alternate. Beyond this,
+`get_repeat_key_count()` may be used in custom handlers to fine-tune behavior
+when alternate repeating.
+
+The following example defines `MY_MACRO` as its own alternate, and specially
+handles repeating and alternate repeating:
+
+```c
+uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
+ switch (keycode) {
+ case MY_MACRO: return MY_MACRO; // MY_MACRO is its own alternate.
+ }
+ return KC_TRNS;
+}
+
+bool process_record_user(uint16_t keycode, keyrecord_t* record) {
+ switch (keycode) {
+ case MY_MACRO:
+ if (get_repeat_key_count() > 0) { // Repeating.
+ if (record->event.pressed) {
+ SEND_STRING("repeat!");
+ }
+ } else if (get_repeat_key_count() < 0) { // Alternate repeating.
+ if (record->event.pressed) {
+ SEND_STRING("alt repeat!");
+ }
+ } else { // Used normally.
+ if (record->event.pressed) {
+ SEND_STRING("macro");
+ }
+ }
+ return false;
+
+ // Other macros...
+ }
+ return true;
+}
+```
+
+
+## Functions
+
+| Function | Description |
+|--------------------------------|------------------------------------------------------------------------|
+| `get_last_keycode()` | The last key's keycode, the key to be repeated. |
+| `get_last_mods()` | Mods to apply when repeating. |
+| `set_last_keycode(kc)` | Set the keycode to be repeated. |
+| `set_last_mods(mods)` | Set the mods to apply when repeating. |
+| `get_repeat_key_count()` | Signed count of times the key has been repeated or alternate repeated. |
+| `get_alt_repeat_key_keycode()` | Keycode to be used for alternate repeating. |
+
+
+## Additional "Alternate" keys
+
+By leveraging `get_last_keycode()` in macros, it is possible to define
+additional, distinct "Alternate Repeat"-like keys. The following defines two
+keys `ALTREP2` and `ALTREP3` and implements ten shortcuts with them for common
+English 5-gram letter patterns, taking inspiration from
+[Stenotype](feature_stenography.md):
+
+
+| Typing | Produces | Typing | Produces |
+|----------------------------------|----------|----------------------------------|----------|
+| <kbd>A</kbd>, <kbd>ALTREP2</kbd> | `ation` | <kbd>A</kbd>, <kbd>ALTREP3</kbd> | `about` |
+| <kbd>I</kbd>, <kbd>ALTREP2</kbd> | `ition` | <kbd>I</kbd>, <kbd>ALTREP3</kbd> | `inter` |
+| <kbd>S</kbd>, <kbd>ALTREP2</kbd> | `ssion` | <kbd>S</kbd>, <kbd>ALTREP3</kbd> | `state` |
+| <kbd>T</kbd>, <kbd>ALTREP2</kbd> | `their` | <kbd>T</kbd>, <kbd>ALTREP3</kbd> | `there` |
+| <kbd>W</kbd>, <kbd>ALTREP2</kbd> | `which` | <kbd>W</kbd>, <kbd>ALTREP3</kbd> | `would` |
+
+```c
+enum custom_keycodes {
+ ALTREP2 = SAFE_RANGE,
+ ALTREP3,
+};
+
+// Use ALTREP2 and ALTREP3 in your layout...
+
+bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
+ uint8_t* remembered_mods) {
+ switch (keycode) {
+ case ALTREP2:
+ case ALTREP3:
+ return false; // Ignore ALTREP keys.
+ }
+
+ return true; // Other keys can be repeated.
+}
+
+static void process_altrep2(uint16_t keycode, uint8_t mods) {
+ switch (keycode) {
+ case KC_A: SEND_STRING(/*a*/"tion"); break;
+ case KC_I: SEND_STRING(/*i*/"tion"); break;
+ case KC_S: SEND_STRING(/*s*/"sion"); break;
+ case KC_T: SEND_STRING(/*t*/"heir"); break;
+ case KC_W: SEND_STRING(/*w*/"hich"); break;
+ }
+}
+
+static void process_altrep3(uint16_t keycode, uint8_t mods) {
+ switch (keycode) {
+ case KC_A: SEND_STRING(/*a*/"bout"); break;
+ case KC_I: SEND_STRING(/*i*/"nter"); break;
+ case KC_S: SEND_STRING(/*s*/"tate"); break;
+ case KC_T: SEND_STRING(/*t*/"here"); break;
+ case KC_W: SEND_STRING(/*w*/"ould"); break;
+ }
+}
+
+bool process_record_user(uint16_t keycode, keyrecord_t* record) {
+ switch (keycode) {
+ case ALTREP2:
+ if (record->event.pressed) {
+ process_altrep2(get_last_keycode(), get_last_mods());
+ }
+ return false;
+
+ case ALTREP3:
+ if (record->event.pressed) {
+ process_altrep3(get_last_keycode(), get_last_mods());
+ }
+ return false;
+ }
+
+ return true;
+}
+```
+
diff --git a/docs/feature_rgb_matrix.md b/docs/feature_rgb_matrix.md
index 20ad4c7faf..75f07b5e64 100644
--- a/docs/feature_rgb_matrix.md
+++ b/docs/feature_rgb_matrix.md
@@ -156,6 +156,82 @@ const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT] = {
Where `X_Y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3733.pdf) and the header file `drivers/led/issi/is31fl3733.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` for now).
---
+### IS31FL3736 :id=is31fl3736
+
+There is basic support for addressable RGB matrix lighting with the I2C IS31FL3736 RGB controller. To enable it, add this to your `rules.mk`:
+
+```make
+RGB_MATRIX_ENABLE = yes
+RGB_MATRIX_DRIVER = IS31FL3736
+```
+You can use between 1 and 4 IS31FL3736 IC's. Do not specify `DRIVER_ADDR_<N>` defines for IC's that are not present on your keyboard.
+
+Configure the hardware via your `config.h`:
+
+| Variable | Description | Default |
+|----------|-------------|---------|
+| `ISSI_TIMEOUT` | (Optional) How long to wait for i2c messages, in milliseconds | 100 |
+| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 |
+| `ISSI_PWM_FREQUENCY` | (Optional) PWM Frequency Setting - IS31FL3736B only | 0 |
+| `ISSI_GLOBALCURRENT` | (Optional) Configuration for the Global Current Register | 0xFF |
+| `ISSI_SWPULLUP` | (Optional) Set the value of the SWx lines on-chip de-ghosting resistors | PUR_0R (Disabled) |
+| `ISSI_CSPULLUP` | (Optional) Set the value of the CSx lines on-chip de-ghosting resistors | PUR_0R (Disabled) |
+| `DRIVER_COUNT` | (Required) How many RGB driver IC's are present | |
+| `RGB_MATRIX_LED_COUNT` | (Required) How many RGB lights are present across all drivers | |
+| `DRIVER_ADDR_1` | (Required) Address for the first RGB driver | |
+| `DRIVER_ADDR_2` | (Optional) Address for the second RGB driver | |
+| `DRIVER_ADDR_3` | (Optional) Address for the third RGB driver | |
+| `DRIVER_ADDR_4` | (Optional) Address for the fourth RGB driver | |
+
+The IS31FL3736 IC's have on-chip resistors that can be enabled to allow for de-ghosting of the RGB matrix. By default these resistors are not enabled (`ISSI_SWPULLUP`/`ISSI_CSPULLUP` are given the value of`PUR_0R`), the values that can be set to enable de-ghosting are as follows:
+
+| `ISSI_SWPULLUP/ISSI_CSPULLUP` | Description |
+|----------------------|-------------|
+| `PUR_0R` | (default) Do not use the on-chip resistors/enable de-ghosting |
+| `PUR_05KR` | The 0.5k Ohm resistor used during blanking period (t_NOL) |
+| `PUR_1KR` | The 1k Ohm resistor used during blanking period (t_NOL) |
+| `PUR_2KR` | The 2k Ohm resistor used during blanking period (t_NOL) |
+| `PUR_4KR` | The 4k Ohm resistor used during blanking period (t_NOL) |
+| `PUR_8KR` | The 8k Ohm resistor during blanking period (t_NOL) |
+| `PUR_16KR` | The 16k Ohm resistor during blanking period (t_NOL) |
+| `PUR_32KR` | The 32k Ohm resistor used during blanking period (t_NOL) |
+
+Here is an example using 2 drivers.
+
+```c
+// This is a 7-bit address, that gets left-shifted and bit 0
+// set to 0 for write, 1 for read (as per I2C protocol)
+// The address will vary depending on your wiring:
+// 0000 <-> GND
+// 0101 <-> SCL
+// 1010 <-> SDA
+// 1111 <-> VCC
+// ADDR represents A3:A0 of the 7-bit address.
+// The result is: 0b101(ADDR)
+#define DRIVER_ADDR_1 0b1010000
+#define DRIVER_ADDR_2 0b1010001
+
+#define DRIVER_COUNT 2
+#define DRIVER_1_LED_TOTAL 30
+#define DRIVER_2_LED_TOTAL 32
+#define RGB_MATRIX_LED_COUNT (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+```
+!> Note the parentheses, this is so when `RGB_MATRIX_LED_COUNT` is used in code and expanded, the values are added together before any additional math is applied to them. As an example, `rand() % (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)` will give very different results than `rand() % DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL`.
+
+Define these arrays listing all the LEDs in your `<keyboard>.c`:
+
+```c
+const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT] = {
+/* Refer to IS31 manual for these locations
+ * driver
+ * | R location
+ * | | G location
+ * | | | B location
+ * | | | | */
+ {0, B_1, A_1, C_1},
+ ....
+}
+```
### IS31FL3737 :id=is31fl3737
There is basic support for addressable RGB matrix lighting with the I2C IS31FL3737 RGB controller. To enable it, add this to your `rules.mk`:
@@ -218,8 +294,6 @@ Here is an example using 2 drivers.
```
!> Note the parentheses, this is so when `RGB_MATRIX_LED_COUNT` is used in code and expanded, the values are added together before any additional math is applied to them. As an example, `rand() % (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)` will give very different results than `rand() % DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL`.
-Currently only 2 drivers are supported, but it would be trivial to support all 4 combinations.
-
Define these arrays listing all the LEDs in your `<keyboard>.c`:
```c
@@ -361,7 +435,7 @@ Configure the hardware via your `config.h`:
```c
// The pin connected to the data pin of the LEDs
-#define RGB_DI_PIN D7
+#define WS2812_DI_PIN D7
// The number of LEDs connected
#define RGB_MATRIX_LED_COUNT 70
```
@@ -383,9 +457,9 @@ Configure the hardware via your `config.h`:
```c
// The pin connected to the data pin of the LEDs
-#define RGB_DI_PIN D7
+#define APA102_DI_PIN D7
// The pin connected to the clock pin of the LEDs
-#define RGB_CI_PIN D6
+#define APA102_CI_PIN D6
// The number of LEDs connected
#define RGB_MATRIX_LED_COUNT 70
```
@@ -690,6 +764,14 @@ Remove the spread effect entirely.
#define RGB_MATRIX_TYPING_HEATMAP_SLIM
```
+It's also possible to adjust the tempo of *heating up*. It's defined as the number of shades that are
+increased on the [HSV scale](https://en.wikipedia.org/wiki/HSL_and_HSV). Decreasing this value increases
+the number of keystrokes needed to fully heat up the key.
+
+```c
+#define RGB_MATRIX_TYPING_HEATMAP_INCREASE_STEP 32
+```
+
### RGB Matrix Effect Solid Reactive :id=rgb-matrix-effect-solid-reactive
Solid reactive effects will pulse RGB light on key presses with user configurable hues. To enable gradient mode that will automatically change reactive color, add the following define:
@@ -811,13 +893,7 @@ These are defined in [`color.h`](https://github.com/qmk/qmk_firmware/blob/master
## EEPROM storage :id=eeprom-storage
-The EEPROM for it is currently shared with the LED Matrix system (it's generally assumed only one feature would be used at a time), but could be configured to use its own 32bit address with:
-
-```c
-#define EECONFIG_RGB_MATRIX (uint32_t *)28
-```
-
-Where `28` is an unused index from `eeconfig.h`.
+The EEPROM for it is currently shared with the LED Matrix system (it's generally assumed only one feature would be used at a time).
## Functions :id=functions
diff --git a/docs/feature_rgblight.md b/docs/feature_rgblight.md
index 060efaf1b3..5131658ae1 100644
--- a/docs/feature_rgblight.md
+++ b/docs/feature_rgblight.md
@@ -33,12 +33,13 @@ RGBLIGHT_DRIVER = APA102
At minimum you must define the data pin your LED strip is connected to, and the number of LEDs in the strip, in your `config.h`. For APA102 LEDs, you must also define the clock pin. If your keyboard has onboard RGB LEDs, and you are simply creating a keymap, you usually won't need to modify these.
-|Define |Description |
-|---------------|---------------------------------------------------------------------------------------------------------|
-|`RGB_DI_PIN` |The pin connected to the data pin of the LEDs |
-|`RGB_CI_PIN` |The pin connected to the clock pin of the LEDs (APA102 only) |
-|`RGBLED_NUM` |The number of LEDs connected |
-|`RGBLED_SPLIT` |(Optional) For split keyboards, the number of LEDs connected on each half directly wired to `RGB_DI_PIN` |
+|Define |Description |
+|---------------|-------------------------------------------------------------------------|
+|`WS2812_DI_PIN`|The pin connected to the data pin of the LEDs (WS2812) |
+|`APA102_DI_PIN`|The pin connected to the data pin of the LEDs (APA102) |
+|`APA102_CI_PIN`|The pin connected to the clock pin of the LEDs (APA102) |
+|`RGBLED_NUM` |The number of LEDs connected |
+|`RGBLED_SPLIT` |(Optional) For split keyboards, the number of LEDs connected on each half|
Then you should be able to use the keycodes below to change the RGB lighting to your liking.
diff --git a/docs/feature_split_keyboard.md b/docs/feature_split_keyboard.md
index c095c8712f..1705ea9222 100644
--- a/docs/feature_split_keyboard.md
+++ b/docs/feature_split_keyboard.md
@@ -300,6 +300,12 @@ This enables transmitting the pointing device status to the master side of the s
This enables triggering of haptic feedback on the slave side of the split keyboard. For DRV2605L this will send the mode, but for solenoids it is expected that the desired mode is already set up on the slave.
+```c
+#define SPLIT_ACTIVITY_ENABLE
+```
+
+This synchronizes the activity timestamps between sides of the split keyboard, allowing for activity timeouts to occur.
+
### Custom data sync between sides :id=custom-data-sync
QMK's split transport allows for arbitrary data transactions at both the keyboard and user levels. This is modelled on a remote procedure call, with the master invoking a function on the slave side, with the ability to send data from master to slave, process it slave side, and send data back from slave to master.
diff --git a/docs/feature_stenography.md b/docs/feature_stenography.md
index 62d4dabf81..df4c9c6ad3 100644
--- a/docs/feature_stenography.md
+++ b/docs/feature_stenography.md
@@ -138,7 +138,7 @@ bool post_process_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t
This function is called after a key has been processed, but before any decision about whether or not to send a chord. This is where to put hooks for things like, say, live displays of steno chords or keys.
-If `IS_PRESSED(record->event)` is false, and `n_pressed_keys` is 0 or 1, the chord will be sent shortly, but has not yet been sent. This relieves you of the need of keeping track of where a packet ends and another begins.
+If `record->event.pressed` is false, and `n_pressed_keys` is 0 or 1, the chord will be sent shortly, but has not yet been sent. This relieves you of the need of keeping track of where a packet ends and another begins.
The `chord` argument contains the packet of the current chord as specified by the protocol in use. This is *NOT* simply a list of chorded steno keys of the form `[STN_E, STN_U, STN_BR, STN_GR]`. Refer to the appropriate protocol section of this document to learn more about the format of the packets in your steno protocol/mode of choice.
diff --git a/docs/feature_swap_hands.md b/docs/feature_swap_hands.md
index 4d0d554093..e9c1d4b7ba 100644
--- a/docs/feature_swap_hands.md
+++ b/docs/feature_swap_hands.md
@@ -47,6 +47,11 @@ const uint8_t PROGMEM encoder_hand_swap_config[NUM_ENCODERS] = { 1, 0 };
### Functions :id=functions
-| Function | Description |
-|----------------------|---------------------------------------------|
-| `is_swap_hands_on()` | Returns true if Swap-Hands is currently on. |
+User callback functions to manipulate Swap-Hands:
+
+| Function | Description |
+|-----------------------|---------------------------------------------|
+| `swap_hands_on()` | Turns Swap-Hands on. |
+| `swap_hands_off()` | Turns Swap-Hands off. |
+| `swap_hands_toggle()` | Toggles Swap-Hands. |
+| `is_swap_hands_on()` | Returns true if Swap-Hands is currently on. |
diff --git a/docs/getting_started_vagrant.md b/docs/getting_started_vagrant.md
deleted file mode 100644
index b5b5ce1539..0000000000
--- a/docs/getting_started_vagrant.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# Vagrant Quick Start
-
-This project includes a `Vagrantfile` that will allow you to build a new firmware for your keyboard very easily without major changes to your primary operating system. This also ensures that when you clone the project and perform a build, you have the exact same environment as anyone else using the Vagrantfile to build. This makes it much easier for people to help you troubleshoot any issues you encounter.
-
-## Requirements
-
-Using the `Vagrantfile` in this repository requires you have [Vagrant](https://www.vagrantup.com/) as well as a supported provider installed:
-
-* [VirtualBox](https://www.virtualbox.org/) (Version at least 5.0.12)
- * Sold as 'the most accessible platform to use Vagrant'
-* [VMware Workstation](https://www.vmware.com/products/workstation) and [Vagrant VMware plugin](https://www.vagrantup.com/vmware)
- * The (paid) VMware plugin requires a licensed copy of VMware Workstation/Fusion
-* [Docker](https://www.docker.com/)
-
-Other than having Vagrant, a suitable provider installed and possibly a restart of your computer afterwards, you can simple run a 'vagrant up' anywhere inside the folder where you checked out this project and it will start an environment (either a virtual machine or container) that contains all the tools required to build this project. There is a post Vagrant startup hint that will get you off on the right foot, otherwise you can also reference the build documentation below.
-
-## Flashing the Firmware
-
-The "easy" way to flash the firmware is using a tool from your host OS:
-
-* [QMK Toolbox](https://github.com/qmk/qmk_toolbox) (recommended)
-* [Teensy Loader](https://www.pjrc.com/teensy/loader.html)
-
-If you want to program via the command line you can uncomment the ['modifyvm'] lines in the Vagrantfile to enable the USB passthrough into Linux and then program using the command line tools like dfu-util/dfu-programmer or you can install the Teensy CLI version.
-
-## Vagrantfile Overview
-The development environment is configured to run the QMK Docker image, `qmkfm/qmk_cli`. This not only ensures predictability between systems, it also mirrors the CI environment.
-
-## FAQ
-
-### Why am I seeing issues under Virtualbox?
-Certain versions of Virtualbox 5 appear to have an incompatibility with the Virtualbox extensions installed in the boxes in this Vagrantfile. If you encounter any issues with the /vagrant mount not succeeding, please upgrade your version of Virtualbox to at least 5.0.12. **Alternately, you can try running the following command:**
-
-```
-vagrant plugin install vagrant-vbguest
-```
-
-### How do I remove an existing environment?
-Finished with your environment? From anywhere inside the folder where you checked out this project, Execute:
-
-```
-vagrant destroy
-```
-
-### What if I want to use Docker directly?
-Want to benefit from the Vagrant workflow without a virtual machine? The Vagrantfile is configured to bypass running a virtual machine, and run the container directly. Execute the following when bringing up the environment to force the use of Docker:
-```
-vagrant up --provider=docker
-```
-
-### How do I access the virtual machine instead of the Docker container?
-Execute the following to bypass the `vagrant` user booting directly to the official qmk builder image:
-
-```
-vagrant ssh -c 'sudo -i'
-```
diff --git a/docs/ja/_summary.md b/docs/ja/_summary.md
index 8516a5eaaa..4d6f2348d5 100644
--- a/docs/ja/_summary.md
+++ b/docs/ja/_summary.md
@@ -38,7 +38,6 @@
* [キーマップの概要](ja/keymap.md)
* 開発環境
* [Docker のガイド](ja/getting_started_docker.md)
- * [Vagrant のガイド](ja/getting_started_vagrant.md)
* 書き込み
* [書き込み](ja/flashing.md)
* [ATmega32A の書き込み (ps2avrgb)](ja/flashing_bootloadhid.md)
@@ -69,6 +68,7 @@
* [モッドタップ](ja/mod_tap.md)
* [マクロ](ja/feature_macros.md)
* [マウスキー](ja/feature_mouse_keys.md)
+ * [Repeat Key](ja/feature_repeat_key.md)
* [Space Cadet Shift](ja/feature_space_cadet.md)
* [US ANSI シフトキー](ja/keycodes_us_ansi_shifted.md)
diff --git a/docs/ja/config_options.md b/docs/ja/config_options.md
index 6135721a42..5e98da5eee 100644
--- a/docs/ja/config_options.md
+++ b/docs/ja/config_options.md
@@ -159,9 +159,6 @@ QMK での全ての利用可能な設定にはデフォルトがあります。
* 詳細は [Permissive Hold](ja/tap_hold.md#permissive-hold) を見てください
* `#define PERMISSIVE_HOLD_PER_KEY`
* キーごとの `PERMISSIVE_HOLD` 設定の処理を有効にします
-* `#define IGNORE_MOD_TAP_INTERRUPT`
- * 両方のキーに `TAPPING_TERM` を適用することで、ホールド時に他のキーに変換するキーを使ってローリングコンボ (zx) をすることができるようにします
- * 詳細は [Ignore Mod Tap Interrupt](ja/tap_hold.md#ignore-mod-tap-interrupt) を見てください
* `#define TAPPING_FORCE_HOLD`
* タップされた直後に、デュアルロールキーを修飾子として使用できるようにします
* [Tapping Force Hold](ja/tap_hold.md#tapping-force-hold)を見てください
@@ -179,8 +176,6 @@ QMK での全ての利用可能な設定にはデフォルトがあります。
* ワンショットがタイムアウトするまでの時間
* `#define ONESHOT_TAP_TOGGLE 2`
* ワンショットトグルが引き起こされるまでのタップ数
-* `#define COMBO_COUNT 2`
- * [コンボ](ja/feature_combo.md)機能で使っているコンボの数にこれを設定します。
* `#define COMBO_TERM 200`
* コンボキーが検出されるまでの時間。定義されていない場合は、デフォルトは `TAPPING_TERM` です。
* `#define TAP_CODE_DELAY 100`
diff --git a/docs/ja/feature_combo.md b/docs/ja/feature_combo.md
index bd46e88b7f..0c0591e5f7 100644
--- a/docs/ja/feature_combo.md
+++ b/docs/ja/feature_combo.md
@@ -18,7 +18,7 @@
```c
const uint16_t PROGMEM test_combo[] = {KC_A, KC_B, COMBO_END};
-combo_t key_combos[COMBO_COUNT] = {COMBO(test_combo, KC_ESC)};
+combo_t key_combos[] = {COMBO(test_combo, KC_ESC)};
```
これは、A と B のキーを押した場合に、"Escape" を送信します。
@@ -38,7 +38,7 @@ enum combos {
const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM jk_combo[] = {KC_J, KC_K, COMBO_END};
-combo_t key_combos[COMBO_COUNT] = {
+combo_t key_combos[] = {
[AB_ESC] = COMBO(ab_combo, KC_ESC),
[JK_TAB] = COMBO(jk_combo, KC_TAB)
};
@@ -55,7 +55,7 @@ enum combo_events {
const uint16_t PROGMEM copy_combo[] = {KC_Z, KC_C, COMBO_END};
const uint16_t PROGMEM paste_combo[] = {KC_X, KC_V, COMBO_END};
-combo_t key_combos[COMBO_COUNT] = {
+combo_t key_combos[] = {
[ZC_COPY] = COMBO_ACTION(copy_combo),
[XV_PASTE] = COMBO_ACTION(paste_combo),
};
diff --git a/docs/ja/feature_dynamic_macros.md b/docs/ja/feature_dynamic_macros.md
index 3cff788007..fa1a1df931 100644
--- a/docs/ja/feature_dynamic_macros.md
+++ b/docs/ja/feature_dynamic_macros.md
@@ -64,7 +64,7 @@ QMK はその場で作られた一時的なマクロをサポートします。
direction がどのマクロであるかを示すことに注意してください。`1` がマクロ 1、`-1` がマクロ 2、0 がマクロ無しです。
-* `dynamic_macro_record_start_user(void)` - マクロの記録を開始する時に起動されます。
+* `dynamic_macro_record_start_user(int8_t direction)` - マクロの記録を開始する時に起動されます。
* `dynamic_macro_play_user(int8_t direction)` - マクロを再生する時に起動されます。
* `dynamic_macro_record_key_user(int8_t direction, keyrecord_t *record)` - マクロの記録中に各キー押下で起動されます。
* `dynamic_macro_record_end_user(int8_t direction)` - マクロの記録を停止した時に起動されます。
diff --git a/docs/ja/feature_stenography.md b/docs/ja/feature_stenography.md
index b280084ae3..9551221696 100644
--- a/docs/ja/feature_stenography.md
+++ b/docs/ja/feature_stenography.md
@@ -80,7 +80,7 @@ bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; }
bool post_process_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed);
```
-この関数はキーが処理された後、ただしコードを送信するかどうかを決める前に呼び出されます。`IS_PRESSED(record->event)` が false で、`pressed` が 0 または 1 の場合は、コードはまもなく送信されますが、まだ送信されてはいません。ここが速記コードあるいはキーのライブ表示などのフックを配置する場所です。
+この関数はキーが処理された後、ただしコードを送信するかどうかを決める前に呼び出されます。`record->event.pressed` が false で、`pressed` が 0 または 1 の場合は、コードはまもなく送信されますが、まだ送信されてはいません。ここが速記コードあるいはキーのライブ表示などのフックを配置する場所です。
## キーコードリファレンス :id=keycode-reference
diff --git a/docs/ja/getting_started_vagrant.md b/docs/ja/getting_started_vagrant.md
deleted file mode 100644
index 0888b7f311..0000000000
--- a/docs/ja/getting_started_vagrant.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Vagrant クイックスタート
-
-<!---
- original document: 0.12.43:docs/getting_started_vagrant.md
- git diff 0.12.43 HEAD -- docs/getting_started_vagrant.md | cat
--->
-
-このプロジェクトは、プライマリオペレーティングシステムに大きな変更を加えることなくキーボードの新しいファームウェアを非常に簡単に構築することができる `Vagrantfile` を含みます。これは、あなたがプロジェクトをクローンしビルドを実行した時に、ビルドのために Vagrantfile を使っている他のユーザと全く同じ環境を持つことも保証します。これにより、人々はあなたが遭遇した問題の解決をより簡単に行えるようになります。
-
-## 必要事項
-
-このリポジトリ内の `Vagrantfile` を使うには、[Vagrant](https://www.vagrantup.com/) およびサポートされるプロバイダがインストールされている必要があります:
-
-* [VirtualBox](https://www.virtualbox.org/) (バージョン 5.0.12 以降)
- * 「Vagrant を使うために最もアクセスしやすいプラットフォーム」とうたわれています。
-* [VMware Workstation](https://www.vmware.com/products/workstation) および [Vagrant VMware プラグイン](https://www.vagrantup.com/vmware)
- * (有料) VMware プラグインには、ライセンスされた VMware Workstation/Fusion のコピーが必要です。
-* [Docker](https://www.docker.com/)
-
-Vagrant 以外に、適切なプロバイダがインストールされ、その後におそらくコンピュータを再起動すると、このプロジェクトをチェックアウトしたフォルダ内の任意の場所で 'vagrant up' を単純に実行することができ、このプロジェクトをビルドするのに必要な全てのツールが含まれる環境(仮想マシンあるいはコンテナ)が開始されます。Vagrant 起動時にうまく始めるためのヒントが表示されますが、それ以外に、以下のビルドドキュメントを参照することもできます。
-
-## ファームウェアの書き込み
-
-ファームウェアを書き込む「簡単な」方法は、ホスト OS からツールを使うことです:
-
-* [QMK Toolbox](https://github.com/qmk/qmk_toolbox) (推奨)
-* [Teensy ローダー](https://www.pjrc.com/teensy/loader.html)
-
-コマンドラインでプログラムしたい場合は、Vagranfile の ['modifyvm'] 行のコメントを解除して Linux への USB パススルーを有効にし、dfu-util/dfu-programmer のようなコマンドラインツールを使ってプログラムすることができます。あるいは Teensy CLI バージョンをインストールすることができます。
-
-## Vagrantfile の概要
-開発環境は QMK Docker イメージ、`qmkfm/qmk_cli` を実行するように設定されています。これはシステム間の予測可能性が保証されるだけでなく、CI 環境もミラーされます。
-
-## FAQ
-
-### Virtualbox で問題が発生するのはなぜですか?
-Virtualbox 5 の特定のバージョンはこの Vagrantfile のボックスにインストールされている Virtualbox の拡張機能と互換性が無いようです。/vagrant のマウントで問題が発生した場合は、Virtualbox のバージョンを少なくとも 5.0.12 にアップグレードしてください。**または、以下のコマンドを実行してみることができます:**
-
-```console
-vagrant plugin install vagrant-vbguest
-```
-
-### 既存の環境を削除するにはどうすればいいですか?
-あなたの環境での作業が完了しましたか?このプロジェクトをチェックアウトしたフォルダの中のどこからでも、以下を実行してください:
-
-```console
-vagrant destroy
-```
-
-### Docker を直接使いたい場合はどうしますか?
-仮想マシン無しで Vagrant のワークフローを活用したいですか?Vagrantfile は仮想マシンの実行をバイパスし、コンテナを直接実行するように設定されています。Docker を強制的に使うように環境を立ち上げる場合は、以下を実行してください:
-```console
-vagrant up --provider=docker
-```
-
-### Docker コンテナではなく仮想マシンにアクセスするにはどうすればいいですか?
-以下を実行して、公式の QMK ビルダーイメージから直接起動する `vagrant` ユーザをバイパスするようにします:
-
-```console
-vagrant ssh -c 'sudo -i'
-```
diff --git a/docs/ja/tap_hold.md b/docs/ja/tap_hold.md
index ac64fe6ce3..00b80c8b22 100644
--- a/docs/ja/tap_hold.md
+++ b/docs/ja/tap_hold.md
@@ -63,8 +63,6 @@ uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
通常、これら全てを `TAPPING_TERM` (デフォルト: 200ms) 内で行うと、ファームウェアとホストシステムによって `ax` として登録されます。許容ホールドを有効にすると、別のキーがタップされた場合にモッドタップキーを修飾キーと見なすように処理を変更し、 `X` (`SHIFT`+`x`) と登録されます。
-?> `モッドタップ割り込みの無視`を有効にしている場合、これにより両方の動きが変更されます。通常のキーには、最初のキーが最初に放された場合、あるいは両方のキーが `TAPPING_TERM` より長くホールドされた場合に、修飾キーが追加されます。
-
この機能をより細かく制御するために、以下を `config.h` に追加することができます:
```c
@@ -84,32 +82,6 @@ bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
}
```
-## モッドタップ割り込みの無視
-
-この設定を有効にするには、これを `config.h` に追加してください:
-
-```c
-#define IGNORE_MOD_TAP_INTERRUPT
-```
-
-許容ホールドと同様に、これは高速なタイピストのためのファームウェアの処理方法を変更します。モッドタップキーを押し、他のキーを押し、モッドタップキーを放し、通常のキーを放すと、`TAPPING_TERM` 内で押された場合でも、通常はモッドと通常のキーが出力されます。これは、ローリングコンボキーや、頻繁に使用するキー(例えば、`RCTL_T(KC_QUOT)`)にモッドタップを使う高速なタイピストには望ましくない場合があります。
-
-`モッドタップ割り込みの無視`を設定するには、両方のキーを `TAPPING_TERM` の間ホールドすると、(その修飾キーの)ホールド機能を実行する必要があります。
-
-例えば:
-
-- `SFT_T(KC_A)` を押す
-- `KC_X` を押す
-- `SFT_T(KC_A)` を放す
-- `KC_X` を放す
-
-通常、これは大文字の `X` (`SHIFT`+`x`)、またはモッド + キーを送信します。`モッドタップ割り込みの無視` を有効にすると、ホールドアクションを登録するには、両方のキーを `TAPPING_TERM` の間ホールドする必要があります。この場合、素早いタップは `ax` を送信しますが、両方をホールドすると、大文字の `X` (`SHIFT`+`x`) を出力します。
-
-
-?> __注意__: これはモディファイアにのみ関係し、レイヤー切り替えキーには関係しません。
-
-?> `許容ホールド`を有効にすると、これは両方がどのように動作するかを変更します。通常のキーには、最初のキーが最初に放された場合、あるいは両方のキーが `TAPPING_TERM` より長くホールドされた場合に、修飾キーが追加されます。
-
## タッピング強制ホールド
`タッピング強制ホールド` を有効にするには、以下を `config.h` に追加します:
diff --git a/docs/keycodes.md b/docs/keycodes.md
index cad050ccf7..e5b6246af7 100644
--- a/docs/keycodes.md
+++ b/docs/keycodes.md
@@ -803,6 +803,15 @@ See also: [Programmable Button](feature_programmable_button.md)
|`QK_PROGRAMMABLE_BUTTON_31`|`PB_31`|Programmable button 31|
|`QK_PROGRAMMABLE_BUTTON_32`|`PB_32`|Programmable button 32|
+## Repeat Key :id=repeat-key
+
+See also: [Repeat Key](feature_repeat_key.md)
+
+|Keycode |Aliases |Description |
+|-----------------------|---------|-------------------------------------|
+|`QK_REPEAT_KEY` |`QK_REP` |Repeat the last pressed key |
+|`QK_ALT_REPEAT_KEY` |`QK_AREP`|Perform alternate of the last key |
+
## Space Cadet :id=space-cadet
See also: [Space Cadet](feature_space_cadet.md)
diff --git a/docs/mod_tap.md b/docs/mod_tap.md
index ca3a2752c7..8b953d76b4 100644
--- a/docs/mod_tap.md
+++ b/docs/mod_tap.md
@@ -111,8 +111,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
```
-Enabling `IGNORE_MOD_TAP_INTERRUPT` is recommended when using Mod-Tap on alphanumeric keys to avoid hold function taking precendence when the next key is pressed quickly. See [Ignore Mod Tap Interrupt](tap_hold.md#ignore-mod-tap-interrupt) for more details.
-
### Changing both tap and hold
This last example implements custom tap and hold function with `LT(0,KC_NO)` to create a single copy-on-tap, paste-on-hold key:
diff --git a/docs/newbs_building_firmware_workflow.md b/docs/newbs_building_firmware_workflow.md
index e6895252aa..51ce304901 100644
--- a/docs/newbs_building_firmware_workflow.md
+++ b/docs/newbs_building_firmware_workflow.md
@@ -95,7 +95,7 @@ on: [push, workflow_dispatch]
jobs:
build:
runs-on: ubuntu-latest
- container: qmkfm/qmk_cli
+ container: ghcr.io/qmk/qmk_cli
strategy:
fail-fast: false
matrix:
diff --git a/docs/quantum_painter.md b/docs/quantum_painter.md
index ac37053c79..317a9d9f1a 100644
--- a/docs/quantum_painter.md
+++ b/docs/quantum_painter.md
@@ -32,16 +32,20 @@ Supported devices:
## Quantum Painter Configuration :id=quantum-painter-config
-| Option | Default | Purpose |
-|------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------|
-| `QUANTUM_PAINTER_NUM_IMAGES` | `8` | The maximum number of images/animations that can be loaded at any one time. |
-| `QUANTUM_PAINTER_NUM_FONTS` | `4` | The maximum number of fonts that can be loaded at any one time. |
-| `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS` | `4` | The maximum number of animations that can be executed at the same time. |
-| `QUANTUM_PAINTER_LOAD_FONTS_TO_RAM` | `FALSE` | Whether or not fonts should be loaded to RAM. Relevant for fonts stored in off-chip persistent storage, such as external flash. |
-| `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE` | `32` | The limit of the amount of pixel data that can be transmitted in one transaction to the display. Higher values require more RAM on the MCU. |
-| `QUANTUM_PAINTER_SUPPORTS_256_PALETTE` | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU. |
-| `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS` | `FALSE` | If native color range is supported. Requires significantly more RAM on the MCU. |
-| `QUANTUM_PAINTER_DEBUG` | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging. |
+| Option | Default | Purpose |
+|---------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `QUANTUM_PAINTER_DISPLAY_TIMEOUT` | `30000` | This controls the amount of time (in milliseconds) that all displays will remain on after the last user input. If set to `0`, the display will remain on indefinitely. |
+| `QUANTUM_PAINTER_TASK_THROTTLE` | `1` | This controls the amount of time (in milliseconds) that the Quantum Painter internal task will wait between each execution. Affects animations, display timeout, and LVGL timing if enabled. |
+| `QUANTUM_PAINTER_NUM_IMAGES` | `8` | The maximum number of images/animations that can be loaded at any one time. |
+| `QUANTUM_PAINTER_NUM_FONTS` | `4` | The maximum number of fonts that can be loaded at any one time. |
+| `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS` | `4` | The maximum number of animations that can be executed at the same time. |
+| `QUANTUM_PAINTER_LOAD_FONTS_TO_RAM` | `FALSE` | Whether or not fonts should be loaded to RAM. Relevant for fonts stored in off-chip persistent storage, such as external flash. |
+| `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE` | `32` | The limit of the amount of pixel data that can be transmitted in one transaction to the display. Higher values require more RAM on the MCU. |
+| `QUANTUM_PAINTER_SUPPORTS_256_PALETTE` | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU. |
+| `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS` | `FALSE` | If native color range is supported. Requires significantly more RAM on the MCU. |
+| `QUANTUM_PAINTER_DEBUG` | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging. |
+| `QUANTUM_PAINTER_DEBUG_ENABLE_FLUSH_TASK_OUTPUT` | _unset_ | By default, debug output is disabled while the internal task is flushing the display(s). If you want to keep it enabled, add this to your `config.h`. Note: Console will get clogged. |
+
Drivers have their own set of configurable options, and are described in their respective sections.
diff --git a/docs/squeezing_avr.md b/docs/squeezing_avr.md
index 62db7f2471..ce9e43cdae 100644
--- a/docs/squeezing_avr.md
+++ b/docs/squeezing_avr.md
@@ -194,6 +194,7 @@ That said, there are a number of Pro Micro replacements with ARM controllers:
* [Blok](https://boardsource.xyz/store/628b95b494dfa308a6581622)
* [Elite-Pi](https://keeb.io/products/elite-pi-usb-c-pro-micro-replacement-rp2040)
* [0xCB Helios](https://keeb.supply/products/0xcb-helios) ([Open Source](https://github.com/0xCB-dev/0xCB-Helios), DIY/PCBA/Shop)
+* [Liatris](https://splitkb.com/products/liatris)
* [Michi](https://github.com/ci-bus/michi-promicro-rp2040)
There are other, non-Pro Micro compatible boards out there. The most popular being:
diff --git a/docs/tap_hold.md b/docs/tap_hold.md
index 348e2655eb..cdc1cfeca7 100644
--- a/docs/tap_hold.md
+++ b/docs/tap_hold.md
@@ -130,20 +130,18 @@ Note that until the tap-or-hold decision completes (which happens when either th
To better illustrate the tap-or-hold decision modes, let us compare the expected output of each decision mode in a handful of tapping scenarios involving a mod-tap key (`LSFT_T(KC_A)`) and a regular key (`KC_B`) with the `TAPPING_TERM` set to 200ms.
-By default, mod-taps behave like `HOLD_ON_OTHER_KEY_PRESS`, while layer-taps behave like "Ignore Interrupt" out of the box. If you want "Ignore Interrupt"-like behaviour for mod-taps, you must enable `IGNORE_MOD_TAP_INTERRUPT`, or return `false` in the `get_hold_on_other_key_press` function for all mod-taps.
-
Note: "`kc` held" in the "Physical key event" column means that the key wasn't physically released yet at this point in time.
#### Distinct taps (AABB) :id=distinct-taps
-| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
+| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 199 | `LSFT_T(KC_A)` up | a | a | a |
| 210 | `KC_B` down | ab | ab | ab |
| 220 | `KC_B` up | ab | ab | ab |
-| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
+| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 200 | `LSFT_T(KC_A)` held|<kbd>Shift</kbd>| <kbd>Shift</kbd> | <kbd>Shift</kbd> |
@@ -153,14 +151,14 @@ Note: "`kc` held" in the "Physical key event" column means that the key wasn't p
#### Nested tap (ABBA) :id=nested-tap
-| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
+| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 110 | `KC_B` down | | | B |
| 120 | `KC_B` up | | B | B |
| 199 | `LSFT_T(KC_A)` up | ab | B | B |
-| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
+| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 110 | `KC_B` down | | | B |
@@ -168,7 +166,7 @@ Note: "`kc` held" in the "Physical key event" column means that the key wasn't p
| 200 | `LSFT_T(KC_A)` held| B | B | B |
| 210 | `LSFT_T(KC_A)` up | B | B | B |
-| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
+| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 200 | `LSFT_T(KC_A)` held|<kbd>Shift</kbd>| <kbd>Shift</kbd> | <kbd>Shift</kbd> |
@@ -178,14 +176,14 @@ Note: "`kc` held" in the "Physical key event" column means that the key wasn't p
#### Rolling keys (ABAB) :id=rolling-keys
-| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
+| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 110 | `KC_B` down | | | B |
| 130 | `LSFT_T(KC_A)` up | ab | ab | B |
| 140 | `KC_B` up | ab | ab | B |
-| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
+| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 110 | `KC_B` down | | | B |
@@ -241,10 +239,8 @@ Example sequence 3 (Mod Tap):
| +--------------+ | |
+---------------------------|--------+
```
-Based on previous examples, you might have expected the output of the above sequence to be `KC_A` `KC_X`
-since `SFT_T(KC_A)` is NOT held longer than the `TAPPING_TERM`.
-However, the actual output would be capital `X` (`SHIFT` + `x`) due to reasons
-explained under [Ignore Mod Tap Interrupt](#ignore-mod-tap-interrupt).
+In the above sequence, `SFT_T(KC_A)` has been released before the end of its `TAPPING_TERM` and as such will be interpreted as `KC_A`,
+followed by any key event that happened after the initial press of `SFT_T(KC_A)`. In this instance, the output would be `KC_A` `KC_X`.
### Permissive Hold
@@ -379,73 +375,6 @@ bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
}
```
-
-## Ignore Mod Tap Interrupt
-
-To enable this setting, add this to your `config.h`:
-
-```c
-#define IGNORE_MOD_TAP_INTERRUPT
-```
-
-?> This option affects only the Mod Tap keys; it does not affect other dual-role keys such as Layer Tap.
-
-By default, the tap-or-hold decision for Mod Tap keys strongly prefers the hold action. If you press a Mod Tap key, then press another key while still holding the Mod Tap key down, the Mod Tap press will be handled as a modifier hold even if the Mod Tap key is then released within the tapping term, and irrespective of the order in which those keys are released. Using options such as `PERMISSIVE_HOLD` or `HOLD_ON_OTHER_KEY_PRESS` will not affect the functionality of Mod Tap keys in a major way (these options would still affect the delay until the common code for dual-role keys finishes its tap-or-hold decision, but then the special code for Mod Tap keys will override the result of that decision and choose the hold action if another key was pressed). In fact, by default, the tap-or-hold decision for Mod Tap keys is done in the same way as if the `HOLD_ON_OTHER_KEY_PRESS` option was enabled, but without the decreased delay provided by `HOLD_ON_OTHER_KEY_PRESS`.
-
-If the `IGNORE_MOD_TAP_INTERRUPT` option is enabled, Mod Tap keys are no longer treated as a special case, and their behavior will match the behavior of other dual-role keys such as Layer Tap. Then the behavior of Mod Tap keys can be further tuned using other options such as `PERMISSIVE_HOLD` or `HOLD_ON_OTHER_KEY_PRESS`.
-
-An example of a sequence that will be affected by the `IGNORE_MOD_TAP_INTERRUPT` option (assuming that options like `PERMISSIVE_HOLD` or `HOLD_ON_OTHER_KEY_PRESS` are not enabled):
-
-- `SFT_T(KC_A)` Down
-- `KC_X` Down
-- `SFT_T(KC_A)` Up
-- `KC_X` Up
-
-```
- TAPPING_TERM
- +---------------------------|--------+
- | +-------------+ | |
- | | SFT_T(KC_A) | | |
- | +-------------+ | |
- | +--------------+ | |
- | | KC_X | | |
- | +--------------+ | |
- +---------------------------|--------+
-```
-
-Normally, this would send a capital `X` (`SHIFT`+`x`), even if the sequence is performed faster than the `TAPPING_TERM`. However, if the `IGNORE_MOD_TAP_INTERRUPT` option is enabled, the `SFT_T(KC_A)` key must be held longer than the `TAPPING_TERM` to register the hold action. A quick tap will output `ax` in this case, while a hold will still output a capital `X` (`SHIFT`+`x`).
-
-However, if the `HOLD_ON_OTHER_KEY_PRESS` option is enabled in addition to `IGNORE_MOD_TAP_INTERRUPT`, the above sequence will again send a capital `X` (`SHIFT`+`x`) even if performed faster than the `TAPPING_TERM`. The difference from the default configuration is that by default the host will receive the key events only after the `SFT_T(KC_A)` key is released, but with the `HOLD_ON_OTHER_KEY_PRESS` option, the host will start receiving key events when the `KC_X` key is pressed.
-
-For more granular control of this feature, you can add the following to your `config.h`:
-
-```c
-#define HOLD_ON_OTHER_KEY_PRESS_PER_KEY
-```
-
-?> This option affects *all* dual-role keys.
-
-You can then add the following function to your keymap:
-
-```c
-bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
- switch (keycode) {
- case SFT_T(KC_SPC):
- // Do not force the mod-tap key press to be handled as a modifier
- // if any other key was pressed while the mod-tap key is held down.
- return false;
- default:
- // Force the dual-role key press to be handled as a modifier if any
- // other key was pressed while the mod-tap key is held down.
- return true;
- }
-}
-```
-
-Note that you must return `false` in `get_hold_on_other_key_press` in order to apply `IGNORE_MOD_TAP_INTERRUPT` for a certain mod-tap key.
-
-?> `IGNORE_MOD_TAP_INTERRUPT[_PER_KEY]` is being progressively phased out to align the (default) behavior and configuration of mod-taps with the rest of dual-role keys.
-
## Quick Tap Term
When the user holds a key after tapping it, the tapping function is repeated by default, rather than activating the hold function. This allows keeping the ability to auto-repeat the tapping function of a dual-role key. `QUICK_TAP_TERM` enables fine tuning of that ability. If set to `0`, it will remove the auto-repeat ability and activate the hold function instead.
diff --git a/docs/understanding_qmk.md b/docs/understanding_qmk.md
index 7b436a45be..7cb46bd8cf 100644
--- a/docs/understanding_qmk.md
+++ b/docs/understanding_qmk.md
@@ -129,6 +129,8 @@ The `process_record()` function itself is deceptively simple, but hidden within
* [`void action_exec(keyevent_t event)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/action.c#L78-L140)
* [`void pre_process_record_quantum(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/quantum.c#L204)
+ * [`bool pre_process_record_kb(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/27119fa77e8a1b95fff80718d3db4f3e32849298/quantum/quantum.c#L117)
+ * [`bool pre_process_record_user(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/27119fa77e8a1b95fff80718d3db4f3e32849298/quantum/quantum.c#L121)
* [`bool process_combo(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/process_keycode/process_combo.c#L521)
* [`void process_record(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/action.c#L254)
* [`bool process_record_quantum(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/quantum.c#L224)
diff --git a/docs/ws2812_driver.md b/docs/ws2812_driver.md
index 5942da28d1..f8cad20ce0 100644
--- a/docs/ws2812_driver.md
+++ b/docs/ws2812_driver.md
@@ -72,12 +72,12 @@ WS2812_DRIVER = i2c
Configure the hardware via your config.h:
```c
-#define WS2812_ADDRESS 0xb0 // default: 0xb0
-#define WS2812_TIMEOUT 100 // default: 100
+#define WS2812_I2C_ADDRESS 0xB0 // default: 0xB0
+#define WS2812_I2C_TIMEOUT 100 // default: 100
```
### SPI
-Targeting STM32 boards where WS2812 support is offloaded to an SPI hardware device. The advantage is that the use of DMA offloads processing of the WS2812 protocol from the MCU. `RGB_DI_PIN` for this driver is the configured SPI MOSI pin. Due to the nature of repurposing SPI to drive the LEDs, the other SPI pins, MISO and SCK, **must** remain unused. To configure it, add this to your rules.mk:
+Targeting STM32 boards where WS2812 support is offloaded to an SPI hardware device. The advantage is that the use of DMA offloads processing of the WS2812 protocol from the MCU. `WS2812_DI_PIN` for this driver is the configured SPI MOSI pin. Due to the nature of repurposing SPI to drive the LEDs, the other SPI pins, MISO and SCK, **must** remain unused. To configure it, add this to your rules.mk:
```make
WS2812_DRIVER = spi
@@ -183,7 +183,7 @@ This can be configured for bitbang, PWM and SPI.
Note: This only applies to STM32 boards.
- To configure the `RGB_DI_PIN` to open drain configuration add this to your config.h file:
+ To configure the `WS2812_DI_PIN` to open drain configuration add this to your config.h file:
```c
#define WS2812_EXTERNAL_PULLUP
```
diff --git a/docs/zh-cn/_summary.md b/docs/zh-cn/_summary.md
index 3baee6dc2e..0fc92e33d3 100644
--- a/docs/zh-cn/_summary.md
+++ b/docs/zh-cn/_summary.md
@@ -42,7 +42,6 @@
* [键映射总览](zh-cn/keymap.md)
* 开发环境
* [Docker指南](zh-cn/getting_started_docker.md)
- * [Vagrant指南](zh-cn/getting_started_vagrant.md)
* 刷写(Flashing)
* [刷写](zh-cn/flashing.md)
* [刷写ATmega32A (ps2avrgb)](zh-cn/flashing_bootloadhid.md)
@@ -74,6 +73,7 @@
* [Mod-Tap](zh-cn/mod_tap.md)
* [宏](zh-cn/feature_macros.md)
* [鼠标键](zh-cn/feature_mouse_keys.md)
+ * [Repeat Key](zh-cn/feature_repeat_key.md)
* [Space Cadet Shift](zh-cn/feature_space_cadet.md)
* [US ANSI上档键值](zh-cn/keycodes_us_ansi_shifted.md)
@@ -188,5 +188,5 @@
* [Midi辅助功能](zh-cn/internals/midi_util.md)
* [发送函数](zh-cn/internals/send_functions.md)
* [Sysex工具](zh-cn/internals/sysex_tools.md)
-
+
<!--fromen:20211014-12:00(GMT+8) commit 04cf161aa01fd433b5dae69d9fd31569ed5dca59-->
diff --git a/docs/zh-cn/getting_started_vagrant.md b/docs/zh-cn/getting_started_vagrant.md
deleted file mode 100644
index 5e5de44552..0000000000
--- a/docs/zh-cn/getting_started_vagrant.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Vagrant快速上手指引
-
-<!---
- original document: 0.15.12:docs/getting_started_vagrant.md
- git diff 0.15.12 HEAD -- docs/getting_started_vagrant.md | cat
--->
-
-本工程包含一份 `Vagrantfile`,可以方便地在不更改你系统环境情况下完成新固件文件的构建工作。这同时也保证了在你拉取该工程代码后的编译环境与也使用Vagrantfile的其它人的一致。当你需要其他人协助你排查遇到的问题时会方便很多。
-
-## 需求
-
-本工程中的 `Vagrantfile` 需要安装[Vagrant](https://www.vagrantup.com/)以及可用的虚拟机服务:
-
-* [VirtualBox](https://www.virtualbox.org/) (5.0.12及以后版本)
- * 卖点是'最适用于Vagrant的平台'
-* [VMware Workstation](https://www.vmware.com/products/workstation) 及 [Vagrant VMware插件](https://www.vagrantup.com/vmware)
- * (付费购买的)VMware插件需要在经过正版授权的VMware Workstation/Fusion上运行
-* [Docker](https://www.docker.com/)
-
-安装了Vagrant之后,在安装合适的虚拟机服务后可能需要重启机器。拉取本工程后在工程目录下执行 'vagrant up' 将启动一个包含了所有本工程所需工具的构建环境(虚拟机或是容器)。最后会有一个vagrant启动提示告知你一切正常就绪,否则你也可以参考一下下面的构建文档。
-
-## 刷写固件
-
-比较“简单”的方案是在你的宿主系统上借助以下工具刷写固件:
-
-* [QMK工具箱](https://github.com/qmk/qmk_toolbox) (推荐)
-* [Teensy Loader](https://www.pjrc.com/teensy/loader.html)
-
-如果你希望通过命令行进行编程工作,可以在Vagrantfile中取消掉['modifyvm']的注释以允许USB直通到Linux环境,既可以使用dfu-util/dfu-programmer之类的命令行工具进行编程工作,或是安装Teensy的命令行版本。
-
-## Vagrantfile概览
-开发环境被配置为运行QMK Docker镜像 `qmkfm/qmk_cli`,不仅让各系统下的功能预期一致,也是我们CI环境的镜像。
-
-## FAQ
-
-### 为什么我的VirtualBox环境会有问题?
-VirtualBox 5的某些版本与工程中Vagrantfile中指定的VirtualBox扩展存在兼容问题。如果你遇到了/vagrant挂载不成功的问题,请升级VirtualBox至5.0.12或更高版本。**或者,可以尝试执行如下命令:**
-
-```console
-vagrant plugin install vagrant-vbguest
-```
-
-### 如何移除一个现有环境?
-不再需要这个环境了是吗?在本工程目录下的任何位置,执行:
-
-```console
-vagrant destroy
-```
-
-### 如果我是想直接用Docker呢?
-想在不使用虚拟机技术的情况下也能使用Vagrant工作流?Vagrangfile已配置为允许绕过运行虚拟机,直接运行容器。通过如下方式执行命令可以强制使用Docker来启动环境:
-```console
-vagrant up --provider=docker
-```
-
-### 如何访问虚拟机环境而非Docker容器?
-通过如下方法跳过 `vagrant` 的用户初始化过程以在QMK构建镜像中直接执行:
-
-```console
-vagrant ssh -c 'sudo -i'
-```
diff --git a/docs/zh-cn/mod_tap.md b/docs/zh-cn/mod_tap.md
index 5bf18a1527..9dc59bfb79 100644
--- a/docs/zh-cn/mod_tap.md
+++ b/docs/zh-cn/mod_tap.md
@@ -117,8 +117,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
```
-在数字及字母键上使用Mod-Tap时推荐启用 `IGNORE_MOD_TAP_INTERRUPT`,以避免在快速按下下一个键时保持功能优先级。参见[忽略Mod Tap中断](zh-cn/tap_hold.md#ignore-mod-tap-interrupt)。
-
### 同时改变点击和按住功能
最后一个例子通过 `LT(0,KC_NO)` 实现了点击复制,按住粘贴的功能: