summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/_summary.md1
-rw-r--r--docs/api_docs.md4
-rw-r--r--docs/audio_driver.md10
-rw-r--r--docs/config_options.md13
-rw-r--r--docs/faq_debug.md2
-rw-r--r--docs/feature_auto_shift.md30
-rw-r--r--docs/feature_autocorrect.md295
-rw-r--r--docs/feature_caps_word.md4
-rw-r--r--docs/feature_combo.md12
-rw-r--r--docs/feature_converters.md52
-rw-r--r--docs/feature_eeprom.md16
-rw-r--r--docs/feature_encoders.md14
-rw-r--r--docs/feature_joystick.md121
-rw-r--r--docs/feature_key_lock.md6
-rw-r--r--docs/feature_key_overrides.md14
-rw-r--r--docs/feature_leader_key.md12
-rw-r--r--docs/feature_led_indicators.md7
-rw-r--r--docs/feature_led_matrix.md30
-rw-r--r--docs/feature_mouse_keys.md34
-rw-r--r--docs/feature_pointing_device.md263
-rw-r--r--docs/feature_programmable_button.md200
-rw-r--r--docs/feature_ps2_mouse.md18
-rw-r--r--docs/feature_rgb_matrix.md89
-rw-r--r--docs/feature_rgblight.md6
-rw-r--r--docs/feature_secure.md12
-rw-r--r--docs/feature_space_cadet.md30
-rw-r--r--docs/feature_split_keyboard.md15
-rw-r--r--docs/feature_unicode.md13
-rw-r--r--docs/feature_velocikey.md2
-rw-r--r--docs/ja/feature_ps2_mouse.md16
-rw-r--r--docs/keycodes.md176
-rw-r--r--docs/keycodes_basic.md2
-rw-r--r--docs/keymap.md4
-rw-r--r--docs/platformdev_rp2040.md5
-rw-r--r--docs/quantum_painter.md566
-rw-r--r--docs/ref_functions.md2
-rw-r--r--docs/squeezing_avr.md1
37 files changed, 1514 insertions, 583 deletions
diff --git a/docs/_summary.md b/docs/_summary.md
index 7dc4ddb0e4..0af0c7bc64 100644
--- a/docs/_summary.md
+++ b/docs/_summary.md
@@ -76,6 +76,7 @@
* Software Features
* [Auto Shift](feature_auto_shift.md)
+ * [Autocorrect](feature_autocorrect.md)
* [Caps Word](feature_caps_word.md)
* [Combos](feature_combo.md)
* [Debounce API](feature_debounce_type.md)
diff --git a/docs/api_docs.md b/docs/api_docs.md
index 237b02fed2..2594821ab0 100644
--- a/docs/api_docs.md
+++ b/docs/api_docs.md
@@ -14,8 +14,8 @@ This service is an asynchronous API for compiling custom keymaps. You POST some
"keymap": "my_awesome_keymap",
"layout": "LAYOUT_all",
"layers": [
- ["KC_GRV","KC_1","KC_2","KC_3","KC_4","KC_5","KC_6","KC_7","KC_8","KC_9","KC_0","KC_MINS","KC_EQL","KC_GRV","KC_BSPC","KC_PGUP","KC_TAB","KC_Q","KC_W","KC_E","KC_R","KC_T","KC_Y","KC_U","KC_I","KC_O","KC_P","KC_LBRC","KC_RBRC","KC_BSLS","KC_PGDN","KC_CAPS","KC_A","KC_S","KC_D","KC_F","KC_G","KC_H","KC_J","KC_K","KC_L","KC_SCLN","KC_QUOT","KC_NUHS","KC_ENT","KC_LSFT","KC_NUBS","KC_Z","KC_X","KC_C","KC_V","KC_B","KC_N","KC_M","KC_COMM","KC_DOT","KC_SLSH","KC_RO","KC_RSFT","KC_UP","KC_LCTL","KC_LGUI","KC_LALT","KC_MHEN","KC_SPC","KC_SPC","KC_HENK","KC_RALT","KC_RCTL","MO(1)","KC_LEFT","KC_DOWN","KC_RIGHT"],
- ["KC_ESC","KC_F1","KC_F2","KC_F3","KC_F4","KC_F5","KC_F6","KC_F7","KC_F8","KC_F9","KC_F10","KC_F11","KC_F12","KC_TRNS","KC_DEL","BL_STEP","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","_______","KC_TRNS","KC_PSCR","KC_SLCK","KC_PAUS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(2)","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_PGUP","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(1)","KC_LEFT","KC_PGDN","KC_RGHT"],
+ ["KC_GRV","KC_1","KC_2","KC_3","KC_4","KC_5","KC_6","KC_7","KC_8","KC_9","KC_0","KC_MINS","KC_EQL","KC_GRV","KC_BSPC","KC_PGUP","KC_TAB","KC_Q","KC_W","KC_E","KC_R","KC_T","KC_Y","KC_U","KC_I","KC_O","KC_P","KC_LBRC","KC_RBRC","KC_BSLS","KC_PGDN","KC_CAPS","KC_A","KC_S","KC_D","KC_F","KC_G","KC_H","KC_J","KC_K","KC_L","KC_SCLN","KC_QUOT","KC_NUHS","KC_ENT","KC_LSFT","KC_NUBS","KC_Z","KC_X","KC_C","KC_V","KC_B","KC_N","KC_M","KC_COMM","KC_DOT","KC_SLSH","KC_INT1","KC_RSFT","KC_UP","KC_LCTL","KC_LGUI","KC_LALT","KC_INT5","KC_SPC","KC_SPC","KC_INT4","KC_RALT","KC_RCTL","MO(1)","KC_LEFT","KC_DOWN","KC_RIGHT"],
+ ["KC_ESC","KC_F1","KC_F2","KC_F3","KC_F4","KC_F5","KC_F6","KC_F7","KC_F8","KC_F9","KC_F10","KC_F11","KC_F12","KC_TRNS","KC_DEL","BL_STEP","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","_______","KC_TRNS","KC_PSCR","KC_SCRL","KC_PAUS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(2)","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_PGUP","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(1)","KC_LEFT","KC_PGDN","KC_RGHT"],
["KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","QK_BOOT","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(2)","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(1)","KC_TRNS","KC_TRNS","KC_TRNS"]
]
}
diff --git a/docs/audio_driver.md b/docs/audio_driver.md
index ffd9c8d5ad..a0bbb22e19 100644
--- a/docs/audio_driver.md
+++ b/docs/audio_driver.md
@@ -159,7 +159,6 @@ A configuration example for the STM32F103C8 would be:
//halconf.h:
#define HAL_USE_PWM TRUE
#define HAL_USE_PAL TRUE
-#define HAL_USE_GPT TRUE
#include_next <halconf.h>
```
@@ -168,8 +167,6 @@ A configuration example for the STM32F103C8 would be:
#include_next <mcuconf.h>
#undef STM32_PWM_USE_TIM1
#define STM32_PWM_USE_TIM1 TRUE
-#undef STM32_GPT_USE_TIM4
-#define STM32_GPT_USE_TIM4 TRUE
```
If we now target pin A8, looking through the data-sheet of the STM32F103C8, for the timers and alternate functions
@@ -184,7 +181,6 @@ with all this information, the configuration would contain these lines:
#define AUDIO_PIN A8
#define AUDIO_PWM_DRIVER PWMD1
#define AUDIO_PWM_CHANNEL 1
-#define AUDIO_STATE_TIMER GPTD4
```
ChibiOS uses GPIOv1 for the F103, which only knows of one alternate function.
@@ -207,15 +203,15 @@ You can also change the timer used for software PWM by defining the driver. For
While not an exhaustive list, the following table provides the scenarios that have been partially validated:
-| | DAC basic | DAC additive | PWM hardware | PWM software |
-|--------------------------|--------------------|--------------------|--------------------|--------------------|
+| | DAC basic | DAC additive | PWM hardware | PWM software |
+| ------------------------ | ------------------ | ------------------ | ------------------ | ------------------ |
| Atmega32U4 | :o: | :o: | :heavy_check_mark: | :o: |
+| RP2040 | :x: | :x: | :heavy_check_mark: | ? |
| STM32F103C8 (bluepill) | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| STM32F303CCT6 (proton-c) | :heavy_check_mark: | :heavy_check_mark: | ? | :heavy_check_mark: |
| STM32F405VG | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| L0xx | :x: (no Tim8) | ? | ? | ? |
-
:heavy_check_mark: : works and was tested
:o: : does not apply
:x: : not supported by MCU
diff --git a/docs/config_options.md b/docs/config_options.md
index cc732de7d2..a6ceb199de 100644
--- a/docs/config_options.md
+++ b/docs/config_options.md
@@ -49,11 +49,11 @@ This is a C header file that is one of the first things included, and will persi
* defines your VID, and for most DIY projects, can be whatever you want
* `#define PRODUCT_ID 0x5678`
* defines your PID, and for most DIY projects, can be whatever you want
-* `#define DEVICE_VER 0`
+* `#define DEVICE_VER 0x0100`
* defines the device version (often used for revisions)
-* `#define MANUFACTURER Me`
+* `#define MANUFACTURER "Me"`
* generally who/whatever brand produced the board
-* `#define PRODUCT Board`
+* `#define PRODUCT "Board"`
* the name of the keyboard
* `#define MATRIX_ROWS 5`
* the number of rows in your keyboard's matrix
@@ -325,6 +325,13 @@ There are a few different ways to set handedness for split keyboards (listed in
* `#define SPLIT_USB_TIMEOUT_POLL 10`
* Poll frequency when detecting master/slave when using `SPLIT_USB_DETECT`
+
+* `#define SPLIT_WATCHDOG_ENABLE`
+ * Reboot slave if no communication from master within timeout.
+ * Helps resolve issue where both sides detect as slave using `SPLIT_USB_DETECT`
+
+* `#define SPLIT_WATCHDOG_TIMEOUT 3000`
+ * Maximum slave timeout when waiting for communication from master when using `SPLIT_WATCHDOG_ENABLE`
* `#define FORCED_SYNC_THROTTLE_MS 100`
* Deadline for synchronizing data from master to slave when using the QMK-provided split transport.
diff --git a/docs/faq_debug.md b/docs/faq_debug.md
index b639b7ea04..cad98bc331 100644
--- a/docs/faq_debug.md
+++ b/docs/faq_debug.md
@@ -4,7 +4,7 @@ This page details various common questions people have about troubleshooting the
## Debugging :id=debugging
-Your keyboard will output debug information if you have `CONSOLE_ENABLE = yes` in your `rules.mk`. By default the output is very limited, but you can turn on debug mode to increase the amount of debug output. Use the `DEBUG` keycode in your keymap, use the [Command](feature_command.md) feature to enable debug mode, or add the following code to your keymap.
+Your keyboard will output debug information if you have `CONSOLE_ENABLE = yes` in your `rules.mk`. By default the output is very limited, but you can turn on debug mode to increase the amount of debug output. Use the `DB_TOGG` keycode in your keymap, use the [Command](feature_command.md) feature to enable debug mode, or add the following code to your keymap.
```c
void keyboard_post_init_user(void) {
diff --git a/docs/feature_auto_shift.md b/docs/feature_auto_shift.md
index 99b0ca3c8a..d3437a9c60 100644
--- a/docs/feature_auto_shift.md
+++ b/docs/feature_auto_shift.md
@@ -300,14 +300,14 @@ This will enable you to define three keys temporarily to increase, decrease and
Map three keys temporarily in your keymap:
-| Key Name | Description |
-|----------|-----------------------------------------------------|
-| KC_ASDN | Lower the Auto Shift timeout variable (down) |
-| KC_ASUP | Raise the Auto Shift timeout variable (up) |
-| KC_ASRP | Report your current Auto Shift timeout value |
-| KC_ASON | Turns on the Auto Shift Function |
-| KC_ASOFF | Turns off the Auto Shift Function |
-| KC_ASTG | Toggles the state of the Auto Shift feature |
+|Keycode |Aliases |Description |
+|----------------------|---------|--------------------------------------------|
+|`QK_AUTO_SHIFT_DOWN` |`AS_DOWN`|Lower the Auto Shift timeout variable (down)|
+|`QK_AUTO_SHIFT_UP` |`AS_UP` |Raise the Auto Shift timeout variable (up) |
+|`QK_AUTO_SHIFT_REPORT`|`AS_RPT` |Report your current Auto Shift timeout value|
+|`QK_AUTO_SHIFT_ON` |`AS_ON` |Turns on the Auto Shift Function |
+|`QK_AUTO_SHIFT_OFF` |`AS_OFF` |Turns off the Auto Shift Function |
+|`QK_AUTO_SHIFT_TOGGLE`|`AS_TOGG`|Toggles the state of the Auto Shift feature |
Compile and upload your new firmware.
@@ -318,18 +318,18 @@ completely normal and with no intention of shifted keys.
1. Type multiple sentences of alphabetical letters.
2. Observe any upper case letters.
-3. If there are none, press the key you have mapped to `KC_ASDN` to decrease
+3. If there are none, press the key you have mapped to `AS_DOWN` to decrease
time Auto Shift timeout value and go back to step 1.
4. If there are some upper case letters, decide if you need to work on tapping
those keys with less down time, or if you need to increase the timeout.
5. If you decide to increase the timeout, press the key you have mapped to
- `KC_ASUP` and go back to step 1.
+ `AS_UP` and go back to step 1.
6. Once you are happy with your results, press the key you have mapped to
- `KC_ASRP`. The keyboard will type by itself the value of your
+ `AS_RPT`. The keyboard will type by itself the value of your
`AUTO_SHIFT_TIMEOUT`.
7. Update `AUTO_SHIFT_TIMEOUT` in your `config.h` with the value reported.
8. Add `AUTO_SHIFT_NO_SETUP` to your `config.h`.
-9. Remove the key bindings `KC_ASDN`, `KC_ASUP` and `KC_ASRP`.
+9. Remove the key bindings `AS_DOWN`, `AS_UP` and `AS_RPT`.
10. Compile and upload your new firmware.
#### An Example Run
@@ -337,17 +337,17 @@ completely normal and with no intention of shifted keys.
hello world. my name is john doe. i am a computer programmer playing with
keyboards right now.
- [PRESS KC_ASDN quite a few times]
+ [PRESS AS_DOWN quite a few times]
heLLo woRLd. mY nAMe is JOHn dOE. i AM A compUTeR proGRaMMER PlAYiNG witH
KEYboArDS RiGHT NOw.
- [PRESS KC_ASUP a few times]
+ [PRESS AS_UP a few times]
hello world. my name is john Doe. i am a computer programmer playing with
keyboarDs right now.
- [PRESS KC_ASRP]
+ [PRESS AS_RPT]
115
diff --git a/docs/feature_autocorrect.md b/docs/feature_autocorrect.md
new file mode 100644
index 0000000000..e042027c0f
--- /dev/null
+++ b/docs/feature_autocorrect.md
@@ -0,0 +1,295 @@
+# Autocorrect
+
+There are a lot of words that are prone to being typed incorrectly, due to habit, sequence or just user error. This feature leverages your firmware to automatically correct these errors, to help reduce typos.
+
+## How does it work? :id=how-does-it-work
+
+The feature maintains a small buffer of recent key presses. On each key press, it checks whether the buffer ends in a recognized typo, and if so, automatically sends keystrokes to correct it.
+
+The tricky part is how to efficiently check the buffer for typos. We don’t want to spend too much memory or time on storing or searching the typos. A good solution is to represent the typos with a trie data structure. A trie is a tree data structure where each node is a letter, and words are formed by following a path to one of the leaves.
+
+![An example trie](https://i.imgur.com/HL5DP8H.png)
+
+Since we search whether the buffer ends in a typo, we store the trie writing in reverse. The trie is queried starting from the last letter, then second to last letter, and so on, until either a letter doesn’t match or we reach a leaf, meaning a typo was found.
+
+## How do I enable Autocorrection :id=how-do-i-enable-autocorrection
+
+In your `rules.mk`, add this:
+
+```make
+AUTOCORRECT_ENABLE = yes
+```
+
+Additionally, you will need a library for autocorrection. A small sample library is included by default, so that you can get up and running right away, but you can provide a customized library.
+
+By default, autocorrect is disabled. To enable it, you need to use the `AC_TOGG` keycode to enable it. The status is stored in persistent memory, so you shouldn't need to enabled it again.
+
+## Customizing autocorrect library :id=customizing-autocorrect-library
+
+To provide a custom library, you need to create a text file with the corrections. For instance:
+
+```text
+:thier -> their
+fitler -> filter
+lenght -> length
+ouput -> output
+widht -> width
+```
+
+The syntax is `typo -> correction`. Typos and corrections are case insensitive, and any whitespace before or after the typo and correction is ignored. The typo must be only the letters a–z, or the special character : representing a word break. The correction may have any non-unicode characters.
+
+Then, run:
+
+```sh
+qmk generate-autocorrect-data autocorrect_dictionary.txt
+```
+
+This will process the file and produce an `autocorrect_data.h` file with the trie library, in the folder that you are at. You can specify the keyboard and keymap (eg `-kb planck/rev6 -km jackhumbert`), and it will place the file in that folder instead. But as long as the file is located in your keymap folder, or user folder, it should be picked up automatically.
+
+This file will look like this:
+
+```c
+// :thier -> their
+// fitler -> filter
+// lenght -> length
+// ouput -> output
+// widht -> width
+
+#define AUTOCORRECT_MIN_LENGTH 5 // "ouput"
+#define AUTOCORRECT_MAX_LENGTH 6 // ":thier"
+
+#define DICTIONARY_SIZE 74
+
+static const uint8_t autocorrect_data[DICTIONARY_SIZE] PROGMEM = {85, 7, 0, 23, 35, 0, 0, 8, 0, 76, 16, 0, 15, 25, 0, 0,
+ 11, 23, 44, 0, 130, 101, 105, 114, 0, 23, 12, 9, 0, 131, 108, 116, 101, 114, 0, 75, 42, 0, 24, 64, 0, 0, 71, 49, 0,
+ 10, 56, 0, 0, 12, 26, 0, 129, 116, 104, 0, 17, 8, 15, 0, 129, 116, 104, 0, 19, 24, 18, 0, 130, 116, 112, 117, 116,
+ 0};
+```
+
+### Avoiding false triggers :id=avoiding-false-triggers
+
+By default, typos are searched within words, to find typos within longer identifiers like maxFitlerOuput. While this is useful, a consequence is that autocorrection will falsely trigger when a typo happens to be a substring of a correctly-spelled word. For instance, if we had thier -> their as an entry, it would falsely trigger on (correct, though relatively uncommon) words like “wealthier” and “filthier.”
+
+The solution is to set a word break : before and/or after the typo to constrain matching. : matches space, period, comma, underscore, digits, and most other non-alpha characters.
+
+|Text |thier |:thier |thier: |:thier: |
+|-----------------|:------:|:------:|:------:|:------:|
+|see `thier` typo |matches |matches |matches |matches |
+|it’s `thiers` |matches |matches |no |no |
+|wealthier words |matches |no |matches |no |
+
+:thier: is most restrictive, matching only when thier is a whole word.
+
+The `qmk generate-autocorrect-data` commands can make an effort to check for entries that would false trigger as substrings of correct words. It searches each typo against a dictionary of 25K English words from the english_words Python package, provided it’s installed. (run `python3 -m pip install english_words` to install it.)
+
+?> Unfortunately, this is limited to just english words, at this point.
+
+## Overriding Autocorrect
+
+Occasionally you might actually want to type a typo (for instance, while editing autocorrection_dict.txt) without being autocorrected. There are a couple of ways to do this:
+
+1. Begin typing the typo.
+2. Before typing the last letter, press and release the Ctrl or Alt key.
+3. Type the remaining letters.
+
+This works because the autocorrection implementation doesn’t understand hotkeys, so it resets itself whenever a modifier other than shift is held.
+
+Additionally, you can use the `AC_TOGG` keycode to toggle the on/off status for Autocorrect.
+
+### Keycodes :id=keycodes
+
+|Keycode |Aliases |Description |
+|-----------------------|---------|----------------------------------------------|
+|`QK_AUTOCORRECT_ON` |`AC_ON` |Turns on the Autocorrect feature. |
+|`QK_AUTOCORRECT_OFF` |`AC_OFF` |Turns off the Autocorrect feature. |
+|`QK_AUTOCORRECT_TOGGLE`|`AC_TOGG`|Toggles the status of the Autocorrect feature.|
+
+## User Callback Functions
+
+### Process Autocorrect
+
+Callback function `bool process_autocorrect_user(uint16_t *keycode, keyrecord_t *record, uint8_t *typo_buffer_size, uint8_t *mods)` is available to customise incoming keycodes and handle exceptions. You can use this function to sanitise input before they are passed onto the autocorrect engine
+
+?> Sanitisation of input is required because autocorrect will only match 8-bit [basic keycodes](keycodes_basic.md) for typos. If valid modifier keys or 16-bit keycodes that are part of a user's word input (such as Shift + A) is passed through, they will fail typo letter detection. For example a [Mod-Tap](mod_tap.md) key such as `LCTL_T(KC_A)` is 16-bit and should be masked for the 8-bit `KC_A`.
+
+The default user callback function is found inside `quantum/process_keycode/process_autocorrect.c`. It covers most use-cases for QMK special functions and quantum keycodes, including [overriding autocorrect](#overriding-autocorrect) with a modifier other than shift. The `process_autocorrect_user` function is `weak` defined to allow user's copy inside `keymap.c` (or code files) to overwrite it.
+
+#### Process Autocorrect Example
+
+If you have a custom keycode `QMKBEST` that should be ignored as part of a word, and another custom keycode `QMKLAYER` that should override autocorrect, both can be added to the bottom of the `process_autocorrect_user` `switch` statement in your source code:
+
+```c
+bool process_autocorrect_user(uint16_t *keycode, keyrecord_t *record, uint8_t *typo_buffer_size, uint8_t *mods) {
+ // See quantum_keycodes.h for reference on these matched ranges.
+ switch (*keycode) {
+ // Exclude these keycodes from processing.
+ case KC_LSFT:
+ case KC_RSFT:
+ case KC_CAPS:
+ case QK_TO ... QK_ONE_SHOT_LAYER_MAX:
+ case QK_LAYER_TAP_TOGGLE ... QK_LAYER_MOD_MAX:
+ case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:
+ return false;
+
+ // Mask for base keycode from shifted keys.
+ case QK_LSFT ... QK_LSFT + 255:
+ case QK_RSFT ... QK_RSFT + 255:
+ if (*keycode >= QK_LSFT && *keycode <= (QK_LSFT + 255)) {
+ *mods |= MOD_LSFT;
+ } else {
+ *mods |= MOD_RSFT;
+ }
+ *keycode &= 0xFF; // Get the basic keycode.
+ return true;
+#ifndef NO_ACTION_TAPPING
+ // Exclude tap-hold keys when they are held down
+ // and mask for base keycode when they are tapped.
+ case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
+# ifdef NO_ACTION_LAYER
+ // Exclude Layer Tap, if layers are disabled
+ // but action tapping is still enabled.
+ return false;
+# endif
+ case QK_MOD_TAP ... QK_MOD_TAP_MAX:
+ // Exclude hold if mods other than Shift is not active
+ if (!record->tap.count) {
+ return false;
+ }
+ *keycode &= 0xFF;
+ break;
+#else
+ case QK_MOD_TAP ... QK_MOD_TAP_MAX:
+ case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
+ // Exclude if disabled
+ return false;
+#endif
+ // Exclude swap hands keys when they are held down
+ // and mask for base keycode when they are tapped.
+ case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX:
+#ifdef SWAP_HANDS_ENABLE
+ if (*keycode >= 0x56F0 || !record->tap.count) {
+ return false;
+ }
+ *keycode &= 0xFF;
+ break;
+#else
+ // Exclude if disabled
+ return false;
+#endif
+ // Handle custom keycodes
+ case QMKBEST:
+ return false;
+ case QMKLAYER:
+ *typo_buffer_size = 0;
+ return false;
+ }
+
+ // Disable autocorrect while a mod other than shift is active.
+ if ((*mods & ~MOD_MASK_SHIFT) != 0) {
+ *typo_buffer_size = 0;
+ return false;
+ }
+
+ return true;
+}
+```
+
+?> In this callback function, `return false` will skip processing of that keycode for autocorrect. Adding `*typo_buffer_size = 0` will also reset the autocorrect buffer at the same time, cancelling any current letters already stored in the buffer.
+
+### Apply Autocorrect
+
+Additionally, `apply_autocorrect(uint8_t backspaces, const char *str)` allows for users to add additional handling to the autocorrection, or replace the functionality entirely. This passes on the number of backspaces needed to replace the words, as well as the replacement string (partial word, not the full word).
+
+#### Apply Autocorrect Example
+
+This following example will play a sound when a typo is autocorrected and execute the autocorrection itself:
+
+```c
+#ifdef AUDIO_ENABLE
+float autocorrect_song[][2] = SONG(TERMINAL_SOUND);
+#endif
+
+bool apply_autocorrect(uint8_t backspaces, const char *str) {
+#ifdef AUDIO_ENABLE
+ PLAY_SONG(autocorrect_song);
+#endif
+ for (uint8_t i = 0; i < backspaces; ++i) {
+ tap_code(KC_BSPC);
+ }
+ send_string_P(str);
+ return false;
+}
+```
+
+?> In this callback function, `return false` will stop the normal processing of autocorrect, which requires manually handling of removing the "bad" characters and typing the new characters.
+
+!> ***IMPORTANT***: `str` is a pointer to `PROGMEM` data for the autocorrection. If you return false, and want to send the string, this needs to use `send_string_P` and not `send_string` or `SEND_STRING`.
+
+You can also use `apply_autocorrect` to detect and display the event but allow internal code to execute the autocorrection with `return true`:
+
+```c
+bool apply_autocorrect(uint8_t backspaces, const char *str) {
+#ifdef OLED_ENABLE
+ oled_write_P(PSTR("Auto-corrected"), false);
+#endif
+ return true;
+}
+```
+
+## Appendix: Trie binary data format :id=appendix
+
+This section details how the trie is serialized to byte data in autocorrection_data. You don’t need to care about this to use this autocorrection implementation. But it is documented for the record in case anyone is interested in modifying the implementation, or just curious how it works.
+
+What I did here is fairly arbitrary, but it is simple to decode and gets the job done.
+
+### Encoding :id=encoding
+
+All autocorrection data is stored in a single flat array autocorrection_data. Each trie node is associated with a byte offset into this array, where data for that node is encoded, beginning with root at offset 0. There are three kinds of nodes. The highest two bits of the first byte of the node indicate what kind:
+
+* 00 ⇒ chain node: a trie node with a single child.
+* 01 ⇒ branching node: a trie node with multiple children.
+* 10 ⇒ leaf node: a leaf, corresponding to a typo and storing its correction.
+
+![An example trie](https://i.imgur.com/HL5DP8H.png)
+
+**Branching node**. Each branch is encoded with one byte for the keycode (KC_A–KC_Z) followed by a link to the child node. Links between nodes are 16-bit byte offsets relative to the beginning of the array, serialized in little endian order.
+
+All branches are serialized this way, one after another, and terminated with a zero byte. As described above, the node is identified as a branch by setting the two high bits of the first byte to 01, done by bitwise ORing the first keycode with 64. keycode. The root node for the above figure would be serialized like:
+
+```
++-------+-------+-------+-------+-------+-------+-------+
+| R|64 | node 2 | T | node 3 | 0 |
++-------+-------+-------+-------+-------+-------+-------+
+```
+
+**Chain node**. Tries tend to have long chains of single-child nodes, as seen in the example above with f-i-t-l in fitler. So to save space, we use a different format to encode chains than branching nodes. A chain is encoded as a string of keycodes, beginning with the node closest to the root, and terminated with a zero byte. The child of the last node in the chain is encoded immediately after. That child could be either a branching node or a leaf.
+
+In the figure above, the f-i-t-l chain is encoded as
+
+```
++-------+-------+-------+-------+-------+
+| L | T | I | F | 0 |
++-------+-------+-------+-------+-------+
+```
+
+If we were to encode this chain using the same format used for branching nodes, we would encode a 16-bit node link with every node, costing 8 more bytes in this example. Across the whole trie, this adds up. Conveniently, we can point to intermediate points in the chain and interpret the bytes in the same way as before. E.g. starting at the i instead of the l, and the subchain has the same format.
+
+**Leaf node**. A leaf node corresponds to a particular typo and stores data to correct the typo. The leaf begins with a byte for the number of backspaces to type, and is followed by a null-terminated ASCII string of the replacement text. The idea is, after tapping backspace the indicated number of times, we can simply pass this string to the `send_string_P` function. For fitler, we need to tap backspace 3 times (not 4, because we catch the typo as the final ‘r’ is pressed) and replace it with lter. To identify the node as a leaf, the two high bits are set to 10 by ORing the backspace count with 128:
+
+```
++-------+-------+-------+-------+-------+-------+
+| 3|128 | 'l' | 't' | 'e' | 'r' | 0 |
++-------+-------+-------+-------+-------+-------+
+```
+
+### Decoding :id=decoding
+
+This format is by design decodable with fairly simple logic. A 16-bit variable state represents our current position in the trie, initialized with 0 to start at the root node. Then, for each keycode, test the highest two bits in the byte at state to identify the kind of node.
+
+* 00 ⇒ **chain node**: If the node’s byte matches the keycode, increment state by one to go to the next byte. If the next byte is zero, increment again to go to the following node.
+* 01 ⇒ **branching node**: Search the branches for one that matches the keycode, and follow its node link.
+* 10 ⇒ **leaf node**: a typo has been found! We read its first byte for the number of backspaces to type, then pass its following bytes to send_string_P to type the correction.
+
+## Credits
+
+Credit goes to [getreuer](https://github.com/getreuer) for originally implementing this [here](https://getreuer.info/posts/keyboards/autocorrection/#how-does-it-work). As well as to [filterpaper](https://github.com/filterpaper) for converting the code to use PROGMEM, and additional improvements.
diff --git a/docs/feature_caps_word.md b/docs/feature_caps_word.md
index 507ea637b2..c58d1a56e2 100644
--- a/docs/feature_caps_word.md
+++ b/docs/feature_caps_word.md
@@ -42,8 +42,8 @@ CAPS_WORD_ENABLE = yes
Next, use one the following methods to activate Caps Word:
-* **Activate by pressing a key**: Use the `CAPS_WORD` keycode (short
- alias `CAPSWRD`) in your keymap.
+* **Activate by pressing a key**: Use the `QK_CAPS_WORD_TOGGLE` keycode (short
+ alias `CW_TOGG`) in your keymap.
* **Activate by pressing Left Shift + Right Shift**: Add `#define
BOTH_SHIFTS_TURNS_ON_CAPS_WORD` to config.h. You may also need to disable or
diff --git a/docs/feature_combo.md b/docs/feature_combo.md
index 42d965509b..2696ff6833 100644
--- a/docs/feature_combo.md
+++ b/docs/feature_combo.md
@@ -105,11 +105,11 @@ It is worth noting that `COMBO_ACTION`s are not needed anymore. As of [PR#8591](
## Keycodes
You can enable, disable and toggle the Combo feature on the fly. This is useful if you need to disable them temporarily, such as for a game. The following keycodes are available for use in your `keymap.c`
-|Keycode |Description |
-|----------|---------------------------------|
-|`CMB_ON` |Turns on Combo feature |
-|`CMB_OFF` |Turns off Combo feature |
-|`CMB_TOG` |Toggles Combo feature on and off |
+|Keycode |Aliases |Description |
+|-----------------|---------|--------------------------------|
+|`QK_COMBO_ON` |`CM_ON` |Turns on Combo feature |
+|`QK_COMBO_OFF` |`CM_OFF` |Turns off Combo feature |
+|`QK_COMBO_TOGGLE`|`CM_TOGG`|Toggles Combo feature on and off|
# Advanced Configuration
These configuration settings can be set in your `config.h` file.
@@ -255,7 +255,7 @@ 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 = sizeof(key_combos) / sizeof(key_combos[0]);` or by adding `COMBO_LENGTH` as the *last* entry in the combo enum and then `uint16_t COMBO_LEN = COMBO_LENGTH;` as such:
+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 {
...,
diff --git a/docs/feature_converters.md b/docs/feature_converters.md
index fe12254efe..3dabae915d 100644
--- a/docs/feature_converters.md
+++ b/docs/feature_converters.md
@@ -17,6 +17,9 @@ Currently the following converters are available:
| `promicro` | `bit_c_pro` |
| `promicro` | `stemcell` |
| `promicro` | `bonsai_c4` |
+| `promicro` | `elite_pi` |
+| `elite_c` | `stemcell` |
+| `elite_c` | `elite_pi` |
See below for more in depth information on each converter.
@@ -47,6 +50,23 @@ Once a converter is enabled, it exposes the `CONVERT_TO_<target_uppercase>` flag
#endif
```
+### Pin Compatibility
+
+To ensure compatibility, provide validation, and power future workflows, a keyboard should declare its `pin compatibility`. For legacy reasons, this is currently assumed to be `promicro`.
+
+Currently the following pin compatibility interfaces are defined:
+
+| Pinout | Notes |
+|------------|-----------------------------------|
+| `promicro` | Includes RX/TX LEDs |
+| `elite_c` | Includes bottom row pins, no LEDs |
+
+To declare the base for conversions, add this line to your keyboard's `rules.mk`:
+
+```makefile
+PIN_COMPATIBLE = elite_c
+```
+
## Pro Micro
If a board currently supported in QMK uses a [Pro Micro](https://www.sparkfun.com/products/12640) (or compatible board), the supported alternative controllers are:
@@ -60,6 +80,7 @@ If a board currently supported in QMK uses a [Pro Micro](https://www.sparkfun.co
| [Bit-C PRO](https://nullbits.co/bit-c-pro) | `bit_c_pro` |
| [STeMCell](https://github.com/megamind4089/STeMCell) | `stemcell` |
| [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` |
Converter summary:
@@ -72,6 +93,7 @@ Converter summary:
| `bit_c_pro` | `-e CONVERT_TO=bit_c_pro` | `CONVERT_TO=bit_c_pro` | `#ifdef CONVERT_TO_BIT_C_PRO` |
| `stemcell` | `-e CONVERT_TO=stemcell` | `CONVERT_TO=stemcell` | `#ifdef CONVERT_TO_STEMCELL` |
| `bonsai_c4` | `-e CONVERT_TO=bonsai_c4` | `CONVERT_TO=bonsai_c4` | `#ifdef CONVERT_TO_BONSAI_C4` |
+| `elite_pi` | `-e CONVERT_TO=elite_pi` | `CONVERT_TO=elite_pi` | `#ifdef CONVERT_TO_ELITE_PI` |
### Proton C :id=proton_c
@@ -102,9 +124,9 @@ The following defaults are based on what has been implemented for [RP2040](platf
| USB Host (e.g. USB-USB converter) | Not supported (USB host code is AVR specific and is not currently supported on ARM) |
| [Split keyboards](feature_split_keyboard.md) | Partial via `PIO` vendor driver - heavily dependent on enabled features |
-### SparkFun Pro Micro - RP2040, Blok, and Bit-C PRO :id=promicro_rp2040
+### SparkFun Pro Micro - RP2040, Blok, Bit-C PRO, and Elite-Pi :id=promicro_rp2040
-Currently identical to [Adafruit KB2040](#kb2040).
+Currently identical to [Adafruit KB2040](#kb2040).
### STeMCell :id=stemcell
@@ -135,4 +157,28 @@ The Bonsai C4 only has one on-board LED (B2), and by default, both the Pro Micro
#define B0 PAL_LINE(GPIOA, 9)
```
-No peripherals are enabled by default at this time, but example code to enable SPI, I2C, PWM, and Serial communications can be found [here](/keyboards/custommk/bonsai_c4_template) \ No newline at end of file
+No peripherals are enabled by default at this time, but example code to enable SPI, I2C, PWM, and Serial communications can be found [here](/keyboards/custommk/bonsai_c4_template).
+
+## Elite-C
+
+If a board currently supported in QMK uses an [Elite-C](https://keeb.io/products/elite-c-low-profile-version-usb-c-pro-micro-replacement-atmega32u4), the supported alternative controllers are:
+
+| Device | Target |
+|----------------------------------------------------------------------------------|-------------------|
+| [STeMCell](https://github.com/megamind4089/STeMCell) | `stemcell` |
+| [Elite-Pi](https://keeb.io/products/elite-pi-usb-c-pro-micro-replacement-rp2040) | `elite_pi` |
+
+Converter summary:
+
+| Target | Argument | `rules.mk` | Condition |
+|-------------------|---------------------------------|------------------------------|-------------------------------------|
+| `stemcell` | `-e CONVERT_TO=stemcell` | `CONVERT_TO=stemcell` | `#ifdef CONVERT_TO_STEMCELL` |
+| `elite_pi` | `-e CONVERT_TO=elite_pi` | `CONVERT_TO=elite_pi` | `#ifdef CONVERT_TO_ELITE_PI` |
+
+### STeMCell :id=stemcell_elite
+
+Currently identical to [STeMCell](#stemcell) with support for the additional bottom row of pins.
+
+### Elite-Pi :id=elite_pi
+
+Currently identical to [Adafruit KB2040](#kb2040), with support for the additional bottom row of pins.
diff --git a/docs/feature_eeprom.md b/docs/feature_eeprom.md
index e261c455cb..088f4f36ff 100644
--- a/docs/feature_eeprom.md
+++ b/docs/feature_eeprom.md
@@ -40,7 +40,7 @@ void keyboard_post_init_user(void) {
// Set default layer, if enabled
if (user_config.rgb_layer_change) {
rgblight_enable_noeeprom();
- rgblight_sethsv_noeeprom_cyan();
+ rgblight_sethsv_noeeprom(HSV_CYAN);
rgblight_mode_noeeprom(1);
}
}
@@ -51,19 +51,19 @@ The above function will use the EEPROM config immediately after reading it, to s
layer_state_t layer_state_set_user(layer_state_t state) {
switch (get_highest_layer(state)) {
case _RAISE:
- if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_magenta(); rgblight_mode_noeeprom(1); }
+ if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom(HSV_MAGENTA); rgblight_mode_noeeprom(1); }
break;
case _LOWER:
- if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_red(); rgblight_mode_noeeprom(1); }
+ if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom(HSV_RED); rgblight_mode_noeeprom(1); }
break;
case _PLOVER:
- if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_green(); rgblight_mode_noeeprom(1); }
+ if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom(HSV_GREEN); rgblight_mode_noeeprom(1); }
break;
case _ADJUST:
- if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_white(); rgblight_mode_noeeprom(1); }
+ if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom(HSV_WHITE); rgblight_mode_noeeprom(1); }
break;
default: // for any other layers, or the default layer
- if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_cyan(); rgblight_mode_noeeprom(1); }
+ if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom(HSV_CYAN); rgblight_mode_noeeprom(1); }
break;
}
return state;
@@ -109,7 +109,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
}
```
-And lastly, you want to add the `eeconfig_init_user` function, so that when the EEPROM is reset, you can specify default values, and even custom actions. To force an EEPROM reset, use the `EEP_RST` keycode or [Bootmagic Lite](feature_bootmagic.md) functionallity. For example, if you want to set rgb layer indication by default, and save the default valued.
+And lastly, you want to add the `eeconfig_init_user` function, so that when the EEPROM is reset, you can specify default values, and even custom actions. To force an EEPROM reset, use the `EE_CLR` keycode or [Bootmagic Lite](feature_bootmagic.md) functionallity. For example, if you want to set rgb layer indication by default, and save the default valued.
```c
void eeconfig_init_user(void) { // EEPROM is getting reset!
@@ -119,7 +119,7 @@ void eeconfig_init_user(void) { // EEPROM is getting reset!
// use the non noeeprom versions, to write these values to EEPROM too
rgblight_enable(); // Enable RGB by default
- rgblight_sethsv_cyan(); // Set it to CYAN by default
+ rgblight_sethsv(HSV_CYAN); // Set it to CYAN by default
rgblight_mode(1); // set to solid by default
}
```
diff --git a/docs/feature_encoders.md b/docs/feature_encoders.md
index 2e4a4fe324..60b613d6a5 100644
--- a/docs/feature_encoders.md
+++ b/docs/feature_encoders.md
@@ -90,6 +90,14 @@ const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
?> This should only be enabled at the keymap level.
+Using encoder mapping pumps events through the normal QMK keycode processing pipeline, resulting in a _keydown/keyup_ combination pushed through `process_record_xxxxx()`. To configure the amount of time between the encoder "keyup" and "keydown", you can add the following to your `config.h`:
+
+```c
+#define ENCODER_MAP_KEY_DELAY 10
+```
+
+?> By default, the encoder map delay matches the value of `TAP_CODE_DELAY`.
+
## Callbacks
When not using `ENCODER_MAP_ENABLE = yes`, the callback functions can be inserted into your `<keyboard>.c`:
@@ -121,7 +129,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) {
}
```
-!> If you return `true`, it will allow the keyboard level code to run as well. Returning `false` will override the keyboard level code, depending on how the keyboard function is set up.
+!> If you return `true`, it will allow the keyboard level code to run as well. Returning `false` will override the keyboard level code, depending on how the keyboard function is set up.
Layer conditions can also be used with the callback function like the following:
@@ -174,7 +182,7 @@ The A an B lines of the encoders should be wired directly to the MCU, and the C/
Multiple encoders may share pins so long as each encoder has a distinct pair of pins when the following conditions are met:
- using detent encoders
- pads must be high at the detent stability point which is called 'default position' in QMK
-- no more than two encoders sharing a pin can be turned at the same time
+- no more than two encoders sharing a pin can be turned at the same time
For example you can support two encoders using only 3 pins like this
```
@@ -187,4 +195,4 @@ You could even support three encoders using only three pins (one per encoder) ho
#define ENCODERS_PAD_A { B1, B1, B2 }
#define ENCODERS_PAD_B { B2, B3, B3 }
```
-Here rotating Encoder 0 `B1 B2` and Encoder 1 `B1 B3` could be interpreted as rotating Encoder 2 `B2 B3` or `B3 B2` depending on the timing. This may still be a useful configuration depending on your use case
+Here rotating Encoder 0 `B1 B2` and Encoder 1 `B1 B3` could be interpreted as rotating Encoder 2 `B2 B3` or `B3 B2` depending on the timing. This may still be a useful configuration depending on your use case
diff --git a/docs/feature_joystick.md b/docs/feature_joystick.md
index 2635298587..a5e4921f9b 100644
--- a/docs/feature_joystick.md
+++ b/docs/feature_joystick.md
@@ -70,71 +70,44 @@ When the ADC reads 900 or higher, the returned axis value will be -127, whereas
In this example, the first axis will be read from the `A4` pin while `B0` is set high and `A7` is set low, using `analogReadPin()`, whereas the second axis will not be read.
-In order to give a value to the second axis, you can do so in any customizable entry point: as an action, in `process_record_user()` or in `matrix_scan_user()`, or even in `joystick_task()` which is called even when no key has been pressed.
-You assign a value by writing to `joystick_status.axes[axis_index]` a signed 8-bit value (ranging from -127 to 127). Then it is necessary to assign the flag `JS_UPDATED` to `joystick_status.status` in order for an updated HID report to be sent.
+#### Virtual Axes
-The following example writes two axes based on keypad presses, with `KC_P5` as a precision modifier:
+To give a value to virtual axes, call `joystick_set_axis(axis, value)`.
+
+The following example adjusts two virtual axes (X and Y) based on keypad presses, with `KC_P5` as a precision modifier:
```c
-#ifdef ANALOG_JOYSTICK_ENABLE
-static uint8_t precision_val = 70;
-static uint8_t axesFlags = 0;
-enum axes {
- Precision = 1,
- Axis1High = 2,
- Axis1Low = 4,
- Axis2High = 8,
- Axis2Low = 16
+joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT] = {
+ [0] = JOYSTICK_AXIS_VIRTUAL, // x
+ [1] = JOYSTICK_AXIS_VIRTUAL // y
};
-#endif
+
+static bool precision = false;
+static uint16_t precision_mod = 64;
+static uint16_t axis_val = 127;
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
- switch(keycode) {
-#ifdef ANALOG_JOYSTICK_ENABLE
- // virtual joystick
-# if JOYSTICK_AXES_COUNT > 1
+ int16_t precision_val = axis_val;
+ if (precision) {
+ precision_val -= precision_mod;
+ }
+
+ switch (keycode) {
case KC_P8:
- if (record->event.pressed) {
- axesFlags |= Axis2Low;
- } else {
- axesFlags &= ~Axis2Low;
- }
- joystick_status.status |= JS_UPDATED;
- break;
+ joystick_set_axis(1, record->event.pressed ? -precision_val : 0);
+ return false;
case KC_P2:
- if (record->event.pressed) {
- axesFlags |= Axis2High;
- } else {
- axesFlags &= ~Axis2High;
- }
- joystick_status.status |= JS_UPDATED;
- break;
-# endif
+ joystick_set_axis(1, record->event.pressed ? precision_val : 0);
+ return false;
case KC_P4:
- if (record->event.pressed) {
- axesFlags |= Axis1Low;
- } else {
- axesFlags &= ~Axis1Low;
- }
- joystick_status.status |= JS_UPDATED;
- break;
+ joystick_set_axis(0, record->event.pressed ? -precision_val : 0);
+ return false;
case KC_P6:
- if (record->event.pressed) {
- axesFlags |= Axis1High;
- } else {
- axesFlags &= ~Axis1High;
- }
- joystick_status.status |= JS_UPDATED;
- break;
+ joystick_set_axis(0, record->event.pressed ? precision_val : 0);
+ return false;
case KC_P5:
- if (record->event.pressed) {
- axesFlags |= Precision;
- } else {
- axesFlags &= ~Precision;
- }
- joystick_status.status |= JS_UPDATED;
- break;
-#endif
+ precision = record->event.pressed;
+ return false;
}
return true;
}
@@ -146,9 +119,41 @@ By default, the resolution of each axis is 8 bit, giving a range of -127 to +127
Note that the supported AVR MCUs have a 10-bit ADC, and 12-bit for most STM32 MCUs.
-### Triggering Joystick Buttons
-
-Joystick buttons are normal Quantum keycodes, defined as `JS_BUTTON0` to `JS_BUTTON31`, depending on the number of buttons you have configured.
-To trigger a joystick button, just add the corresponding keycode to your keymap.
+### Keycodes
+
+|Key |Aliases|Description|
+|-----------------------|-------|-----------|
+|`QK_JOYSTICK_BUTTON_0` |`JS_0` |Button 0 |
+|`QK_JOYSTICK_BUTTON_1` |`JS_1` |Button 1 |
+|`QK_JOYSTICK_BUTTON_2` |`JS_2` |Button 2 |
+|`QK_JOYSTICK_BUTTON_3` |`JS_3` |Button 3 |
+|`QK_JOYSTICK_BUTTON_4` |`JS_4` |Button 4 |
+|`QK_JOYSTICK_BUTTON_5` |`JS_5` |Button 5 |
+|`QK_JOYSTICK_BUTTON_6` |`JS_6` |Button 6 |
+|`QK_JOYSTICK_BUTTON_7` |`JS_7` |Button 7 |
+|`QK_JOYSTICK_BUTTON_8` |`JS_8` |Button 8 |
+|`QK_JOYSTICK_BUTTON_9` |`JS_9` |Button 9 |
+|`QK_JOYSTICK_BUTTON_10`|`JS_10`|Button 10 |
+|`QK_JOYSTICK_BUTTON_11`|`JS_11`|Button 11 |
+|`QK_JOYSTICK_BUTTON_12`|`JS_12`|Button 12 |
+|`QK_JOYSTICK_BUTTON_13`|`JS_13`|Button 13 |
+|`QK_JOYSTICK_BUTTON_14`|`JS_14`|Button 14 |
+|`QK_JOYSTICK_BUTTON_15`|`JS_15`|Button 15 |
+|`QK_JOYSTICK_BUTTON_16`|`JS_16`|Button 16 |
+|`QK_JOYSTICK_BUTTON_17`|`JS_17`|Button 17 |
+|`QK_JOYSTICK_BUTTON_18`|`JS_18`|Button 18 |
+|`QK_JOYSTICK_BUTTON_19`|`JS_19`|Button 19 |
+|`QK_JOYSTICK_BUTTON_20`|`JS_20`|Button 20 |
+|`QK_JOYSTICK_BUTTON_21`|`JS_21`|Button 21 |
+|`QK_JOYSTICK_BUTTON_22`|`JS_22`|Button 22 |
+|`QK_JOYSTICK_BUTTON_23`|`JS_23`|Button 23 |
+|`QK_JOYSTICK_BUTTON_24`|`JS_24`|Button 24 |
+|`QK_JOYSTICK_BUTTON_25`|`JS_25`|Button 25 |
+|`QK_JOYSTICK_BUTTON_26`|`JS_26`|Button 26 |
+|`QK_JOYSTICK_BUTTON_27`|`JS_27`|Button 27 |
+|`QK_JOYSTICK_BUTTON_28`|`JS_28`|Button 28 |
+|`QK_JOYSTICK_BUTTON_29`|`JS_29`|Button 29 |
+|`QK_JOYSTICK_BUTTON_30`|`JS_30`|Button 30 |
+|`QK_JOYSTICK_BUTTON_31`|`JS_31`|Button 31 |
You can also trigger joystick buttons in code with `register_joystick_button(button)` and `unregister_joystick_button(button)`, where `button` is the 0-based button index (0 = button 1).
diff --git a/docs/feature_key_lock.md b/docs/feature_key_lock.md
index 1b02c7c291..1acee524da 100644
--- a/docs/feature_key_lock.md
+++ b/docs/feature_key_lock.md
@@ -2,17 +2,17 @@
Sometimes you may find yourself needing to hold down a specific key for a long period of time. Key Lock holds down the next key you press for you. Press it again, and it will be released.
-Let's say you need to type in ALL CAPS for a few sentences. Hit `KC_LOCK`, and then Shift. Now, Shift will be considered held until you tap it again. You can think of Key Lock as Caps Lock, but supercharged.
+Let's say you need to type in ALL CAPS for a few sentences. Hit `QK_LOCK`, and then Shift. Now, Shift will be considered held until you tap it again. You can think of Key Lock as Caps Lock, but supercharged.
## Usage
-First, enable Key Lock by setting `KEY_LOCK_ENABLE = yes` in your `rules.mk`. Then pick a key in your keymap and assign it the keycode `KC_LOCK`.
+First, enable Key Lock by setting `KEY_LOCK_ENABLE = yes` in your `rules.mk`. Then pick a key in your keymap and assign it the keycode `QK_LOCK`.
## Keycodes
|Keycode |Description |
|---------|--------------------------------------------------------------|
-|`KC_LOCK`|Hold down the next key pressed, until the key is pressed again|
+|`QK_LOCK`|Hold down the next key pressed, until the key is pressed again|
## Caveats
diff --git a/docs/feature_key_overrides.md b/docs/feature_key_overrides.md
index 2417fcf594..36fd383cd4 100644
--- a/docs/feature_key_overrides.md
+++ b/docs/feature_key_overrides.md
@@ -150,15 +150,13 @@ const key_override_t fn_override = {.trigger_mods = MOD_BIT(KC_RGUI) |
.enabled = NULL};
```
-## Keycodes
+## Keycodes
-You can enable, disable and toggle all key overrides on the fly.
-
-|Keycode |Description |Function Equivalent|
-|----------|---------------------------------|--------|
-|`KEY_OVERRIDE_ON` |Turns on Key Override feature | `key_override_on(void)`|
-|`KEY_OVERRIDE_OFF` |Turns off Key Override feature |`key_override_off(void)`|
-|`KEY_OVERRIDE_TOGGLE` |Toggles Key Override feature on and off |`key_override_toggle(void)`|
+|Keycode |Aliases |Description |
+|------------------------|---------|----------------------|
+|`QK_KEY_OVERRIDE_TOGGLE`|`KO_TOGG`|Toggle key overrides |
+|`QK_KEY_OVERRIDE_ON` |`KO_ON` |Turn on key overrides |
+|`QK_KEY_OVERRIDE_OFF` |`KO_OFF` |Turn off key overrides|
## Reference for `key_override_t`
diff --git a/docs/feature_leader_key.md b/docs/feature_leader_key.md
index e5b1e7a4d9..e285d10597 100644
--- a/docs/feature_leader_key.md
+++ b/docs/feature_leader_key.md
@@ -2,11 +2,11 @@
If you've ever used Vim, you know what a Leader key is. If not, you're about to discover a wonderful concept. :) Instead of hitting Alt+Shift+W for example (holding down three keys at the same time), what if you could hit a _sequence_ of keys instead? So you'd hit our special modifier (the Leader key), followed by W and then C (just a rapid succession of keys), and something would happen.
-That's what `KC_LEAD` does. Here's an example:
+That's what `QK_LEAD` does. Here's an example:
-1. Pick a key on your keyboard you want to use as the Leader key. Assign it the keycode `KC_LEAD`. This key would be dedicated just for this -- it's a single action key, can't be used for anything else.
-2. Include the line `#define LEADER_TIMEOUT 300` in your `config.h`. This sets the timeout for the `KC_LEAD` key. Specifically, when you press the `KC_LEAD` key, you only have a certain amount of time to complete the Leader Key sequence. The `300` here sets that to 300ms, and you can increase this value to give you more time to hit the sequence. But any keys pressed during this timeout are intercepted and not sent, so you may want to keep this value low.
- * By default, this timeout is how long after pressing `KC_LEAD` to complete your entire sequence. This may be very low for some people. So you may want to increase this timeout. Optionally, you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped. This allows you to maintain a low value here, but still be able to use the longer sequences. To enable this option, add `#define LEADER_PER_KEY_TIMING` to your `config.h`.
+1. Pick a key on your keyboard you want to use as the Leader key. Assign it the keycode `QK_LEAD`. This key would be dedicated just for this -- it's a single action key, can't be used for anything else.
+2. Include the line `#define LEADER_TIMEOUT 300` in your `config.h`. This sets the timeout for the `QK_LEAD` key. Specifically, when you press the `QK_LEAD` key, you only have a certain amount of time to complete the Leader Key sequence. The `300` here sets that to 300ms, and you can increase this value to give you more time to hit the sequence. But any keys pressed during this timeout are intercepted and not sent, so you may want to keep this value low.
+ * By default, this timeout is how long after pressing `QK_LEAD` to complete your entire sequence. This may be very low for some people. So you may want to increase this timeout. Optionally, you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped. This allows you to maintain a low value here, but still be able to use the longer sequences. To enable this option, add `#define LEADER_PER_KEY_TIMING` to your `config.h`.
3. Within your `matrix_scan_user` function, add something like this:
```c
@@ -95,7 +95,7 @@ While, this may be fine for most, if you want to specify the whole keycode (eg,
The Leader Key feature has some additional customization to how the Leader Key feature works. It has two functions that can be called at certain parts of the process. Namely `leader_start()` and `leader_end()`.
-The `leader_start()` function is called when you tap the `KC_LEAD` key, and the `leader_end()` function is called when either the leader sequence is completed, or the leader timeout is hit.
+The `leader_start()` function is called when you tap the `QK_LEAD` key, and the `leader_end()` function is called when either the leader sequence is completed, or the leader timeout is hit.
You can add these functions to your code (`keymap.c` usually) to add feedback to the Leader sequences (such as beeping or playing music).
@@ -111,7 +111,7 @@ void leader_end(void) {
### Example
-This example will play the Mario "One Up" sound when you hit `KC_LEAD` to start the Leader Sequence, and will play "All Star" if it completes successfully or "Rick Roll" you if it fails.
+This example will play the Mario "One Up" sound when you hit `QK_LEAD` to start the Leader Sequence, and will play "All Star" if it completes successfully or "Rick Roll" you if it fails.
```c
bool did_leader_succeed;
diff --git a/docs/feature_led_indicators.md b/docs/feature_led_indicators.md
index a2a2e17c6f..d89562a377 100644
--- a/docs/feature_led_indicators.md
+++ b/docs/feature_led_indicators.md
@@ -101,6 +101,13 @@ The `host_keyboard_led_state()` function will report the LED state returned from
bool caps = host_keyboard_led_state().caps_lock;
```
+## `led_update_ports()`
+
+This function writes the LED state to the actual hardware. Call it manually
+from your `led_update_*()` callbacks to modify the handling of the standard
+keyboard LEDs.
+For example when repurposing a standard LED indicator as layer indicator.
+
## Setting Physical LED State
Some keyboard implementations provide convenient methods for setting the state of the physical LEDs.
diff --git a/docs/feature_led_matrix.md b/docs/feature_led_matrix.md
index 563fa149a2..280db2a383 100644
--- a/docs/feature_led_matrix.md
+++ b/docs/feature_led_matrix.md
@@ -22,7 +22,7 @@ You can use between 1 and 4 IS31FL3731 IC's. Do not specify `LED_DRIVER_ADDR_<N>
| `ISSI_TIMEOUT` | (Optional) How long to wait for i2c messages, in milliseconds | 100 |
| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 |
| `LED_DRIVER_COUNT` | (Required) How many LED driver IC's are present | |
-| `DRIVER_LED_TOTAL` | (Required) How many LED lights are present across all drivers | |
+| `LED_MATRIX_LED_COUNT` | (Required) How many LED lights are present across all drivers | |
| `LED_DRIVER_ADDR_1` | (Required) Address for the first LED driver | |
| `LED_DRIVER_ADDR_2` | (Optional) Address for the second LED driver | |
| `LED_DRIVER_ADDR_3` | (Optional) Address for the third LED driver | |
@@ -44,17 +44,17 @@ Here is an example using 2 drivers.
#define LED_DRIVER_COUNT 2
#define LED_DRIVER_1_LED_TOTAL 25
#define LED_DRIVER_2_LED_TOTAL 24
-#define DRIVER_LED_TOTAL (LED_DRIVER_1_LED_TOTAL + LED_DRIVER_2_LED_TOTAL)
+#define LED_MATRIX_LED_COUNT (LED_DRIVER_1_LED_TOTAL + LED_DRIVER_2_LED_TOTAL)
```
-!> Note the parentheses, this is so when `LED_DRIVER_LED_TOTAL` is used in code and expanded, the values are added together before any additional math is applied to them. As an example, `rand() % (LED_DRIVER_1_LED_TOTAL + LED_DRIVER_2_LED_TOTAL)` will give very different results than `rand() % LED_DRIVER_1_LED_TOTAL + LED_DRIVER_2_LED_TOTAL`.
+!> Note the parentheses, this is so when `LED_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() % (LED_DRIVER_1_LED_TOTAL + LED_DRIVER_2_LED_TOTAL)` will give very different results than `rand() % LED_DRIVER_1_LED_TOTAL + LED_DRIVER_2_LED_TOTAL`.
For split keyboards using `LED_MATRIX_SPLIT` with an LED driver, you can either have the same driver address or different driver addresses. If using different addresses, use `DRIVER_ADDR_1` for one and `DRIVER_ADDR_2` for the other one. Then, in `g_is31_leds`, fill out the correct driver index (0 or 1). If using one address, use `DRIVER_ADDR_1` for both, and use index 0 for `g_is31_leds`.
Define these arrays listing all the LEDs in your `<keyboard>.c`:
```c
-const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = {
+const is31_led PROGMEM g_is31_leds[LED_MATRIX_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | LED address
@@ -95,7 +95,7 @@ Configure the hardware via your `config.h`:
| `ISSI_TIMEOUT` | (Optional) How long to wait for i2c messages, in milliseconds | 100 |
| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 |
| `DRIVER_COUNT` | (Required) How many LED driver IC's are present | |
-| `DRIVER_LED_TOTAL` | (Required) How many LED lights are present across all drivers | |
+| `LED_MATRIX_LED_COUNT` | (Required) How many LED lights are present across all drivers | |
| `DRIVER_ADDR_1` | (Optional) Address for the first LED driver | |
| `DRIVER_ADDR_<N>` | (Required) Address for the additional LED drivers | |
| `ISSI_SSR_<N>` | (Optional) Configuration for the Spread Spectrum Register | |
@@ -130,16 +130,16 @@ Here is an example using 2 drivers.
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 66
#define DRIVER_2_LED_TOTAL 42
-#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+#define LED_MATRIX_LED_COUNT (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
```
-!> Note the parentheses, this is so when `DRIVER_LED_TOTAL` 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`.
+!> Note the parentheses, this is so when `LED_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 4 drivers are supported, but it would be trivial to support for more. Note that using a combination of different drivers is not supported. All drivers must be of the same model.
Define these arrays listing all the LEDs in your `<keyboard>.c`:
```c
-const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = {
+const is31_led __flash g_is31_leds[LED_MATRIX_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | LED address
@@ -364,10 +364,9 @@ For inspiration and examples, check out the built-in effects under `quantum/led_
#define LED_MATRIX_KEYPRESSES // reacts to keypresses
#define LED_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
#define LED_MATRIX_FRAMEBUFFER_EFFECTS // enable framebuffer effects
-#define LED_DISABLE_TIMEOUT 0 // number of milliseconds to wait until led automatically turns off
-#define LED_DISABLE_AFTER_TIMEOUT 0 // OBSOLETE: number of ticks to wait until disabling effects
+#define LED_MATRIX_TIMEOUT 0 // number of milliseconds to wait until led automatically turns off
#define LED_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
-#define LED_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
+#define LED_MATRIX_LED_PROCESS_LIMIT (LED_MATRIX_LED_COUNT + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
#define LED_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define LED_MATRIX_MAXIMUM_BRIGHTNESS 255 // limits maximum brightness of LEDs
#define LED_MATRIX_STARTUP_MODE LED_MATRIX_SOLID // Sets the default mode, if none has been set
@@ -391,7 +390,7 @@ Where `28` is an unused index from `eeconfig.h`.
|Function |Description |
|--------------------------------------------|-------------|
|`led_matrix_set_value_all(v)` |Set all of the LEDs to the given value, where `v` is between 0 and 255 (not written to EEPROM) |
-|`led_matrix_set_value(index, v)` |Set a single LED to the given value, where `v` is between 0 and 255, and `index` is between 0 and `DRIVER_LED_TOTAL` (not written to EEPROM) |
+|`led_matrix_set_value(index, v)` |Set a single LED to the given value, where `v` is between 0 and 255, and `index` is between 0 and `LED_MATRIX_LED_COUNT` (not written to EEPROM) |
### Disable/Enable Effects :id=disable-enable-effects
|Function |Description |
@@ -442,8 +441,12 @@ Where `28` is an unused index from `eeconfig.h`.
If you want to set custom indicators, such as an LED for Caps Lock, or layer indication, you can use the `led_matrix_indicators_kb` or `led_matrix_indicators_user` function for that:
```c
-void led_matrix_indicators_kb(void) {
+bool led_matrix_indicators_kb(void) {
+ if (!led_matrix_indicators_user()) {
+ return false;
+ }
led_matrix_set_value(index, value);
+ return true;
}
```
@@ -452,5 +455,6 @@ In addition, there are the advanced indicator functions. These are aimed at tho
```c
void led_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
LED_MATRIX_INDICATOR_SET_VALUE(index, value);
+ return false;
}
```
diff --git a/docs/feature_mouse_keys.md b/docs/feature_mouse_keys.md
index 8e474c4245..eed4f4f4aa 100644
--- a/docs/feature_mouse_keys.md
+++ b/docs/feature_mouse_keys.md
@@ -48,8 +48,9 @@ Mouse keys supports three different modes to move the cursor:
* **Kinetic:** Holding movement keys accelerates the cursor with its speed following a quadratic curve until it reaches its maximum speed.
* **Constant:** Holding movement keys moves the cursor at constant speeds.
* **Combined:** Holding movement keys accelerates the cursor until it reaches its maximum speed, but holding acceleration and movement keys simultaneously moves the cursor at constant speeds.
+* **Inertia:** Cursor accelerates when key held, and decelerates after key release. Tracks X and Y velocity separately for more nuanced movements. Applies to cursor only, not scrolling.
-The same principle applies to scrolling.
+The same principle applies to scrolling, in most modes.
Configuration options that are times, intervals or delays are given in milliseconds. Scroll speed is given as multiples of the default scroll step. For example, a scroll speed of 8 means that each scroll action covers 8 times the length of the default scroll step as defined by your operating system or application.
@@ -170,6 +171,37 @@ To use combined speed mode, you must at least define `MK_COMBINED` in your keyma
#define MK_COMBINED
```
+### Inertia mode
+
+This mode provides smooth motion, like sliding on ice. The cursor accelerates
+along a quadratic curve while a key is held, then glides to a stop after the
+key is released. Vertical and horizontal movements are tracked independently,
+so the cursor can move in many directions and make curves.
+
+Cannot be used at the same time as Kinetic mode, Constant mode, or Combined mode.
+
+Recommended settings in your keymap’s `config.h` file:
+
+|Define |Default |Description |
+|----------------------------|---------|-----------------------------------------------------------|
+|`MOUSEKEY_INERTIA` |undefined|Enable Inertia mode |
+|`MOUSEKEY_DELAY` |150 |Delay between pressing a movement key and cursor movement |
+|`MOUSEKEY_INTERVAL` |16 |Time between cursor movements in milliseconds (16 = 60fps) |
+|`MOUSEKEY_MAX_SPEED` |32 |Maximum cursor speed at which acceleration stops |
+|`MOUSEKEY_TIME_TO_MAX` |32 |Number of frames until maximum cursor speed is reached |
+|`MOUSEKEY_FRICTION` |24 |How quickly the cursor stops after releasing a key |
+|`MOUSEKEY_MOVE_DELTA` |1 |How much to move on first frame (1 strongly recommended) |
+
+Tips:
+
+* Set `MOUSEKEY_DELAY` to roughly the same value as your host computer's key repeat delay, in ms. Recommended values are 100 to 300.
+* Set `MOUSEKEY_INTERVAL` to a value of 1000 / your monitor's FPS. For 60 FPS, 1000/60 = 16.
+* Set `MOUSEKEY_MAX_SPEED` based on your screen resolution and refresh rate, like Width / FPS. For example, 1920 pixels / 60 FPS = 32 pixels per frame.
+* Set `MOUSEKEY_TIME_TO_MAX` to a value of approximately FPS / 2, to make it reach full speed in half a second (or so).
+* Set `MOUSEKEY_FRICTION` to something between 1 and 255. Lower makes the cursor glide longer. Values from 8 to 40 are the most effective.
+* Keep `MOUSEKEY_MOVE_DELTA` at 1. This allows precise movements before the gliding effect starts.
+* Mouse wheel options are the same as the default accelerated mode, and do not use inertia.
+
## Use with PS/2 Mouse and Pointing Device
Mouse keys button state is shared with [PS/2 mouse](feature_ps2_mouse.md) and [pointing device](feature_pointing_device.md) so mouse keys button presses can be used for clicks and drags.
diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md
index 999dd1272d..0771203cdd 100644
--- a/docs/feature_pointing_device.md
+++ b/docs/feature_pointing_device.md
@@ -93,20 +93,20 @@ This supports the Cirque Pinnacle 1CA027 Touch Controller, which is used in the
#### Common settings
-| Setting | Description | Default |
-| -------------------------------- | ---------------------------------------------------------- | ------------------ |
-| `CIRQUE_PINNACLE_DIAMETER_MM` | (Optional) Diameter of the trackpad sensor in millimeters. | `40` |
-| `CIRQUE_PINNACLE_ATTENUATION` | (Optional) Sets the attenuation of the sensor data. | `ADC_ATTENUATE_4X` |
-| `CIRQUE_PINNACLE_CURVED_OVERLAY` | (Optional) Applies settings tuned for curved overlay. | _not defined_ |
-| `CIRQUE_PINNACLE_POSITION_MODE` | (Optional) Mode of operation. | _not defined_ |
+| Setting | Description | Default |
+| -------------------------------- | ---------------------------------------------------------- | ------------------------------------------- |
+| `CIRQUE_PINNACLE_DIAMETER_MM` | (Optional) Diameter of the trackpad sensor in millimeters. | `40` |
+| `CIRQUE_PINNACLE_ATTENUATION` | (Optional) Sets the attenuation of the sensor data. | `EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_4X` |
+| `CIRQUE_PINNACLE_CURVED_OVERLAY` | (Optional) Applies settings tuned for curved overlay. | _not defined_ |
+| `CIRQUE_PINNACLE_POSITION_MODE` | (Optional) Mode of operation. | _not defined_ |
**`CIRQUE_PINNACLE_ATTENUATION`** is a measure of how much data is suppressed in regards to sensitivity. The higher the attenuation, the less sensitive the touchpad will be.
Default attenuation is set to 4X, although if you are using a thicker overlay (such as the curved overlay) you will want a lower attenuation such as 2X. The possible values are:
-* `ADC_ATTENUATE_4X`: Least sensitive
-* `ADC_ATTENUATE_3X`
-* `ADC_ATTENUATE_2X`
-* `ADC_ATTENUATE_1X`: Most sensitive
+* `EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_4X`: Least sensitive
+* `EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_3X`
+* `EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_2X`
+* `EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_1X`: Most sensitive
**`CIRQUE_PINNACLE_POSITION_MODE`** can be `CIRQUE_PINNACLE_ABSOLUTE_MODE` or `CIRQUE_PINNACLE_RELATIVE_MODE`. Modes differ in supported features/gestures.
@@ -289,6 +289,7 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
| `POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ |
| `POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ |
| `POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ |
+| `POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW` | (Optional) If defined then the motion pin is active-low. | _varies_ |
| `POINTING_DEVICE_TASK_THROTTLE_MS` | (Optional) Limits the frequency that the sensor is polled for motion. | _not defined_ |
| `POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE` | (Optional) Enable inertial cursor. Cursor continues moving after a flick gesture and slows down by kinetic friction. | _not defined_ |
| `POINTING_DEVICE_GESTURES_SCROLL_ENABLE` | (Optional) Enable scroll gesture. The gesture that activates the scroll is device dependent. | _not defined_ |
@@ -345,7 +346,7 @@ The combined functions below are only available when using `SPLIT_POINTING_ENABL
| Function | Description |
| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `pointing_device_set_shared_report(mouse_report)` | Sets the shared mouse report to the assigned `mouse_report_t` data structured passed to the function. |
-| `pointing_device_set_cpi_on_side(bool, uint16_t)` | Sets the CPI/DPI of one side, if supported. Passing `true` will set the left and `false` the right` |
+| `pointing_device_set_cpi_on_side(bool, uint16_t)` | Sets the CPI/DPI of one side, if supported. Passing `true` will set the left and `false` the right |
| `pointing_device_combine_reports(left_report, right_report)` | Returns a combined mouse_report of left_report and right_report (as a `mouse_report_t` data structure) |
| `pointing_device_task_combined_kb(left_report, right_report)` | Callback, so keyboard code can intercept and modify the data. Returns a combined mouse report. |
| `pointing_device_task_combined_user(left_report, right_report)` | Callback, so user code can intercept and modify. Returns a combined mouse report using `pointing_device_combine_reports` |
@@ -487,3 +488,243 @@ report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, re
return pointing_device_combine_reports(left_report, right_report);
}
```
+
+# Troubleshooting
+
+If you are having issues with pointing device drivers debug messages can be enabled that will give you insights in the inner workings. To enable these add to your keyboards `config.h` file:
+
+```c
+#define POINTING_DEVICE_DEBUG
+```
+
+?> The messages will be printed out to the `CONSOLE` output. For additional information, refer to [Debugging/Troubleshooting QMK](faq_debug.md).
+
+
+---
+# Automatic Mouse Layer :id=pointing-device-auto-mouse
+
+When using a pointing device combined with a keyboard the mouse buttons are often kept on a separate layer from the default keyboard layer, which requires pressing or holding a key to change layers before using the mouse. To make this easier and more efficient an additional pointing device feature may be enabled that will automatically activate a target layer as soon as the pointing device is active _(in motion, mouse button pressed etc.)_ and deactivate the target layer after a set time.
+
+Additionally if any key that is defined as a mouse key is pressed then the layer will be held as long as the key is pressed and the timer will be reset on key release. When a non-mouse key is pressed then the layer is deactivated early _(with some exceptions see below)_. Mod, mod tap, and one shot mod keys are ignored _(i.e. don't hold or activate layer but do not deactivate the layer either)_ when sending a modifier keycode _(e.g. hold for mod tap)_ allowing for mod keys to be used with the mouse without activating the target layer when typing.
+
+All of the standard layer keys (tap toggling, toggle, toggle on, one_shot, layer tap, layer mod) that activate the current target layer are uniquely handled to ensure they behave as expected _(see layer key table below)_. The target layer that can be changed at any point during by calling the `set_auto_mouse_layer(<new_target_layer>);` function.
+
+### Behaviour of Layer keys that activate the target layer
+| Layer key as in `keymap.c` | Auto Mouse specific behaviour |
+| -------------------------- | --------------------------------------------------------------------------------------------------------------------- |
+| `MO(<target_layer>)` | Treated as a mouse key holding the layer while pressed |
+| `LT(<target_layer>)` | When tapped will be treated as non mouse key and mouse key when held |
+| `LM(<target_layer>)` | Treated as a mouse key |
+| `TG(<target_layer>)` | Will set flag preventing target layer deactivation or removal until pressed again |
+| `TO(<target_layer>)` | Same as `TG(<target_layer>)` |
+| `TT(<target_layer>)` | Treated as a mouse key when `tap.count < TAPPING_TOGGLE` and as `TG` when `tap.count == TAPPING_TOGGLE` |
+| `DF(<target_layer>)` | Skips auto mouse key processing similar to mod keys |
+| `OSL(<target_layer>)` | Skips, but if current one shot layer is the target layer then it will prevent target layer deactivation or removal |
+
+
+## How to enable:
+
+```c
+// in config.h:
+#define POINTING_DEVICE_AUTO_MOUSE_ENABLE
+// only required if not setting mouse layer elsewhere
+#define AUTO_MOUSE_DEFAULT_LAYER <index of your mouse layer>
+
+// in keymap.c:
+void pointing_device_init_user(void) {
+ set_auto_mouse_layer(<mouse_layer>); // only required if AUTO_MOUSE_DEFAULT_LAYER is not set to index of <mouse_layer>
+ set_auto_mouse_enable(true); // always required before the auto mouse feature will work
+}
+```
+
+Because the auto mouse feature can be disabled/enabled during runtime and starts as disabled by default it must be enabled by calling `set_auto_mouse_enable(true);` somewhere in firmware before the feature will work.
+_Note: for setting the target layer during initialization either setting `AUTO_MOUSE_DEFAULT_LAYER` in `config.h` or calling `set_auto_mouse_layer(<mouse_layer>)` can be used._
+
+
+## How to Customize:
+
+There are a few ways to control the auto mouse feature with both `config.h` options and functions for controlling it during runtime.
+
+### `config.h` Options:
+| Define | Description | Range | Units | Default |
+| ----------------------------------- | --------------------------------------------------------------------- | :------------------: | :---------: | -------------------------: |
+| `POINTING_DEVICE_AUTO_MOUSE_ENABLE` | (Required) Enables auto mouse layer feature | | _None_ | _Not defined_ |
+| `AUTO_MOUSE_DEFAULT_LAYER` | (Optional) Index of layer to use as default target layer | 0 - `LAYER_MAX` | _`uint8_t`_ | `1` |
+| `AUTO_MOUSE_TIME` | (Optional) Time layer remains active after activation | _ideally_ (250-1000) | _ms_ | `650 ms` |
+| `AUTO_MOUSE_DELAY` | (Optional) Lockout time after non-mouse key is pressed | _ideally_ (100-1000) | _ms_ | `TAPPING_TERM` or `200 ms` |
+| `AUTO_MOUSE_DEBOUNCE` | (Optional) Time delay from last activation to next update | _ideally_ (10 - 100) | _ms_ | `25 ms` |
+
+### Adding mouse keys
+
+While all default mouse keys and layer keys(for current mouse layer) are treated as mouse keys, additional Keyrecords can be added to mouse keys by adding them to the is_mouse_record_* stack.
+
+#### Callbacks for setting up additional key codes as mouse keys:
+| Callback | Description |
+| -------------------------------------------------------------------- | -------------------------------------------------- |
+| `bool is_mouse_record_kb(uint16_t keycode, keyrecord_t* record)` | keyboard level callback for adding mouse keys |
+| `bool is_mouse_record_user(uint16_t keycode, keyrecord_t* record)` | user/keymap level callback for adding mouse keys |
+
+##### To use the callback function to add mouse keys:
+
+The following code will cause the enter key and all of the arrow keys to be treated as mouse keys (hold target layer while they are pressed and reset active layer timer).
+```c
+
+// in <keyboard>.c:
+bool is_mouse_record_kb(uint16_t keycode, keyrecord_t* record) {
+ switch(keycode) {
+ case KC_ENT:
+ return true;
+ case KC_RIGHT ... KC_UP:
+ return true;
+ default:
+ return false;
+ }
+ return is_mouse_record_user(keycode, record);
+}
+```
+
+
+## Advanced control
+
+There are several functions that allow for more advanced interaction with the auto mouse feature allowing for greater control.
+
+### Functions to control auto mouse enable and target layer:
+| Function | Description | Aliases | Return type |
+| :--------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------- | --------------: |
+| `set_auto_mouse_enable(bool enable)` | Enable or disable auto mouse (true:enable, false:disable) | | `void`(None) |
+| `get_auto_mouse_enable(void)` | Return auto mouse enable state (true:enabled, false:disabled) | `AUTO_MOUSE_ENABLED` | `bool` |
+| `set_auto_mouse_layer(uint8_t LAYER)` | Change/set the target layer for auto mouse | | `void`(None) |
+| `get_auto_mouse_layer(void)` | Return auto mouse target layer index | `AUTO_MOUSE_TARGET_LAYER` | `uint8_t` |
+| `remove_auto_mouse_layer(layer_state_t state, bool force)` | Return `state` with target layer removed if appropriate (ignore criteria if `force`) | | `layer_state_t` |
+| `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` |
+
+_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._
+ - _It is recommended that `remove_auto_mouse_layer` is used in the `layer_state_set_*` stack of functions and `auto_mouse_layer_off` is used everywhere else_
+ - _`remove_auto_mouse_layer(state, false)` or `auto_mouse_layer_off()` should be called before any instance of `set_auto_mouse_enabled(false)` or `set_auto_mouse_layer(layer)` to ensure that the target layer will be removed appropriately before disabling auto mouse or changing target to avoid a stuck layer_
+
+### Functions for handling custom key events:
+| Function | Description | Return type |
+| :--------------------------------------------------------- | -------------------------------------------------------------------------------- | --------------: |
+| `auto_mouse_keyevent(bool pressed)` | Auto mouse mouse key event (true: key down, false: key up) | `void`(None) |
+| `auto_mouse_trigger_reset(bool pressed)` | Reset auto mouse status on key down and start delay timer (non-mouse key event) | `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` |
+_NOTE: Generally it would be preferable to use the `is_mouse_record_*` functions to add any additional keys that should act as mouse keys rather than adding `auto_mouse_keyevent(record.event->pressed)` to `process_records_*`_
+
+### Advanced control examples
+
+#### Disable auto mouse on certain layers:
+
+The auto mouse feature can be disabled any time and this can be helpful if you want to disable the auto mouse feature under certain circumstances such as when particular layers are active. One issue however is the handling of the target layer, it needs to be removed appropriately **before** disabling auto mouse _(see notes under control functions above)_. The following function would disable the auto_mouse feature whenever the layers `_LAYER5` through `_LAYER7` are active as the top most layer _(ignoring target layer)_.
+
+```c
+// in keymap.c:
+layer_state_t layer_state_set_user(layer_state_t state) {
+ // checks highest layer other than target layer
+ switch(get_highest_layer(remove_auto_mouse_layer(state, true))) {
+ case _LAYER5 ... _LAYER7:
+ // remove_auto_mouse_target must be called to adjust state *before* setting enable
+ state = remove_auto_mouse_layer(state, false);
+ set_auto_mouse_enable(false);
+ break;
+ default:
+ set_auto_mouse_enable(true);
+ break;
+ }
+ // recommend that any code that makes adjustment based on auto mouse layer state would go here
+ return state;
+}
+```
+
+#### Set different target layer when a particular layer is active:
+
+The below code will change the auto mouse layer target to `_MOUSE_LAYER_2` when `_DEFAULT_LAYER_2` is highest default layer state.
+*NOTE: that `auto_mouse_layer_off` is used here instead of `remove_auto_mouse_layer` as `default_layer_state_set_*` stack is separate from the `layer_state_set_*` stack* if something similar was to be done in `layer_state_set_user `state = remove_auto_mouse_layer(state, false)` should be used instead
+*ADDITIONAL NOTE: `AUTO_MOUSE_TARGET_LAYER` is checked if already set to avoid deactivating the target layer unless needed*
+
+```c
+// in keymap.c
+layer_state_t default_layer_state_set_user(layer_state_t state) {
+ // switch on change in default layer need to check if target layer already set to avoid turning off layer needlessly
+ switch(get_highest_layer(state)) {
+ case _DEFAULT_LAYER_2:
+ if ((AUTO_MOUSE_TARGET_LAYER) == _MOUSE_LAYER_2) break;
+ auto_mouse_layer_off();
+ set_auto_mouse_layer(_MOUSE_LAYER_2);
+ break;
+
+ default:
+ if((AUTO_MOUSE_TARGET_LAYER) == _MOUSE_LAYER_1) break;
+ auto_mouse_layer_off();
+ set_auto_mouse_layer(_MOUSE_LAYER_1);
+ }
+ return state;
+}
+```
+
+### Use custom keys to control auto mouse:
+Custom key records could also be created that control the auto mouse feature.
+The code example below would create a custom key that would toggle the auto mouse feature on and off when pressed while also setting a bool that could be used to disable other code that may turn it on such as the layer code above.
+
+```c
+// in config.h:
+enum user_custom_keycodes {
+ AM_Toggle = SAFE_RANGE
+};
+
+// in keymap.c:
+// set up global bool to adjust other user code
+bool auto_mouse_tg_off = !AUTO_MOUSE_ENABLED;
+
+bool process_record_user(uint16_t keycode, keyrecord_t* record) {
+ switch (keycode) {
+ // toggle auto mouse enable key
+ case AM_Toggle:
+ if(record->event.pressed) { // key down
+ auto_mouse_layer_off(); // disable target layer if needed
+ set_auto_mouse_enabled((AUTO_MOUSE_ENABLED) ^ 1);
+ auto_mouse_tg_off = !get_auto_mouse_enabled();
+ } // do nothing on key up
+ return false; // prevent further processing of keycode
+ }
+}
+```
+
+
+## Customize Target Layer Activation
+
+Layer activation can be customized by overwriting the `auto_mouse_activation` function. This function is checked every time `pointing_device_task` is called when inactive and every `AUTO_MOUSE_DEBOUNCE` ms when active, and will evaluate pointing device level conditions that trigger target layer activation. When it returns true, the target layer will be activated barring the usual exceptions _(e.g. delay time has not expired)_.
+
+By default it will return true if any of the `mouse_report` axes `x`,`y`,`h`,`v` are non zero, or if there is any mouse buttons active in `mouse_report`.
+_Note: The Cirque pinnacle track pad already implements a custom activation function that will activate on touchdown as well as movement all of the default conditions, currently this only works for the master side of split keyboards._
+
+| Function | Description | Return type |
+| :--------------------------------------------------------- | -------------------------------------------------------------------------------- | --------------: |
+| `auto_mouse_activation(report_mouse_t mouse_report)` | Overwritable function that controls target layer activation (when true) | `bool` |
+
+## Auto Mouse for Custom Pointing Device Task
+
+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) {
+ //...Custom pointing device task code
+
+ // handle automatic mouse layer (needs report_mouse_t as input)
+ pointing_device_task_auto_mouse(local_mouse_report);
+
+ //...More custom pointing device task code
+
+ pointing_device_send();
+}
+```
+
+In general the following two functions must be implemented in appropriate locations for auto mouse to function:
+
+| Function | Description | Suggested location |
+| -------------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------: |
+| `pointing_device_task_auto_mouse(report_mouse_t mouse_report)` | handles target layer activation and is_active status updates | `pointing_device_task` stack |
+| `process_auto_mouse(uint16_t keycode, keyrecord_t* record)` | Keycode processing for auto mouse | `process_record` stack |
diff --git a/docs/feature_programmable_button.md b/docs/feature_programmable_button.md
index b1ef555d16..43a9e7fc16 100644
--- a/docs/feature_programmable_button.md
+++ b/docs/feature_programmable_button.md
@@ -1,74 +1,144 @@
-## Programmable Button
+# Programmable Button :id=programmable-button
-Programmable button is a feature that can be used to send keys that have no
-predefined meaning.
-This means they can be processed on the host side by custom software without
-colliding without the operating system trying to interpret these keys.
+Programmable Buttons are keys that have no predefined meaning. This means they can be processed on the host side by custom software without the operating system trying to interpret them.
-The keycodes are emitted according to the HID usage
-"Telephony Device Page" (0x0B), "Programmable button usage" (0x07).
-On Linux (> 5.14) they are handled automatically and translated to `KEY_MACRO#`
-keycodes.
-(Up to `KEY_MACRO30`)
+The keycodes are emitted according to the HID Telephony Device page (`0x0B`), Programmable Button usage (`0x07`). On Linux (> 5.14) they are handled automatically and translated to `KEY_MACRO#` keycodes (up to `KEY_MACRO30`).
-### Enabling Programmable Button support
+?> Currently there is no known support in Windows or macOS. It may be possible to write a custom HID driver to receive these usages, but this is out of the scope of the QMK documentation.
-To enable Programmable Button, add the following line to your keymap’s `rules.mk`:
+## Usage :id=usage
-```c
+Add the following to your `rules.mk`:
+
+```make
PROGRAMMABLE_BUTTON_ENABLE = yes
```
-### Mapping
-
-In your keymap you can use the following keycodes to map key presses to Programmable Buttons:
-
-|Key |Description |
-|------------------------|----------------------|
-|`PROGRAMMABLE_BUTTON_1` |Programmable button 1 |
-|`PROGRAMMABLE_BUTTON_2` |Programmable button 2 |
-|`PROGRAMMABLE_BUTTON_3` |Programmable button 3 |
-|`PROGRAMMABLE_BUTTON_4` |Programmable button 4 |
-|`PROGRAMMABLE_BUTTON_5` |Programmable button 5 |
-|`PROGRAMMABLE_BUTTON_6` |Programmable button 6 |
-|`PROGRAMMABLE_BUTTON_7` |Programmable button 7 |
-|`PROGRAMMABLE_BUTTON_8` |Programmable button 8 |
-|`PROGRAMMABLE_BUTTON_9` |Programmable button 9 |
-|`PROGRAMMABLE_BUTTON_10`|Programmable button 10|
-|`PROGRAMMABLE_BUTTON_11`|Programmable button 11|
-|`PROGRAMMABLE_BUTTON_12`|Programmable button 12|
-|`PROGRAMMABLE_BUTTON_13`|Programmable button 13|
-|`PROGRAMMABLE_BUTTON_14`|Programmable button 14|
-|`PROGRAMMABLE_BUTTON_15`|Programmable button 15|
-|`PROGRAMMABLE_BUTTON_16`|Programmable button 16|
-|`PROGRAMMABLE_BUTTON_17`|Programmable button 17|
-|`PROGRAMMABLE_BUTTON_18`|Programmable button 18|
-|`PROGRAMMABLE_BUTTON_19`|Programmable button 19|
-|`PROGRAMMABLE_BUTTON_20`|Programmable button 20|
-|`PROGRAMMABLE_BUTTON_21`|Programmable button 21|
-|`PROGRAMMABLE_BUTTON_22`|Programmable button 22|
-|`PROGRAMMABLE_BUTTON_23`|Programmable button 23|
-|`PROGRAMMABLE_BUTTON_24`|Programmable button 24|
-|`PROGRAMMABLE_BUTTON_25`|Programmable button 25|
-|`PROGRAMMABLE_BUTTON_26`|Programmable button 26|
-|`PROGRAMMABLE_BUTTON_27`|Programmable button 27|
-|`PROGRAMMABLE_BUTTON_28`|Programmable button 28|
-|`PROGRAMMABLE_BUTTON_29`|Programmable button 29|
-|`PROGRAMMABLE_BUTTON_30`|Programmable button 30|
-|`PROGRAMMABLE_BUTTON_31`|Programmable button 31|
-|`PROGRAMMABLE_BUTTON_32`|Programmable button 32|
-|`PB_1` to `PB_32` |Aliases for keymaps |
-
-### API
-
-You can also use a dedicated API defined in `programmable_button.h` to interact with this feature:
+## Keycodes :id=keycodes
-```
-void programmable_button_clear(void);
-void programmable_button_send(void);
-void programmable_button_on(uint8_t code);
-void programmable_button_off(uint8_t code);
-bool programmable_button_is_on(uint8_t code);
-uint32_t programmable_button_get_report(void);
-void programmable_button_set_report(uint32_t report);
-```
+|Key |Aliases|Description |
+|---------------------------|-------|----------------------|
+|`QK_PROGRAMMABLE_BUTTON_1` |`PB_1` |Programmable button 1 |
+|`QK_PROGRAMMABLE_BUTTON_2` |`PB_2` |Programmable button 2 |
+|`QK_PROGRAMMABLE_BUTTON_3` |`PB_3` |Programmable button 3 |
+|`QK_PROGRAMMABLE_BUTTON_4` |`PB_4` |Programmable button 4 |
+|`QK_PROGRAMMABLE_BUTTON_5` |`PB_5` |Programmable button 5 |
+|`QK_PROGRAMMABLE_BUTTON_6` |`PB_6` |Programmable button 6 |
+|`QK_PROGRAMMABLE_BUTTON_7` |`PB_7` |Programmable button 7 |
+|`QK_PROGRAMMABLE_BUTTON_8` |`PB_8` |Programmable button 8 |
+|`QK_PROGRAMMABLE_BUTTON_9` |`PB_9` |Programmable button 9 |
+|`QK_PROGRAMMABLE_BUTTON_10`|`PB_10`|Programmable button 10|
+|`QK_PROGRAMMABLE_BUTTON_11`|`PB_11`|Programmable button 11|
+|`QK_PROGRAMMABLE_BUTTON_12`|`PB_12`|Programmable button 12|
+|`QK_PROGRAMMABLE_BUTTON_13`|`PB_13`|Programmable button 13|
+|`QK_PROGRAMMABLE_BUTTON_14`|`PB_14`|Programmable button 14|
+|`QK_PROGRAMMABLE_BUTTON_15`|`PB_15`|Programmable button 15|
+|`QK_PROGRAMMABLE_BUTTON_16`|`PB_16`|Programmable button 16|
+|`QK_PROGRAMMABLE_BUTTON_17`|`PB_17`|Programmable button 17|
+|`QK_PROGRAMMABLE_BUTTON_18`|`PB_18`|Programmable button 18|
+|`QK_PROGRAMMABLE_BUTTON_19`|`PB_19`|Programmable button 19|
+|`QK_PROGRAMMABLE_BUTTON_20`|`PB_20`|Programmable button 20|
+|`QK_PROGRAMMABLE_BUTTON_21`|`PB_21`|Programmable button 21|
+|`QK_PROGRAMMABLE_BUTTON_22`|`PB_22`|Programmable button 22|
+|`QK_PROGRAMMABLE_BUTTON_23`|`PB_23`|Programmable button 23|
+|`QK_PROGRAMMABLE_BUTTON_24`|`PB_24`|Programmable button 24|
+|`QK_PROGRAMMABLE_BUTTON_25`|`PB_25`|Programmable button 25|
+|`QK_PROGRAMMABLE_BUTTON_26`|`PB_26`|Programmable button 26|
+|`QK_PROGRAMMABLE_BUTTON_27`|`PB_27`|Programmable button 27|
+|`QK_PROGRAMMABLE_BUTTON_28`|`PB_28`|Programmable button 28|
+|`QK_PROGRAMMABLE_BUTTON_29`|`PB_29`|Programmable button 29|
+|`QK_PROGRAMMABLE_BUTTON_30`|`PB_30`|Programmable button 30|
+|`QK_PROGRAMMABLE_BUTTON_31`|`PB_31`|Programmable button 31|
+|`QK_PROGRAMMABLE_BUTTON_32`|`PB_32`|Programmable button 32|
+
+## API :id=api
+
+### `void programmable_button_clear(void)` :id=api-programmable-button-clear
+
+Clear the programmable button report.
+
+---
+
+### `void programmable_button_add(uint8_t index)` :id=api-programmable-button-add
+
+Set the state of a button.
+
+#### Arguments :id=api-programmable-button-add-arguments
+
+ - `uint8_t index`
+ The index of the button to press, from 0 to 31.
+
+---
+
+### `void programmable_button_remove(uint8_t index)` :id=api-programmable-button-remove
+
+Reset the state of a button.
+
+#### Arguments :id=api-programmable-button-remove-arguments
+
+ - `uint8_t index`
+ The index of the button to release, from 0 to 31.
+
+---
+
+### `void programmable_button_register(uint8_t index)` :id=api-programmable-button-register
+
+Set the state of a button, and flush the report.
+
+#### Arguments :id=api-programmable-button-register-arguments
+
+ - `uint8_t index`
+ The index of the button to press, from 0 to 31.
+
+---
+
+### `void programmable_button_unregister(uint8_t index)` :id=api-programmable-button-unregister
+
+Reset the state of a button, and flush the report.
+
+#### Arguments :id=api-programmable-button-unregister-arguments
+
+ - `uint8_t index`
+ The index of the button to release, from 0 to 31.
+
+---
+
+### `bool programmable_button_is_on(uint8_t index)` :id=api-programmable-button-is-on
+
+Get the state of a button.
+
+#### Arguments :id=api-programmable-button-is-on-arguments
+
+ - `uint8_t index`
+ The index of the button to check, from 0 to 31.
+
+#### Return Value :id=api-programmable-button-is-on-return
+
+`true` if the button is pressed.
+
+---
+
+### `void programmable_button_flush(void)` :id=api-programmable-button-flush
+
+Send the programmable button report to the host.
+
+---
+
+### `uint32_t programmable_button_get_report(void)` :id=api-programmable-button-get-report
+
+Get the programmable button report.
+
+#### Return Value :id=api-programmable-button-get-report-return
+
+The bitmask of programmable button states.
+
+---
+
+### `void programmable_button_set_report(uint32_t report)` :id=api-programmable-button-set-report
+
+Set the programmable button report.
+
+#### Arguments :id=api-programmable-button-set-report-arguments
+
+ - `uint32_t report`
+ A bitmask of programmable button states.
diff --git a/docs/feature_ps2_mouse.md b/docs/feature_ps2_mouse.md
index c980705ae7..e714d9b867 100644
--- a/docs/feature_ps2_mouse.md
+++ b/docs/feature_ps2_mouse.md
@@ -32,13 +32,14 @@ In rules.mk:
```make
PS2_MOUSE_ENABLE = yes
-PS2_USE_BUSYWAIT = yes
+PS2_ENABLE = yes
+PS2_DRIVER = busywait
```
In your keyboard config.h:
```c
-#ifdef PS2_USE_BUSYWAIT
+#ifdef PS2_DRIVER_BUSYWAIT
# define PS2_CLOCK_PIN D1
# define PS2_DATA_PIN D2
#endif
@@ -52,13 +53,14 @@ In rules.mk:
```make
PS2_MOUSE_ENABLE = yes
-PS2_USE_INT = yes
+PS2_ENABLE = yes
+PS2_DRIVER = interrupt
```
In your keyboard config.h:
```c
-#ifdef PS2_USE_INT
+#ifdef PS2_DRIVER_INTERRUPT
#define PS2_CLOCK_PIN D2
#define PS2_DATA_PIN D5
@@ -84,7 +86,8 @@ In rules.mk:
```
PS2_MOUSE_ENABLE = yes
-PS2_USE_INT = yes
+PS2_ENABLE = yes
+PS2_DRIVER = interrupt
```
In your keyboard config.h:
@@ -108,13 +111,14 @@ In rules.mk:
```make
PS2_MOUSE_ENABLE = yes
-PS2_USE_USART = yes
+PS2_ENABLE = yes
+PS2_DRIVER = usart
```
In your keyboard config.h:
```c
-#ifdef PS2_USE_USART
+#ifdef PS2_DRIVER_USART
#define PS2_CLOCK_PIN D5
#define PS2_DATA_PIN D2
diff --git a/docs/feature_rgb_matrix.md b/docs/feature_rgb_matrix.md
index c5d473ef2a..bac49b75ff 100644
--- a/docs/feature_rgb_matrix.md
+++ b/docs/feature_rgb_matrix.md
@@ -23,7 +23,7 @@ You can use between 1 and 4 IS31FL3731 IC's. Do not specify `DRIVER_ADDR_<N>` de
| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 |
| `ISSI_3731_DEGHOST` | (Optional) Set this define to enable de-ghosting by halving Vcc during blanking time | |
| `DRIVER_COUNT` | (Required) How many RGB driver IC's are present | |
-| `DRIVER_LED_TOTAL` | (Required) How many RGB lights are present across all drivers | |
+| `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 | |
@@ -45,17 +45,17 @@ Here is an example using 2 drivers.
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 25
#define DRIVER_2_LED_TOTAL 24
-#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+#define RGB_MATRIX_LED_COUNT (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
```
-!> Note the parentheses, this is so when `DRIVER_LED_TOTAL` 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`.
+!> 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`.
For split keyboards using `RGB_MATRIX_SPLIT` with an LED driver, you can either have the same driver address or different driver addresses. If using different addresses, use `DRIVER_ADDR_1` for one and `DRIVER_ADDR_2` for the other one. Then, in `g_is31_leds`, fill out the correct driver index (0 or 1). If using one address, use `DRIVER_ADDR_1` for both, and use index 0 for `g_is31_leds`.
Define these arrays listing all the LEDs in your `<keyboard>.c`:
```c
-const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = {
+const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
@@ -90,7 +90,7 @@ You can use between 1 and 4 IS31FL3733 IC's. Do not specify `DRIVER_ADDR_<N>` de
| `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 | |
-| `DRIVER_LED_TOTAL` | (Required) How many RGB lights are present across all drivers | |
+| `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 | |
@@ -131,17 +131,17 @@ Here is an example using 2 drivers.
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 58
#define DRIVER_2_LED_TOTAL 10
-#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+#define RGB_MATRIX_LED_COUNT (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
```
-!> Note the parentheses, this is so when `DRIVER_LED_TOTAL` 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`.
+!> 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 4 drivers are supported, but it would be trivial to support all 8 combinations.
Define these arrays listing all the LEDs in your `<keyboard>.c`:
```c
-const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = {
+const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
@@ -164,7 +164,7 @@ There is basic support for addressable RGB matrix lighting with the I2C IS31FL37
RGB_MATRIX_ENABLE = yes
RGB_MATRIX_DRIVER = IS31FL3737
```
-You can use between 1 and 2 IS31FL3737 IC's. Do not specify `DRIVER_ADDR_2` define for second IC if not present on your keyboard.
+You can use between 1 and 4 IS31FL3737 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`:
@@ -177,9 +177,11 @@ Configure the hardware via your `config.h`:
| `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 | |
-| `DRIVER_LED_TOTAL` | (Required) How many RGB lights are present across all drivers | |
+| `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 IS31FL3737 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:
@@ -212,16 +214,16 @@ Here is an example using 2 drivers.
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 30
#define DRIVER_2_LED_TOTAL 36
-#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+#define RGB_MATRIX_LED_COUNT (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
```
-!> Note the parentheses, this is so when `DRIVER_LED_TOTAL` 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`.
+!> 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
-const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = {
+const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
@@ -233,7 +235,7 @@ const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = {
}
```
-Where `X_Y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3737.pdf) and the header file `drivers/led/issi/is31fl3737.h`. The `driver` is the index of the driver you defined in your `config.h` (Only `0`, `1` for now).
+Where `X_Y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3737.pdf) and the header file `drivers/led/issi/is31fl3737.h`. The `driver` is the index of the driver you defined in your `config.h` (Only `0`, `1`, `2`, or `3` for now).
---
### IS31FLCOMMON :id=is31flcommon
@@ -263,7 +265,7 @@ Configure the hardware via your `config.h`:
| `ISSI_TIMEOUT` | (Optional) How long to wait for i2c messages, in milliseconds | 100 |
| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 |
| `DRIVER_COUNT` | (Required) How many RGB driver IC's are present | |
-| `DRIVER_LED_TOTAL` | (Required) How many RGB lights are present across all drivers | |
+| `RGB_MATRIX_LED_COUNT` | (Required) How many RGB lights are present across all drivers | |
| `DRIVER_ADDR_1` | (Optional) Address for the first RGB driver | |
| `DRIVER_ADDR_<N>` | (Required) Address for the additional RGB drivers | |
| `ISSI_SSR_<N>` | (Optional) Configuration for the Spread Spectrum Register | |
@@ -300,17 +302,17 @@ Here is an example using 2 drivers.
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 66
#define DRIVER_2_LED_TOTAL 42
-#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+#define RGB_MATRIX_LED_COUNT (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
```
-!> Note the parentheses, this is so when `DRIVER_LED_TOTAL` 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`.
+!> 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 4 drivers are supported, but it would be trivial to support for more. Note that using a combination of different drivers is not supported. All drivers must be of the same model.
Define these arrays listing all the LEDs in your `<keyboard>.c`:
```c
-const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = {
+const is31_led __flash g_is31_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
@@ -361,7 +363,7 @@ Configure the hardware via your `config.h`:
// The pin connected to the data pin of the LEDs
#define RGB_DI_PIN D7
// The number of LEDs connected
-#define DRIVER_LED_TOTAL 70
+#define RGB_MATRIX_LED_COUNT 70
```
?> There are additional configuration options for ARM controllers that offer increased performance over the default bitbang driver. Please see [WS2812 Driver](ws2812_driver.md) for more information.
@@ -385,7 +387,7 @@ Configure the hardware via your `config.h`:
// The pin connected to the clock pin of the LEDs
#define RGB_CI_PIN D6
// The number of LEDs connected
-#define DRIVER_LED_TOTAL 70
+#define RGB_MATRIX_LED_COUNT 70
```
---
@@ -408,7 +410,7 @@ You can use up to 2 AW20216 IC's. Do not specify `DRIVER_<N>_xxx` defines for IC
| `DRIVER_1_LED_TOTAL` | (Required) How many RGB lights are connected to first RGB driver | |
| `DRIVER_2_LED_TOTAL` | (Optional) How many RGB lights are connected to second RGB driver | |
| `DRIVER_COUNT` | (Required) How many RGB driver IC's are present | |
-| `DRIVER_LED_TOTAL` | (Required) How many RGB lights are present across all drivers | |
+| `RGB_MATRIX_LED_COUNT` | (Required) How many RGB lights are present across all drivers | |
| `AW_SCALING_MAX` | (Optional) LED current scaling value (0-255, higher values mean LED is brighter at full PWM) | 150 |
| `AW_GLOBAL_CURRENT_MAX` | (Optional) Driver global current limit (0-255, higher values means the driver may consume more power) | 150 |
| `AW_SPI_MODE` | (Optional) Mode for SPI communication (0-3, defines polarity and phase of the clock) | 3 |
@@ -426,15 +428,15 @@ Here is an example using 2 drivers.
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 66
#define DRIVER_2_LED_TOTAL 32
-#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+#define RGB_MATRIX_LED_COUNT (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
```
-!> Note the parentheses, this is so when `DRIVER_LED_TOTAL` 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`.
+!> 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 aw_led PROGMEM g_aw_leds[DRIVER_LED_TOTAL] = {
+const aw_led PROGMEM g_aw_leds[RGB_MATRIX_LED_COUNT] = {
/* Each AW20216 channel is controlled by a register at some offset between 0x00
* and 0xD7 inclusive.
* See drivers/awinic/aw20216.h for the mapping between register offsets and
@@ -791,10 +793,9 @@ These are defined in [`color.h`](https://github.com/qmk/qmk_firmware/blob/master
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses
#define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS // enable framebuffer effects
-#define RGB_DISABLE_TIMEOUT 0 // number of milliseconds to wait until rgb automatically turns off
-#define RGB_DISABLE_AFTER_TIMEOUT 0 // OBSOLETE: number of ticks to wait until disabling effects
+#define RGB_MATRIX_TIMEOUT 0 // number of milliseconds to wait until rgb automatically turns off
#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
-#define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
+#define RGB_MATRIX_LED_PROCESS_LIMIT (RGB_MATRIX_LED_COUNT + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
#define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_LEFT_RIGHT // Sets the default mode, if none has been set
@@ -824,7 +825,7 @@ Where `28` is an unused index from `eeconfig.h`.
|Function |Description |
|--------------------------------------------|-------------|
|`rgb_matrix_set_color_all(r, g, b)` |Set all of the LEDs to the given RGB value, where `r`/`g`/`b` are between 0 and 255 (not written to EEPROM) |
-|`rgb_matrix_set_color(index, r, g, b)` |Set a single LED to the given RGB value, where `r`/`g`/`b` are between 0 and 255, and `index` is between 0 and `DRIVER_LED_TOTAL` (not written to EEPROM) |
+|`rgb_matrix_set_color(index, r, g, b)` |Set a single LED to the given RGB value, where `r`/`g`/`b` are between 0 and 255, and `index` is between 0 and `RGB_MATRIX_LED_COUNT` (not written to EEPROM) |
### Disable/Enable Effects :id=disable-enable-effects
|Function |Description |
@@ -889,16 +890,21 @@ Where `28` is an unused index from `eeconfig.h`.
If you want to set custom indicators, such as an LED for Caps Lock, or layer indication, you can use the `rgb_matrix_indicators_kb` or `rgb_matrix_indicators_user` function for that:
```c
-void rgb_matrix_indicators_kb(void) {
+bool rgb_matrix_indicators_kb(void) {
+ if (!rgb_matrix_indicators_user()) {
+ return false;
+ }
rgb_matrix_set_color(index, red, green, blue);
+ return true;
}
```
In addition, there are the advanced indicator functions. These are aimed at those with heavily customized displays, where rendering every LED per cycle is expensive. Such as some of the "drashna" layouts. This includes a special macro to help make this easier to use: `RGB_MATRIX_INDICATOR_SET_COLOR(i, r, g, b)`.
```c
-void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
+bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
RGB_MATRIX_INDICATOR_SET_COLOR(index, red, green, blue);
+ return false;
}
```
@@ -906,21 +912,22 @@ void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
Caps Lock indicator on alphanumeric flagged keys:
```c
-void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
+bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
if (host_keyboard_led_state().caps_lock) {
- for (uint8_t i = led_min; i <= led_max; i++) {
+ for (uint8_t i = led_min; i < led_max; i++) {
if (g_led_config.flags[i] & LED_FLAG_KEYLIGHT) {
rgb_matrix_set_color(i, RGB_RED);
}
}
}
+ return false;
}
```
Layer indicator on all keys:
```c
-void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
- for (uint8_t i = led_min; i <= led_max; i++) {
+bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
+ for (uint8_t i = led_min; i < led_max; i++) {
switch(get_highest_layer(layer_state|default_layer_state)) {
case 2:
rgb_matrix_set_color(i, RGB_BLUE);
@@ -932,12 +939,13 @@ void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
break;
}
}
+ return false;
}
```
Layer indicator only on keys with configured keycodes:
```c
-void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
+bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
if (get_highest_layer(layer_state) > 0) {
uint8_t layer = get_highest_layer(layer_state);
@@ -945,13 +953,14 @@ void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
for (uint8_t col = 0; col < MATRIX_COLS; ++col) {
uint8_t index = g_led_config.matrix_co[row][col];
- if (index >= led_min && index <= led_max && index != NO_LED &&
+ if (index >= led_min && index < led_max && index != NO_LED &&
keymap_key_to_keycode(layer, (keypos_t){col,row}) > KC_TRNS) {
rgb_matrix_set_color(index, RGB_GREEN);
}
}
}
}
+ return false;
}
```
@@ -962,7 +971,7 @@ void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
This example sets the modifiers to be a specific color based on the layer state. You can use a switch case here, instead, if you would like. This uses HSV and then converts to RGB, because this allows the brightness to be limited (important when using the WS2812 driver).
```c
-void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
+bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
HSV hsv = {0, 255, 255};
if (layer_state_is(layer_state, 2)) {
@@ -976,23 +985,25 @@ void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
}
RGB rgb = hsv_to_rgb(hsv);
- for (uint8_t i = led_min; i <= led_max; i++) {
+ for (uint8_t i = led_min; i < led_max; i++) {
if (HAS_FLAGS(g_led_config.flags[i], 0x01)) { // 0x01 == LED_FLAG_MODIFIER
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
}
+ return false;
}
```
If you want to indicate a Host LED status (caps lock, num lock, etc), you can use something like this to light up the caps lock key:
```c
-void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
+bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
if (host_keyboard_led_state().caps_lock) {
RGB_MATRIX_INDICATOR_SET_COLOR(5, 255, 255, 255); // assuming caps lock is at led #5
} else {
RGB_MATRIX_INDICATOR_SET_COLOR(5, 0, 0, 0);
}
+ return false;
}
```
diff --git a/docs/feature_rgblight.md b/docs/feature_rgblight.md
index 7e7699c5b7..1159347112 100644
--- a/docs/feature_rgblight.md
+++ b/docs/feature_rgblight.md
@@ -302,7 +302,7 @@ void keyboard_post_init_user(void) {
// after the flag has been flipped...
void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
- case DEBUG:
+ case QK_DEBUG_TOGGLE:
rgblight_blink_layer(debug_enable ? 0 : 1, 500);
break;
@@ -319,13 +319,13 @@ You can also use `rgblight_blink_layer_repeat` to specify the amount of times th
```c
void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
- case DEBUG:
+ case QK_DEBUG_TOGGLE:
rgblight_blink_layer_repeat(debug_enable ? 0 : 1, 200, 3);
break;
}
}
```
-would turn the layer 0 (or 1) on and off again three times when `DEBUG` is pressed.
+would turn the layer 0 (or 1) on and off again three times when `DB_TOGG` is pressed.
Blinking accumulates layers so if multiple layers are set blinking at the same time they will all blink for the duration and repeat times of the last layer to be blinked.
To stop these other layers from blinking use `rgblight_unblink_layer` or `rgblight_unblink_all_but_layer`:
diff --git a/docs/feature_secure.md b/docs/feature_secure.md
index ee774b05a8..eaa2b601ae 100644
--- a/docs/feature_secure.md
+++ b/docs/feature_secure.md
@@ -26,12 +26,12 @@ SECURE_ENABLE = yes
## Keycodes
-| Key | Description |
-|------------------|--------------------------------------------------------------------------------|
-| `SECURE_LOCK` | Revert back to a locked state |
-| `SECURE_UNLOCK` | Forces unlock without performing a unlock sequence |
-| `SECURE_TOGGLE` | Toggle directly between locked and unlock without performing a unlock sequence |
-| `SECURE_REQUEST` | Request that user perform the unlock sequence |
+| Key |Aliases | Description |
+|---------------------|---------|--------------------------------------------------------------------------------|
+| `QK_SECURE_LOCK` |`SE_LOCK`| Revert back to a locked state |
+| `QK_SECURE_UNLOCK` |`SE_UNLK`| Forces unlock without performing a unlock sequence |
+| `QK_SECURE_TOGGLE` |`SE_TOGG`| Toggle directly between locked and unlock without performing a unlock sequence |
+| `QK_SECURE_REQUEST` |`SE_REQ` | Request that user perform the unlock sequence |
## Configuration
diff --git a/docs/feature_space_cadet.md b/docs/feature_space_cadet.md
index e290964241..63a3881da8 100644
--- a/docs/feature_space_cadet.md
+++ b/docs/feature_space_cadet.md
@@ -5,22 +5,22 @@ Steve Losh described the [Space Cadet Shift](https://stevelosh.com/blog/2012/10/
## Usage
Firstly, in your keymap, do one of the following:
-- Replace the Left Shift key with `KC_LSPO` (Left Shift, Parenthesis Open), and Right Shift with `KC_RSPC` (Right Shift, Parenthesis Close).
-- Replace the Left Control key with `KC_LCPO` (Left Control, Parenthesis Open), and Right Control with `KC_RCPC` (Right Control, Parenthesis Close).
-- Replace the Left Alt key with `KC_LAPO` (Left Alt, Parenthesis Open), and Right Alt with `KC_RAPC` (Right Alt, Parenthesis Close).
-- Replace any Shift key in your keymap with `KC_SFTENT` (Right Shift, Enter).
+- Replace the Left Shift key with `SC_LSPO` (Left Shift, Parenthesis Open), and Right Shift with `SC_RSPC` (Right Shift, Parenthesis Close).
+- Replace the Left Control key with `SC_LCPO` (Left Control, Parenthesis Open), and Right Control with `SC_RCPC` (Right Control, Parenthesis Close).
+- Replace the Left Alt key with `SC_LAPO` (Left Alt, Parenthesis Open), and Right Alt with `SC_RAPC` (Right Alt, Parenthesis Close).
+- Replace any Shift key in your keymap with `SC_SENT` (Right Shift, Enter).
## Keycodes
-|Keycode |Description |
-|-----------|-------------------------------------------|
-|`KC_LSPO` |Left Shift when held, `(` when tapped |
-|`KC_RSPC` |Right Shift when held, `)` when tapped |
-|`KC_LCPO` |Left Control when held, `(` when tapped |
-|`KC_RCPC` |Right Control when held, `)` when tapped |
-|`KC_LAPO` |Left Alt when held, `(` when tapped |
-|`KC_RAPC` |Right Alt when held, `)` when tapped |
-|`KC_SFTENT`|Right Shift when held, Enter when tapped |
+|Keycode |Aliases |Description |
+|----------------------------------------------|---------|----------------------------------------|
+|`QK_SPACE_CADET_LEFT_CTRL_PARENTHESIS_OPEN` |`SC_LCPO`|Left Control when held, `(` when tapped |
+|`QK_SPACE_CADET_RIGHT_CTRL_PARENTHESIS_CLOSE` |`SC_RCPC`|Right Control when held, `)` when tapped|
+|`QK_SPACE_CADET_LEFT_SHIFT_PARENTHESIS_OPEN` |`SC_LSPO`|Left Shift when held, `(` when tapped |
+|`QK_SPACE_CADET_RIGHT_SHIFT_PARENTHESIS_CLOSE`|`SC_RSPC`|Right Shift when held, `)` when tapped |
+|`QK_SPACE_CADET_LEFT_ALT_PARENTHESIS_OPEN` |`SC_LAPO`|Left Alt when held, `(` when tapped |
+|`QK_SPACE_CADET_RIGHT_ALT_PARENTHESIS_CLOSE` |`SC_RAPC`|Right Alt when held, `)` when tapped |
+|`QK_SPACE_CADET_RIGHT_SHIFT_ENTER` |`SC_SENT`|Right Shift when held, Enter when tapped|
## Caveats
@@ -32,7 +32,7 @@ COMMAND_ENABLE = no
## Configuration
-By default Space Cadet assumes a US ANSI layout, but if your layout uses different keys for parentheses, you can redefine them in your `config.h`. In addition, you can redefine the modifier to send on tap, or even send no modifier at all. The new configuration defines bundle all options up into a single define of 3 key codes in this order: the `Modifier` when held or when used with other keys, the `Tap Modifer` sent when tapped (no modifier if `KC_TRNS`), finally the `Keycode` sent when tapped. Now keep in mind, mods from other keys will still apply to the `Keycode` if say `KC_RSFT` is held while tapping `KC_LSPO` key with `KC_TRNS` as the `Tap Modifer`.
+By default Space Cadet assumes a US ANSI layout, but if your layout uses different keys for parentheses, you can redefine them in your `config.h`. In addition, you can redefine the modifier to send on tap, or even send no modifier at all. The new configuration defines bundle all options up into a single define of 3 key codes in this order: the `Modifier` when held or when used with other keys, the `Tap Modifer` sent when tapped (no modifier if `KC_TRNS`), finally the `Keycode` sent when tapped. Now keep in mind, mods from other keys will still apply to the `Keycode` if say `KC_RSFT` is held while tapping `SC_LSPO` key with `KC_TRNS` as the `Tap Modifer`.
|Define |Default |Description |
|----------------|-------------------------------|---------------------------------------------------------------------------------|
@@ -48,7 +48,7 @@ By default Space Cadet assumes a US ANSI layout, but if your layout uses differe
## Obsolete Configuration
-These defines are used in the above defines internally to support backwards compatibility, so you may continue to use them, however the above defines open up a larger range of flexibility than before. As an example, say you want to not send any modifier when you tap just `KC_LSPO`, with the old defines you had an all or nothing choice of using the `DISABLE_SPACE_CADET_MODIFIER` define. Now you can define that key as: `#define LSPO_KEYS KC_LSFT, KC_TRNS, KC_9`. This tells the system to set Left Shift if held or used with other keys, then on tap send no modifier (transparent) with the `KC_9`.
+These defines are used in the above defines internally to support backwards compatibility, so you may continue to use them, however the above defines open up a larger range of flexibility than before. As an example, say you want to not send any modifier when you tap just `SC_LSPO`, with the old defines you had an all or nothing choice of using the `DISABLE_SPACE_CADET_MODIFIER` define. Now you can define that key as: `#define LSPO_KEYS KC_LSFT, KC_TRNS, KC_9`. This tells the system to set Left Shift if held or used with other keys, then on tap send no modifier (transparent) with the `KC_9`.
|Define |Default |Description |
|------------------------------|-------------|------------------------------------------------------------------|
diff --git a/docs/feature_split_keyboard.md b/docs/feature_split_keyboard.md
index e53b3525cb..0b475cc63d 100644
--- a/docs/feature_split_keyboard.md
+++ b/docs/feature_split_keyboard.md
@@ -153,11 +153,11 @@ Example:
make crkbd:default:avrdude-split-left
```
-?> ARM controllers using `dfu-util` will require an EEPROM reset after setting handedness. This can be done using the `EEP_RST` keycode or [Bootmagic Lite](feature_bootmagic.md). Controllers using emulated EEPROM will always require handedness parameter when flashing the firmware.
+?> ARM controllers using `dfu-util` will require an EEPROM reset after setting handedness. This can be done using the `EE_CLR` keycode or [Bootmagic Lite](feature_bootmagic.md). Controllers using emulated EEPROM will always require handedness parameter when flashing the firmware.
?> [QMK Toolbox]() can also be used to flash EEPROM handedness files. Place the controller in bootloader mode and select menu option Tools -> EEPROM -> Set Left/Right Hand
-This setting is not changed when re-initializing the EEPROM using the `EEP_RST` key, or using the `eeconfig_init()` function. However, if you reset the EEPROM outside of the firmware's built in options (such as flashing a file that overwrites the `EEPROM`, like how the [QMK Toolbox]()'s "Reset EEPROM" button works), you'll need to re-flash the controller with the `EEPROM` files.
+This setting is not changed when re-initializing the EEPROM using the `EE_CLR` key, or using the `eeconfig_init()` function. However, if you reset the EEPROM outside of the firmware's built in options (such as flashing a file that overwrites the `EEPROM`, like how the [QMK Toolbox]()'s "Reset EEPROM" button works), you'll need to re-flash the controller with the `EEPROM` files.
You can find the `EEPROM` files in the QMK firmware repo, [here](https://github.com/qmk/qmk_firmware/tree/master/quantum/split_common).
@@ -422,6 +422,17 @@ This sets the maximum timeout when detecting master/slave when using `SPLIT_USB_
```
This sets the poll frequency when detecting master/slave when using `SPLIT_USB_DETECT`
+```c
+#define SPLIT_WATCHDOG_ENABLE
+```
+
+This will enable a software watchdog on any side delegated as slave and will reboot the keyboard if no successful communication occurs within `SPLIT_WATCHDOG_TIMEOUT`. This can be particularly helpful when `SPLIT_USB_DETECT` delegates both sides as slave in some circumstances.
+
+```c
+#define SPLIT_WATCHDOG_TIMEOUT 3000
+```
+This set the maximum slave timeout when waiting for communication from master when using `SPLIT_WATCHDOG_ENABLE`
+
## Hardware Considerations and Mods
Master/slave delegation is made either by detecting voltage on VBUS connection or waiting for USB communication (`SPLIT_USB_DETECT`). Pro Micro boards can use VBUS detection out of the box and be used with or without `SPLIT_USB_DETECT`.
diff --git a/docs/feature_unicode.md b/docs/feature_unicode.md
index 2389cb735c..0b06cae6c2 100644
--- a/docs/feature_unicode.md
+++ b/docs/feature_unicode.md
@@ -119,8 +119,6 @@ The following input modes are available:
!> Using the _Unicode Hex Input_ input source may disable some Option-based shortcuts, such as Option+Left and Option+Right.
- !> `UC_OSX` is a deprecated alias of `UC_MAC` that will be removed in future versions of QMK. All new keymaps should use `UC_MAC`.
-
* **`UC_LNX`**: Linux built-in IBus Unicode input. Supports code points up to `0x10FFFF` (all possible code points).
Enabled by default and works almost anywhere on IBus-enabled distros. Without IBus, this mode works under GTK apps, but rarely anywhere else.
@@ -206,6 +204,17 @@ The functions for starting and finishing Unicode input on your platform can be o
You can find the default implementations of these functions in [`process_unicode_common.c`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_unicode_common.c).
+### Input Mode Callbacks
+
+There are callbacks functions available that are called whenever the unicode input mode changes. The new input mode is passed to the function.
+
+|Callback |Description |
+|---------------------------------------------------|-----------------------------------------------------|
+| `unicode_input_mode_set_kb(uint8_t input_mode)` | Callback for unicode input mode set, for keyboard. |
+| `unicode_input_mode_set_user(uint8_t input_mode)` | Callback for unicode input mode set, for users. |
+
+This feature can be used, for instance, to implement LED indicators for the current unicode input mode.
+
### Input Key Configuration
You can customize the keys used to trigger Unicode input for macOS, Linux and WinCompose by adding corresponding defines to your `config.h`. The default values match the platforms' default settings, so you shouldn't need to change this unless Unicode input isn't working, or you want to use a different key (e.g. in order to free up left or right Alt).
diff --git a/docs/feature_velocikey.md b/docs/feature_velocikey.md
index 14d4be314d..aeb1865e8a 100644
--- a/docs/feature_velocikey.md
+++ b/docs/feature_velocikey.md
@@ -12,7 +12,7 @@ EXTRAKEY_ENABLE = yes
VELOCIKEY_ENABLE = yes
```
-Then, while using your keyboard, you need to also turn it on with the `VLK_TOG` keycode, which toggles the feature on and off.
+Then, while using your keyboard, you need to also turn it on with the `VK_TOGG` keycode, which toggles the feature on and off.
The following light effects will all be controlled by Velocikey when it is enabled:
- RGB Breathing
diff --git a/docs/ja/feature_ps2_mouse.md b/docs/ja/feature_ps2_mouse.md
index 569934c187..2798f61283 100644
--- a/docs/ja/feature_ps2_mouse.md
+++ b/docs/ja/feature_ps2_mouse.md
@@ -36,13 +36,14 @@ rules.mk で:
```makefile
PS2_MOUSE_ENABLE = yes
-PS2_USE_BUSYWAIT = yes
+PS2_ENABLE = yes
+PS2_DRIVER = busywait
```
キーボードの config.h で:
```c
-#ifdef PS2_USE_BUSYWAIT
+#ifdef PS2_DRIVER_BUSYWAIT
# define PS2_CLOCK_PIN D1
# define PS2_DATA_PIN D2
#endif
@@ -56,13 +57,14 @@ rules.mk で:
```makefile
PS2_MOUSE_ENABLE = yes
-PS2_USE_INT = yes
+PS2_ENABLE = yes
+PS2_DRIVER = interrupt
```
キーボードの config.h で:
```c
-#ifdef PS2_USE_INT
+#ifdef PS2_DRIVER_INTERRUPT
#define PS2_CLOCK_PIN D2
#define PS2_DATA_PIN D5
@@ -88,14 +90,14 @@ rules.mk で:
```makefile
PS2_MOUSE_ENABLE = yes
-PS2_USE_USART = yes
+PS2_ENABLE = yes
+PS2_DRIVER = usart
```
キーボードの config.h で:
```c
-#ifdef PS2_USE_USART
-#ifdef PS2_USE_USART
+#ifdef PS2_DRIVER_USART
#define PS2_CLOCK_PIN D5
#define PS2_DATA_PIN D2
diff --git a/docs/keycodes.md b/docs/keycodes.md
index d0ba8e25bf..1aea603ede 100644
--- a/docs/keycodes.md
+++ b/docs/keycodes.md
@@ -207,6 +207,8 @@ See also: [Basic Keycodes](keycodes_basic.md)
|`KC_MEDIA_REWIND` |`KC_MRWD` |Previous Track |✔<sup>6</sup>|✔<sup>5</sup>|✔ |
|`KC_BRIGHTNESS_UP` |`KC_BRIU` |Brightness Up |✔ |✔ |✔ |
|`KC_BRIGHTNESS_DOWN` |`KC_BRID` |Brightness Down |✔ |✔ |✔ |
+|`KC_CONTROL_PANEL` |`KC_CPNL` |Open Control Panel |✔ | | |
+|`KC_ASSISTANT` |`KC_ASST` |Launch Context-Aware Assistant |✔ | | |
<sup>1. The Linux kernel HID driver recognizes [nearly all keycodes](https://github.com/torvalds/linux/blob/master/drivers/hid/hid-input.c), but the default bindings depend on the DE/WM.</sup><br/>
<sup>2. Treated as F13-F15.</sup><br/>
@@ -245,6 +247,29 @@ See also: [Audio](feature_audio.md)
|`MU_TOG` | |Toggles Music Mode |
|`MU_MOD` | |Cycles through the music modes |
+## Auto Shift :id=auto-shift
+
+See also: [Auto Shift](feature_auto_shift.md)
+
+|Key |Aliases |Description |
+|----------------------|---------|--------------------------------------------|
+|`QK_AUTO_SHIFT_DOWN` |`AS_DOWN`|Lower the Auto Shift timeout variable (down)|
+|`QK_AUTO_SHIFT_UP` |`AS_UP` |Raise the Auto Shift timeout variable (up) |
+|`QK_AUTO_SHIFT_REPORT`|`AS_RPT` |Report your current Auto Shift timeout value|
+|`QK_AUTO_SHIFT_ON` |`AS_ON` |Turns on the Auto Shift Function |
+|`QK_AUTO_SHIFT_OFF` |`AS_OFF` |Turns off the Auto Shift Function |
+|`QK_AUTO_SHIFT_TOGGLE`|`AS_TOGG`|Toggles the state of the Auto Shift feature |
+
+## Autocorrect :id=autocorrect
+
+See also: [Autocorrect](feature_autocorrect.md)
+
+|Key |Aliases |Description |
+|-----------------------|---------|----------------------------------------------|
+|`QK_AUTOCORRECT_ON` |`AC_ON` |Turns on the Autocorrect feature. |
+|`QK_AUTOCORRECT_OFF` |`AC_OFF` |Turns off the Autocorrect feature. |
+|`QK_AUTOCORRECT_TOGGLE`|`AC_TOGG`|Toggles the status of the Autocorrect feature.|
+
## Backlighting :id=backlighting
See also: [Backlighting](feature_backlight.md)
@@ -273,9 +298,9 @@ See also: [Bluetooth](feature_bluetooth.md)
See also: [Caps Word](feature_caps_word.md)
-|Key |Aliases |Description |
-|-----------|---------|------------------------------|
-|`CAPS_WORD`|`CAPSWRD`|Toggles Caps Word |
+|Key |Aliases |Description |
+|---------------------|---------|------------------------------|
+|`QK_CAPS_WORD_TOGGLE`|`CW_TOGG`|Toggles Caps Word |
## Dynamic Macros :id=dynamic-macros
@@ -297,13 +322,52 @@ See also: [Grave Escape](feature_grave_esc.md)
|-----------------|---------|------------------------------------------------------------------|
|`QK_GRAVE_ESCAPE`|`QK_GESC`|Escape when pressed, <code>&#96;</code> when Shift or GUI are held|
+## Joystick :id=joystick
+
+See also: [Joystick](feature_joystick.md)
+
+|Key |Aliases|Description|
+|-----------------------|-------|-----------|
+|`QK_JOYSTICK_BUTTON_0` |`JS_0` |Button 0 |
+|`QK_JOYSTICK_BUTTON_1` |`JS_1` |Button 1 |
+|`QK_JOYSTICK_BUTTON_2` |`JS_2` |Button 2 |
+|`QK_JOYSTICK_BUTTON_3` |`JS_3` |Button 3 |
+|`QK_JOYSTICK_BUTTON_4` |`JS_4` |Button 4 |
+|`QK_JOYSTICK_BUTTON_5` |`JS_5` |Button 5 |
+|`QK_JOYSTICK_BUTTON_6` |`JS_6` |Button 6 |
+|`QK_JOYSTICK_BUTTON_7` |`JS_7` |Button 7 |
+|`QK_JOYSTICK_BUTTON_8` |`JS_8` |Button 8 |
+|`QK_JOYSTICK_BUTTON_9` |`JS_9` |Button 9 |
+|`QK_JOYSTICK_BUTTON_10`|`JS_10`|Button 10 |
+|`QK_JOYSTICK_BUTTON_11`|`JS_11`|Button 11 |
+|`QK_JOYSTICK_BUTTON_12`|`JS_12`|Button 12 |
+|`QK_JOYSTICK_BUTTON_13`|`JS_13`|Button 13 |
+|`QK_JOYSTICK_BUTTON_14`|`JS_14`|Button 14 |
+|`QK_JOYSTICK_BUTTON_15`|`JS_15`|Button 15 |
+|`QK_JOYSTICK_BUTTON_16`|`JS_16`|Button 16 |
+|`QK_JOYSTICK_BUTTON_17`|`JS_17`|Button 17 |
+|`QK_JOYSTICK_BUTTON_18`|`JS_18`|Button 18 |
+|`QK_JOYSTICK_BUTTON_19`|`JS_19`|Button 19 |
+|`QK_JOYSTICK_BUTTON_20`|`JS_20`|Button 20 |
+|`QK_JOYSTICK_BUTTON_21`|`JS_21`|Button 21 |
+|`QK_JOYSTICK_BUTTON_22`|`JS_22`|Button 22 |
+|`QK_JOYSTICK_BUTTON_23`|`JS_23`|Button 23 |
+|`QK_JOYSTICK_BUTTON_24`|`JS_24`|Button 24 |
+|`QK_JOYSTICK_BUTTON_25`|`JS_25`|Button 25 |
+|`QK_JOYSTICK_BUTTON_26`|`JS_26`|Button 26 |
+|`QK_JOYSTICK_BUTTON_27`|`JS_27`|Button 27 |
+|`QK_JOYSTICK_BUTTON_28`|`JS_28`|Button 28 |
+|`QK_JOYSTICK_BUTTON_29`|`JS_29`|Button 29 |
+|`QK_JOYSTICK_BUTTON_30`|`JS_30`|Button 30 |
+|`QK_JOYSTICK_BUTTON_31`|`JS_31`|Button 31 |
+
## Key Lock :id=key-lock
See also: [Key Lock](feature_key_lock.md)
|Key |Description |
|---------|--------------------------------------------------------------|
-|`KC_LOCK`|Hold down the next key pressed, until the key is pressed again|
+|`QK_LOCK`|Hold down the next key pressed, until the key is pressed again|
## Layer Switching :id=layer-switching
@@ -326,7 +390,7 @@ See also: [Leader Key](feature_leader_key.md)
|Key |Description |
|---------|------------------------|
-|`KC_LEAD`|Begins a leader sequence|
+|`QK_LEAD`|Begins a leader sequence|
## Magic Keycodes :id=magic-keycodes
@@ -363,6 +427,7 @@ See also: [Magic Keycodes](keycodes_magic.md)
|`MAGIC_UNSWAP_GRAVE_ESC` |`GE_NORM`|Unswap <code>&#96;</code> and Escape |
|`MAGIC_SWAP_BACKSLASH_BACKSPACE` |`BS_SWAP`|Swap `\` and Backspace |
|`MAGIC_UNSWAP_BACKSLASH_BACKSPACE`|`BS_NORM`|Unswap `\` and Backspace |
+|`MAGIC_TOGGLE_BACKSLASH_BACKSPACE`|`BS_TOGG`|Toggle `\` and Backspace swap state |
|`MAGIC_HOST_NKRO` |`NK_ON` |Enable N-key rollover |
|`MAGIC_UNHOST_NKRO` |`NK_OFF` |Disable N-key rollover |
|`MAGIC_TOGGLE_NKRO` |`NK_TOGG`|Toggle N-key rollover |
@@ -694,67 +759,66 @@ See also: [US ANSI Shifted Symbols](keycodes_us_ansi_shifted.md)
See also: [One Shot Keys](one_shot_keys.md)
-|Key |Description |
-|------------|----------------------------------|
-|`OSM(mod)` |Hold `mod` for one keypress |
-|`OSL(layer)`|Switch to `layer` for one keypress|
-|`OS_ON` |Turns One Shot keys on |
-|`OS_OFF` |Turns One Shot keys off |
-|`OS_TOGG` |Toggles One Shot keys status |
+|Key |Aliases |Description |
+|--------------------|---------|----------------------------------|
+|`OSM(mod)` | |Hold `mod` for one keypress |
+|`OSL(layer)` | |Switch to `layer` for one keypress|
+|`QK_ONE_SHOT_TOGGLE`|`OS_TOGG`|Toggles One Shot keys status |
+|`QK_ONE_SHOT_ON` |`OS_ON` |Turns One Shot keys on |
+|`QK_ONE_SHOT_OFF` |`OS_OFF` |Turns One Shot keys off |
## Programmable Button Support :id=programmable-button
See also: [Programmable Button](feature_programmable_button.md)
-|Key |Description |
-|------------------------|----------------------|
-|`PROGRAMMABLE_BUTTON_1` |Programmable button 1 |
-|`PROGRAMMABLE_BUTTON_2` |Programmable button 2 |
-|`PROGRAMMABLE_BUTTON_3` |Programmable button 3 |
-|`PROGRAMMABLE_BUTTON_4` |Programmable button 4 |
-|`PROGRAMMABLE_BUTTON_5` |Programmable button 5 |
-|`PROGRAMMABLE_BUTTON_6` |Programmable button 6 |
-|`PROGRAMMABLE_BUTTON_7` |Programmable button 7 |
-|`PROGRAMMABLE_BUTTON_8` |Programmable button 8 |
-|`PROGRAMMABLE_BUTTON_9` |Programmable button 9 |
-|`PROGRAMMABLE_BUTTON_10`|Programmable button 10|
-|`PROGRAMMABLE_BUTTON_11`|Programmable button 11|
-|`PROGRAMMABLE_BUTTON_12`|Programmable button 12|
-|`PROGRAMMABLE_BUTTON_13`|Programmable button 13|
-|`PROGRAMMABLE_BUTTON_14`|Programmable button 14|
-|`PROGRAMMABLE_BUTTON_15`|Programmable button 15|
-|`PROGRAMMABLE_BUTTON_16`|Programmable button 16|
-|`PROGRAMMABLE_BUTTON_17`|Programmable button 17|
-|`PROGRAMMABLE_BUTTON_18`|Programmable button 18|
-|`PROGRAMMABLE_BUTTON_19`|Programmable button 19|
-|`PROGRAMMABLE_BUTTON_20`|Programmable button 20|
-|`PROGRAMMABLE_BUTTON_21`|Programmable button 21|
-|`PROGRAMMABLE_BUTTON_22`|Programmable button 22|
-|`PROGRAMMABLE_BUTTON_23`|Programmable button 23|
-|`PROGRAMMABLE_BUTTON_24`|Programmable button 24|
-|`PROGRAMMABLE_BUTTON_25`|Programmable button 25|
-|`PROGRAMMABLE_BUTTON_26`|Programmable button 26|
-|`PROGRAMMABLE_BUTTON_27`|Programmable button 27|
-|`PROGRAMMABLE_BUTTON_28`|Programmable button 28|
-|`PROGRAMMABLE_BUTTON_29`|Programmable button 29|
-|`PROGRAMMABLE_BUTTON_30`|Programmable button 30|
-|`PROGRAMMABLE_BUTTON_31`|Programmable button 31|
-|`PROGRAMMABLE_BUTTON_32`|Programmable button 32|
-|`PB_1` to `PB_32` |Aliases for keymaps |
+|Key |Aliases|Description |
+|---------------------------|-------|----------------------|
+|`QK_PROGRAMMABLE_BUTTON_1` |`PB_1` |Programmable button 1 |
+|`QK_PROGRAMMABLE_BUTTON_2` |`PB_2` |Programmable button 2 |
+|`QK_PROGRAMMABLE_BUTTON_3` |`PB_3` |Programmable button 3 |
+|`QK_PROGRAMMABLE_BUTTON_4` |`PB_4` |Programmable button 4 |
+|`QK_PROGRAMMABLE_BUTTON_5` |`PB_5` |Programmable button 5 |
+|`QK_PROGRAMMABLE_BUTTON_6` |`PB_6` |Programmable button 6 |
+|`QK_PROGRAMMABLE_BUTTON_7` |`PB_7` |Programmable button 7 |
+|`QK_PROGRAMMABLE_BUTTON_8` |`PB_8` |Programmable button 8 |
+|`QK_PROGRAMMABLE_BUTTON_9` |`PB_9` |Programmable button 9 |
+|`QK_PROGRAMMABLE_BUTTON_10`|`PB_10`|Programmable button 10|
+|`QK_PROGRAMMABLE_BUTTON_11`|`PB_11`|Programmable button 11|
+|`QK_PROGRAMMABLE_BUTTON_12`|`PB_12`|Programmable button 12|
+|`QK_PROGRAMMABLE_BUTTON_13`|`PB_13`|Programmable button 13|
+|`QK_PROGRAMMABLE_BUTTON_14`|`PB_14`|Programmable button 14|
+|`QK_PROGRAMMABLE_BUTTON_15`|`PB_15`|Programmable button 15|
+|`QK_PROGRAMMABLE_BUTTON_16`|`PB_16`|Programmable button 16|
+|`QK_PROGRAMMABLE_BUTTON_17`|`PB_17`|Programmable button 17|
+|`QK_PROGRAMMABLE_BUTTON_18`|`PB_18`|Programmable button 18|
+|`QK_PROGRAMMABLE_BUTTON_19`|`PB_19`|Programmable button 19|
+|`QK_PROGRAMMABLE_BUTTON_20`|`PB_20`|Programmable button 20|
+|`QK_PROGRAMMABLE_BUTTON_21`|`PB_21`|Programmable button 21|
+|`QK_PROGRAMMABLE_BUTTON_22`|`PB_22`|Programmable button 22|
+|`QK_PROGRAMMABLE_BUTTON_23`|`PB_23`|Programmable button 23|
+|`QK_PROGRAMMABLE_BUTTON_24`|`PB_24`|Programmable button 24|
+|`QK_PROGRAMMABLE_BUTTON_25`|`PB_25`|Programmable button 25|
+|`QK_PROGRAMMABLE_BUTTON_26`|`PB_26`|Programmable button 26|
+|`QK_PROGRAMMABLE_BUTTON_27`|`PB_27`|Programmable button 27|
+|`QK_PROGRAMMABLE_BUTTON_28`|`PB_28`|Programmable button 28|
+|`QK_PROGRAMMABLE_BUTTON_29`|`PB_29`|Programmable button 29|
+|`QK_PROGRAMMABLE_BUTTON_30`|`PB_30`|Programmable button 30|
+|`QK_PROGRAMMABLE_BUTTON_31`|`PB_31`|Programmable button 31|
+|`QK_PROGRAMMABLE_BUTTON_32`|`PB_32`|Programmable button 32|
## Space Cadet :id=space-cadet
See also: [Space Cadet](feature_space_cadet.md)
-|Key |Description |
-|-----------|----------------------------------------|
-|`KC_LCPO` |Left Control when held, `(` when tapped |
-|`KC_RCPC` |Right Control when held, `)` when tapped|
-|`KC_LSPO` |Left Shift when held, `(` when tapped |
-|`KC_RSPC` |Right Shift when held, `)` when tapped |
-|`KC_LAPO` |Left Alt when held, `(` when tapped |
-|`KC_RAPC` |Right Alt when held, `)` when tapped |
-|`KC_SFTENT`|Right Shift when held, Enter when tapped|
+|Key |Aliases |Description |
+|----------------------------------------------|---------|----------------------------------------|
+|`QK_SPACE_CADET_LEFT_CTRL_PARENTHESIS_OPEN` |`SC_LCPO`|Left Control when held, `(` when tapped |
+|`QK_SPACE_CADET_RIGHT_CTRL_PARENTHESIS_CLOSE` |`SC_RCPC`|Right Control when held, `)` when tapped|
+|`QK_SPACE_CADET_LEFT_SHIFT_PARENTHESIS_OPEN` |`SC_LSPO`|Left Shift when held, `(` when tapped |
+|`QK_SPACE_CADET_RIGHT_SHIFT_PARENTHESIS_CLOSE`|`SC_RSPC`|Right Shift when held, `)` when tapped |
+|`QK_SPACE_CADET_LEFT_ALT_PARENTHESIS_OPEN` |`SC_LAPO`|Left Alt when held, `(` when tapped |
+|`QK_SPACE_CADET_RIGHT_ALT_PARENTHESIS_CLOSE` |`SC_RAPC`|Right Alt when held, `)` when tapped |
+|`QK_SPACE_CADET_RIGHT_SHIFT_ENTER` |`SC_SENT`|Right Shift when held, Enter when tapped|
## Swap Hands :id=swap-hands
diff --git a/docs/keycodes_basic.md b/docs/keycodes_basic.md
index 6f6ef7a3fd..d2a49100d1 100644
--- a/docs/keycodes_basic.md
+++ b/docs/keycodes_basic.md
@@ -221,6 +221,8 @@ These keycodes are not part of the Keyboard/Keypad usage page. The `SYSTEM_` key
|`KC_MEDIA_REWIND` |`KC_MRWD`|Previous Track |
|`KC_BRIGHTNESS_UP` |`KC_BRIU`|Brightness Up |
|`KC_BRIGHTNESS_DOWN` |`KC_BRID`|Brightness Down |
+|`KC_CONTROL_PANEL` |`KC_CPNL`|Open Control Panel |
+|`KC_ASSISTANT` |`KC_ASST`|Launch Assistant |
## Number Pad
diff --git a/docs/keymap.md b/docs/keymap.md
index ddcf782140..ea702ff0f2 100644
--- a/docs/keymap.md
+++ b/docs/keymap.md
@@ -147,8 +147,8 @@ Here is an example of the Clueboard's base layer:
F(0), KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_GRV, KC_BSPC, KC_PGUP, \
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, \
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NUHS, KC_ENT, \
- KC_LSFT, KC_NUBS, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RO, KC_RSFT, KC_UP, \
- KC_LCTL, KC_LGUI, KC_LALT, KC_MHEN, KC_SPC,KC_SPC, KC_HENK, KC_RALT, KC_RCTL, MO(_FL), KC_LEFT, KC_DOWN, KC_RGHT),
+ KC_LSFT, KC_NUBS, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_INT1, KC_RSFT, KC_UP, \
+ KC_LCTL, KC_LGUI, KC_LALT, KC_INT5, KC_SPC,KC_SPC, KC_INT4, KC_RALT, KC_RCTL, MO(_FL), KC_LEFT, KC_DOWN, KC_RGHT),
Some interesting things to note about this:
diff --git a/docs/platformdev_rp2040.md b/docs/platformdev_rp2040.md
index f6db70701c..3a6f1a1683 100644
--- a/docs/platformdev_rp2040.md
+++ b/docs/platformdev_rp2040.md
@@ -2,10 +2,11 @@
The following table shows the current driver status for peripherals on RP2040 MCUs:
-| System | Support |
+| System | Support |
| ---------------------------------------------------------------- | ---------------------------------------------- |
| [ADC driver](adc_driver.md) | Support planned (no ETA) |
-| [Audio](audio_driver.md) | Support planned (no ETA) |
+| [Audio](audio_driver.md#pwm-hardware) | :heavy_check_mark: |
+| [Backlight](feature_backlight.md) | :heavy_check_mark: |
| [I2C driver](i2c_driver.md) | :heavy_check_mark: |
| [SPI driver](spi_driver.md) | :heavy_check_mark: |
| [WS2812 driver](ws2812_driver.md) | :heavy_check_mark: using `PIO` driver |
diff --git a/docs/quantum_painter.md b/docs/quantum_painter.md
index 6d4e2764d4..ed9cec171b 100644
--- a/docs/quantum_painter.md
+++ b/docs/quantum_painter.md
@@ -8,7 +8,7 @@ To enable overall Quantum Painter to be built into your firmware, add the follow
```make
QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS = ......
+QUANTUM_PAINTER_DRIVERS += ......
```
You will also likely need to select an appropriate driver in `rules.mk`, which is listed below.
@@ -17,17 +17,18 @@ You will also likely need to select an appropriate driver in `rules.mk`, which i
The QMK CLI can be used to convert from normal images such as PNG files or animated GIFs, as well as fonts from TTF files.
-Hardware supported:
+Supported devices:
-| Display Panel | Panel Type | Size | Comms Transport | Driver |
-|---------------|--------------------|------------------|-----------------|-----------------------------------------|
-| GC9A01 | RGB LCD (circular) | 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = gc9a01_spi` |
-| ILI9163 | RGB LCD | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9163_spi` |
-| ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9341_spi` |
-| ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9488_spi` |
-| SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ssd1351_spi` |
-| ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = st7789_spi` |
-| ST7735 | RGB LCD | 132x162, 80x160 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = st7735_spi` |
+| Display Panel | Panel Type | Size | Comms Transport | Driver |
+|----------------|--------------------|------------------|-----------------|---------------------------------------------|
+| GC9A01 | RGB LCD (circular) | 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += gc9a01_spi` |
+| ILI9163 | RGB LCD | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9163_spi` |
+| ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9341_spi` |
+| ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9488_spi` |
+| SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ssd1351_spi` |
+| ST7735 | RGB LCD | 132x162, 80x160 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7735_spi` |
+| ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7789_spi` |
+| RGB565 Surface | Virtual | User-defined | None | `QUANTUM_PAINTER_DRIVERS += rgb565_surface` |
## Quantum Painter Configuration :id=quantum-painter-config
@@ -45,7 +46,9 @@ Drivers have their own set of configurable options, and are described in their r
## Quantum Painter CLI Commands :id=quantum-painter-cli
-### `qmk painter-convert-graphics`
+<!-- tabs:start -->
+
+### ** `qmk painter-convert-graphics` **
This command converts images to a format usable by QMK, i.e. the QGF File Format.
@@ -93,7 +96,7 @@ Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/my_image.qgf.h...
Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/my_image.qgf.c...
```
-### `qmk painter-make-font-image`
+### ** `qmk painter-make-font-image` **
This command converts a TTF font to an intermediate format for editing, before converting to the QFF File Format.
@@ -126,7 +129,7 @@ The `UNICODE_GLYPHS` argument allows for specifying extra unicode glyphs to gene
$ qmk painter-make-font-image --font NotoSans-ExtraCondensedBold.ttf --size 11 -o noto11.png --unicode-glyphs "ĄȽɂɻɣɈʣ"
```
-### `qmk painter-convert-font-image`
+### ** `qmk painter-convert-font-image` **
This command converts an intermediate font image to the QFF File Format.
@@ -170,6 +173,255 @@ Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/noto11.qff.h...
Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/noto11.qff.c...
```
+<!-- tabs:end -->
+
+## Quantum Painter Display Drivers :id=quantum-painter-drivers
+
+<!-- tabs:start -->
+
+### ** Common: Standard TFT (SPI + D/C + RST) **
+
+Most TFT display panels use a 5-pin interface -- SPI SCK, SPI MOSI, SPI CS, D/C, and RST pins.
+
+For these displays, QMK's `spi_master` must already be correctly configured for the platform you're building for.
+
+The pin assignments for SPI CS, D/C, and RST are specified during device construction.
+
+<!-- tabs:start -->
+
+#### ** GC9A01 **
+
+Enabling support for the GC9A01 in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += gc9a01_spi
+```
+
+Creating a GC9A01 device in firmware can then be done with the following API:
+
+```c
+painter_device_t qp_gc9a01_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
+```
+
+The device handle returned from the `qp_gc9a01_make_spi_device` function can be used to perform all other drawing operations.
+
+The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
+
+```c
+// 3 displays:
+#define GC9A01_NUM_DEVICES 3
+```
+
+#### ** ILI9163 **
+
+Enabling support for the ILI9163 in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += ili9163_spi
+```
+
+Creating a ILI9163 device in firmware can then be done with the following API:
+
+```c
+painter_device_t qp_ili9163_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
+```
+
+The device handle returned from the `qp_ili9163_make_spi_device` function can be used to perform all other drawing operations.
+
+The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
+
+```c
+// 3 displays:
+#define ILI9163_NUM_DEVICES 3
+```
+
+#### ** ILI9341 **
+
+Enabling support for the ILI9341 in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += ili9341_spi
+```
+
+Creating a ILI9341 device in firmware can then be done with the following API:
+
+```c
+painter_device_t qp_ili9341_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
+```
+
+The device handle returned from the `qp_ili9341_make_spi_device` function can be used to perform all other drawing operations.
+
+The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
+
+```c
+// 3 displays:
+#define ILI9341_NUM_DEVICES 3
+```
+
+#### ** ILI9488 **
+
+Enabling support for the ILI9488 in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += ili9488_spi
+```
+
+Creating a ILI9488 device in firmware can then be done with the following API:
+
+```c
+painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
+```
+
+The device handle returned from the `qp_ili9488_make_spi_device` function can be used to perform all other drawing operations.
+
+The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
+
+```c
+// 3 displays:
+#define ILI9488_NUM_DEVICES 3
+```
+
+#### ** SSD1351 **
+
+Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += ssd1351_spi
+```
+
+Creating a SSD1351 device in firmware can then be done with the following API:
+
+```c
+painter_device_t qp_ssd1351_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
+```
+
+The device handle returned from the `qp_ssd1351_make_spi_device` function can be used to perform all other drawing operations.
+
+The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
+
+```c
+// 3 displays:
+#define SSD1351_NUM_DEVICES 3
+```
+
+#### ** ST7735 **
+
+Enabling support for the ST7735 in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += st7735_spi
+```
+
+Creating a ST7735 device in firmware can then be done with the following API:
+
+```c
+painter_device_t qp_st7735_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
+```
+
+The device handle returned from the `qp_st7735_make_spi_device` function can be used to perform all other drawing operations.
+
+The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
+
+```c
+// 3 displays:
+#define ST7735_NUM_DEVICES 3
+```
+
+!> Some ST7735 devices are known to have different drawing offsets -- despite being a 132x162 pixel display controller internally, some display panels are only 80x160, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered.
+
+#### ** ST7789 **
+
+Enabling support for the ST7789 in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += st7789_spi
+```
+
+Creating a ST7789 device in firmware can then be done with the following API:
+
+```c
+painter_device_t qp_st7789_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
+```
+
+The device handle returned from the `qp_st7789_make_spi_device` function can be used to perform all other drawing operations.
+
+The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
+
+```c
+// 3 displays:
+#define ST7789_NUM_DEVICES 3
+```
+
+!> Some ST7789 devices are known to have different drawing offsets -- despite being a 240x320 pixel display controller internally, some display panels are only 240x240, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered.
+
+<!-- tabs:end -->
+
+### ** Common: Surfaces **
+
+Quantum Painter has surface drivers which are able to target a buffer in RAM. In general, surfaces keep track of the "dirty" region -- the area that has been drawn to since the last flush -- so that when transferring to the display they can transfer the minimal amount of data to achieve the end result.
+
+!> These generally require significant amounts of RAM, so at large sizes and/or higher bit depths, they may not be usable on all MCUs.
+
+<!-- tabs:start -->
+
+#### ** RGB565 Surface **
+
+Enabling support for RGB565 surfaces in Quantum Painter is done by adding the following to `rules.mk`:
+
+```make
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS += rgb565_surface
+```
+
+Creating a RGB565 surface in firmware can then be done with the following API:
+
+```c
+painter_device_t qp_rgb565_make_surface(uint16_t panel_width, uint16_t panel_height, void *buffer);
+```
+
+The `buffer` is a user-supplied area of memory, and is assumed to be of the size `sizeof(uint16_t) * panel_width * panel_height`.
+
+The device handle returned from the `qp_rgb565_make_surface` function can be used to perform all other drawing operations.
+
+Example:
+
+```c
+static painter_device_t my_surface;
+static uint16_t my_framebuffer[320 * 240]; // Allocate a buffer for a 320x240 RGB565 display
+void keyboard_post_init_kb(void) {
+ my_surface = qp_rgb565_make_surface(320, 240, my_framebuffer);
+ qp_init(my_surface, QP_ROTATION_0);
+}
+```
+
+The maximum number of RGB565 surfaces can be configured by changing the following in your `config.h` (default is 1):
+
+```c
+// 3 surfaces:
+#define RGB565_SURFACE_NUM_DEVICES 3
+```
+
+To transfer the contents of the RGB565 surface to another display, the following API can be invoked:
+
+```c
+bool qp_rgb565_surface_draw(painter_device_t surface, painter_device_t display, uint16_t x, uint16_t y);
+```
+
+The `surface` is the surface to copy out from. The `display` is the target display to draw into. `x` and `y` are the target location to draw the surface pixel data. Under normal circumstances, the location should be consistent, as the dirty region is calculated with respect to the `x` and `y` coordinates -- changing those will result in partial, overlapping draws.
+
+?> Calling `qp_flush()` on the surface resets its dirty region. Copying the surface contents to the display also automatically resets the dirty region.
+
+<!-- tabs:end -->
+
+<!-- tabs:end -->
+
## Quantum Painter Drawing API :id=quantum-painter-api
All APIs require a `painter_device_t` object as their first parameter -- this object comes from the specific device initialisation, and instructions on creating it can be found in each driver's respective section.
@@ -179,7 +431,9 @@ To use any of the APIs, you need to include `qp.h`:
#include <qp.h>
```
-### General Notes :id=quantum-painter-api-general
+<!-- tabs:start -->
+
+### ** General Notes **
The coordinate system used in Quantum Painter generally accepts `left`, `top`, `right`, and `bottom` instead of x/y/width/height, and each coordinate is inclusive of where pixels should be drawn. This is required as some datatypes used by display panels have a maximum value of `255` -- for any value or geometry extent that matches `256`, this would be represented as a `0`, instead.
@@ -193,9 +447,11 @@ All color data matches the standard QMK HSV triplet definitions:
?> Colors used in Quantum Painter are not subject to the RGB lighting CIE curve, if it is enabled.
-### Device Control :id=quantum-painter-api-device-control
+### ** Device Control **
+
+<!-- tabs:start -->
-#### Display Initialisation :id=quantum-painter-api-init
+#### ** Display Initialisation **
```c
bool qp_init(painter_device_t device, painter_rotation_t rotation);
@@ -211,7 +467,7 @@ void keyboard_post_init_kb(void) {
}
```
-#### Display Power :id=quantum-painter-api-power
+#### ** Display Power **
```c
bool qp_power(painter_device_t device, bool power_on);
@@ -242,7 +498,7 @@ void suspend_wakeup_init_user(void) {
}
```
-#### Display Clear :id=quantum-painter-api-clear
+#### ** Display Clear **
```c
bool qp_clear(painter_device_t device);
@@ -250,7 +506,7 @@ bool qp_clear(painter_device_t device);
The `qp_clear` function clears the display's screen.
-#### Display Flush :id=quantum-painter-api-flush
+#### ** Display Flush **
```c
bool qp_flush(painter_device_t device);
@@ -272,9 +528,13 @@ void housekeeping_task_user(void) {
}
```
-### Drawing Primitives :id=quantum-painter-api-primitives
+<!-- tabs:end -->
-#### Set Pixel :id=quantum-painter-api-setpixel
+### ** Drawing Primitives **
+
+<!-- tabs:start -->
+
+#### ** Set Pixel **
```c
bool qp_setpixel(painter_device_t device, uint16_t x, uint16_t y, uint8_t hue, uint8_t sat, uint8_t val);
@@ -298,7 +558,7 @@ void housekeeping_task_user(void) {
}
```
-#### Draw Line :id=quantum-painter-api-line
+#### ** Draw Line **
```c
bool qp_line(painter_device_t device, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t hue, uint8_t sat, uint8_t val);
@@ -320,7 +580,7 @@ void housekeeping_task_user(void) {
}
```
-#### Draw Rect :id=quantum-painter-api-rect
+#### ** Draw Rect **
```c
bool qp_rect(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom, uint8_t hue, uint8_t sat, uint8_t val, bool filled);
@@ -342,7 +602,7 @@ void housekeeping_task_user(void) {
}
```
-#### Draw Circle :id=quantum-painter-api-circle
+#### ** Draw Circle **
```c
bool qp_circle(painter_device_t device, uint16_t x, uint16_t y, uint16_t radius, uint8_t hue, uint8_t sat, uint8_t val, bool filled);
@@ -364,7 +624,7 @@ void housekeeping_task_user(void) {
}
```
-#### Draw Ellipse :id=quantum-painter-api-ellipse
+#### ** Draw Ellipse **
```c
bool qp_ellipse(painter_device_t device, uint16_t x, uint16_t y, uint16_t sizex, uint16_t sizey, uint8_t hue, uint8_t sat, uint8_t val, bool filled);
@@ -386,9 +646,24 @@ void housekeeping_task_user(void) {
}
```
-### Image Functions :id=quantum-painter-api-images
+<!-- tabs:end -->
+
+### ** Image Functions **
-#### Load Image :id=quantum-painter-api-load-image
+Making an image available for use requires compiling it into your firmware. To do so, assuming you've created `my_image.qgf.c` and `my_image.qgf.h` as per the CLI examples above, you'd add the following to your `rules.mk`:
+
+```make
+SRC += my_image.qgf.c
+```
+
+...and in your `keymap.c`, you'd add to the top of the file:
+```c
+#include "my_image.qgf.h"
+```
+
+<!-- tabs:start -->
+
+#### ** Load Image **
```c
painter_image_handle_t qp_load_image_mem(const void *buffer);
@@ -396,7 +671,7 @@ painter_image_handle_t qp_load_image_mem(const void *buffer);
The `qp_load_image_mem` function loads a QGF image from memory or flash.
-`qp_load_image_mem` returns a handle to the loaded image, which can then be used to draw to the screen using `qp_drawimage`, `qp_drawimage_recolor`, `qp_animate`, or `qp_animate_recolor`. If an image is no longer required, it can be unloaded by calling `qp_close_image` below.
+`qp_load_image_mem` returns a handle to the loaded image, which can then be used to draw to the screen using `qp_drawimage`, `qp_drawimage_recolor`, `qp_animate`, or `qp_animate_recolor`. If an image is no longer required, it can be unloaded by calling `qp_close_image` below.
See the [CLI Commands](quantum_painter.md?id=quantum-painter-cli) for instructions on how to convert images to [QGF](quantum_painter_qgf.md).
@@ -410,7 +685,7 @@ Image information is available through accessing the handle:
| Height | `image->height` |
| Frame Count | `image->frame_count` |
-#### Unload Image :id=quantum-painter-api-close-image
+#### ** Unload Image **
```c
bool qp_close_image(painter_image_handle_t image);
@@ -418,7 +693,7 @@ bool qp_close_image(painter_image_handle_t image);
The `qp_close_image` function releases resources related to the loading of the supplied image.
-#### Draw image :id=quantum-painter-api-draw-image
+#### ** Draw image **
```c
bool qp_drawimage(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image);
@@ -438,7 +713,7 @@ void keyboard_post_init_kb(void) {
}
```
-#### Animate Image :id=quantum-painter-api-animate-image
+#### ** Animate Image **
```c
deferred_token qp_animate(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image);
@@ -463,7 +738,7 @@ void keyboard_post_init_kb(void) {
}
```
-#### Stop Animation :id=quantum-painter-api-stop-animation
+#### ** Stop Animation **
```c
void qp_stop_animation(deferred_token anim_token);
@@ -478,9 +753,24 @@ void housekeeping_task_user(void) {
}
```
-### Font Functions :id=quantum-painter-api-fonts
+<!-- tabs:end -->
+
+### ** Font Functions **
-#### Load Font :id=quantum-painter-api-load-font
+Making a font available for use requires compiling it into your firmware. To do so, assuming you've created `my_font.qff.c` and `my_font.qff.h` as per the CLI examples above, you'd add the following to your `rules.mk`:
+
+```make
+SRC += noto11.qff.c
+```
+
+...and in your `keymap.c`, you'd add to the top of the file:
+```c
+#include "noto11.qff.h"
+```
+
+<!-- tabs: start -->
+
+#### ** Load Font **
```c
painter_font_handle_t qp_load_font_mem(const void *buffer);
@@ -488,7 +778,7 @@ painter_font_handle_t qp_load_font_mem(const void *buffer);
The `qp_load_font_mem` function loads a QFF font from memory or flash.
-`qp_load_font_mem` returns a handle to the loaded font, which can then be measured using `qp_textwidth`, or drawn to the screen using `qp_drawtext`, or `qp_drawtext_recolor`. If a font is no longer required, it can be unloaded by calling `qp_close_font` below.
+`qp_load_font_mem` returns a handle to the loaded font, which can then be measured using `qp_textwidth`, or drawn to the screen using `qp_drawtext`, or `qp_drawtext_recolor`. If a font is no longer required, it can be unloaded by calling `qp_close_font` below.
See the [CLI Commands](quantum_painter.md?id=quantum-painter-cli) for instructions on how to convert TTF fonts to [QFF](quantum_painter_qff.md).
@@ -500,7 +790,7 @@ Font information is available through accessing the handle:
|-------------|----------------------|
| Line Height | `image->line_height` |
-#### Unload Font :id=quantum-painter-api-close-font
+#### ** Unload Font **
```c
bool qp_close_font(painter_font_handle_t font);
@@ -508,7 +798,7 @@ bool qp_close_font(painter_font_handle_t font);
The `qp_close_font` function releases resources related to the loading of the supplied font.
-#### Measure Text :id=quantum-painter-api-textwidth
+#### ** Measure Text **
```c
int16_t qp_textwidth(painter_font_handle_t font, const char *str);
@@ -516,7 +806,7 @@ int16_t qp_textwidth(painter_font_handle_t font, const char *str);
The `qp_textwidth` function allows measurement of how many pixels wide the supplied string would result in, for the given font.
-#### Draw Text :id=quantum-painter-api-drawtext
+#### ** Draw Text **
```c
int16_t qp_drawtext(painter_device_t device, uint16_t x, uint16_t y, painter_font_handle_t font, const char *str);
@@ -529,7 +819,7 @@ The `qp_drawtext` and `qp_drawtext_recolor` functions draw the supplied string t
// Draw a text message on the bottom-right of the 240x320 display on initialisation
static painter_font_handle_t my_font;
void keyboard_post_init_kb(void) {
- my_font = qp_load_font_mem(font_opensans);
+ my_font = qp_load_font_mem(font_noto11);
if (my_font != NULL) {
static const char *text = "Hello from QMK!";
int16_t width = qp_textwidth(my_font, text);
@@ -538,9 +828,13 @@ void keyboard_post_init_kb(void) {
}
```
-### Advanced Functions :id=quantum-painter-api-advanced
+<!-- tabs:end -->
+
+### ** Advanced Functions **
-#### Get Geometry :id=quantum-painter-api-get-geometry
+<!-- tabs:start -->
+
+#### ** Get Geometry **
```c
void qp_get_geometry(painter_device_t device, uint16_t *width, uint16_t *height, painter_rotation_t *rotation, uint16_t *offset_x, uint16_t *offset_y);
@@ -548,7 +842,7 @@ void qp_get_geometry(painter_device_t device, uint16_t *width, uint16_t *height,
The `qp_get_geometry` function allows external code to retrieve the current width, height, rotation, and drawing offsets.
-#### Set Viewport Offsets :id=quantum-painter-api-set-viewport
+#### ** Set Viewport Offsets **
```c
void qp_set_viewport_offsets(painter_device_t device, uint16_t offset_x, uint16_t offset_y);
@@ -556,7 +850,7 @@ void qp_set_viewport_offsets(painter_device_t device, uint16_t offset_x, uint16_
The `qp_set_viewport_offsets` function can be used to offset all subsequent drawing operations. For example, if a display controller is internally 240x320, but the display panel is 240x240 and has a Y offset of 80 pixels, you could invoke `qp_set_viewport_offsets(display, 0, 80);` and the drawing positioning would be corrected.
-#### Set Viewport :id=quantum-painter-api-viewport
+#### ** Set Viewport **
```c
bool qp_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom);
@@ -564,7 +858,7 @@ bool qp_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t
The `qp_viewport` function controls where raw pixel data is written to.
-#### Stream Pixel Data :id=quantum-painter-api-pixdata
+#### ** Stream Pixel Data **
```c
bool qp_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count);
@@ -574,184 +868,6 @@ The `qp_pixdata` function allows raw pixel data to be streamed to the display. I
!> Under normal circumstances, users will not need to manually call either `qp_viewport` or `qp_pixdata`. These allow for writing of raw pixel information, in the display panel's native format, to the area defined by the viewport.
-## Quantum Painter Display Drivers :id=quantum-painter-drivers
-
-### Common: Standard TFT (SPI + D/C + RST)
-
-Most TFT display panels use a 5-pin interface -- SPI SCK, SPI MOSI, SPI CS, D/C, and RST pins.
-
-For these displays, QMK's `spi_master` must already be correctly configured for the platform you're building for.
-
-The pin assignments for SPI CS, D/C, and RST are specified during device construction.
-
-### GC9A01 :id=qp-driver-gc9a01
-
-Enabling support for the GC9A01 in Quantum Painter is done by adding the following to `rules.mk`:
-
-```make
-QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS = gc9a01_spi
-```
-
-Creating a GC9A01 device in firmware can then be done with the following API:
-
-```c
-painter_device_t qp_gc9a01_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
-```
-
-The device handle returned from the `qp_gc9a01_make_spi_device` function can be used to perform all other drawing operations.
-
-The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
-
-```c
-// 3 displays:
-#define GC9A01_NUM_DEVICES 3
-```
-
-### ILI9163 :id=qp-driver-ili9163
-
-Enabling support for the ILI9163 in Quantum Painter is done by adding the following to `rules.mk`:
-
-```make
-QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS = ili9163_spi
-```
-
-Creating a ILI9163 device in firmware can then be done with the following API:
-
-```c
-painter_device_t qp_ili9163_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
-```
-
-The device handle returned from the `qp_ili9163_make_spi_device` function can be used to perform all other drawing operations.
-
-The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
-
-```c
-// 3 displays:
-#define ILI9163_NUM_DEVICES 3
-```
-
-### ILI9341 :id=qp-driver-ili9341
-
-Enabling support for the ILI9341 in Quantum Painter is done by adding the following to `rules.mk`:
-
-```make
-QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS = ili9341_spi
-```
-
-Creating a ILI9341 device in firmware can then be done with the following API:
-
-```c
-painter_device_t qp_ili9341_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
-```
-
-The device handle returned from the `qp_ili9341_make_spi_device` function can be used to perform all other drawing operations.
-
-The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
-
-```c
-// 3 displays:
-#define ILI9341_NUM_DEVICES 3
-```
-
-### ILI9488 :id=qp-driver-ili9488
-
-Enabling support for the ILI9488 in Quantum Painter is done by adding the following to `rules.mk`:
-
-```make
-QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS = ili9488_spi
-```
-
-Creating a ILI9488 device in firmware can then be done with the following API:
-
-```c
-painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
-```
-
-The device handle returned from the `qp_ili9488_make_spi_device` function can be used to perform all other drawing operations.
-
-The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
-
-```c
-// 3 displays:
-#define ILI9488_NUM_DEVICES 3
-```
-
-### SSD1351 :id=qp-driver-ssd1351
-
-Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`:
-
-```make
-QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS = ssd1351_spi
-```
-
-Creating a SSD1351 device in firmware can then be done with the following API:
-
-```c
-painter_device_t qp_ssd1351_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
-```
-
-The device handle returned from the `qp_ssd1351_make_spi_device` function can be used to perform all other drawing operations.
-
-The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
-
-```c
-// 3 displays:
-#define SSD1351_NUM_DEVICES 3
-```
-
-### ST7789 :id=qp-driver-st7789
-
-Enabling support for the ST7789 in Quantum Painter is done by adding the following to `rules.mk`:
-
-```make
-QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS = st7789_spi
-```
-
-Creating a ST7789 device in firmware can then be done with the following API:
-
-```c
-painter_device_t qp_st7789_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
-```
-
-The device handle returned from the `qp_st7789_make_spi_device` function can be used to perform all other drawing operations.
-
-The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
-
-```c
-// 3 displays:
-#define ST7789_NUM_DEVICES 3
-```
-
-!> Some ST7789 devices are known to have different drawing offsets -- despite being a 240x320 pixel display controller internally, some display panels are only 240x240, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered.
-
-### ST7735 :id=qp-driver-st7735
-
-Enabling support for the ST7735 in Quantum Painter is done by adding the following to `rules.mk`:
-
-```make
-QUANTUM_PAINTER_ENABLE = yes
-QUANTUM_PAINTER_DRIVERS = st7735_spi
-```
-
-Creating a ST7735 device in firmware can then be done with the following API:
-
-```c
-painter_device_t qp_st7735_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
-```
-
-The device handle returned from the `qp_st7735_make_spi_device` function can be used to perform all other drawing operations.
-
-The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
-
-```c
-// 3 displays:
-#define ST7735_NUM_DEVICES 3
-```
+<!-- tabs:end -->
-!> Some ST7735 devices are known to have different drawing offsets -- despite being a 132x162 pixel display controller internally, some display panels are only 80x160, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered. \ No newline at end of file
+<!-- tabs:end -->
diff --git a/docs/ref_functions.md b/docs/ref_functions.md
index c375ecd057..c82c5747c2 100644
--- a/docs/ref_functions.md
+++ b/docs/ref_functions.md
@@ -97,7 +97,7 @@ To reset to the bootloader use `QK_BOOTLOADER` or `QK_BOOT` keycode or `reset_ke
## Wiping the EEPROM (Persistent Storage)
-If you're having issues with Audio, RGB Underglow, backlighting or keys acting weird, then you can reset the EEPROM (persistent setting storage). To force an EEPROM reset, use the [`EEP_RST` keycode](quantum_keycodes.md) or [Bootmagic Lite](feature_bootmagic.md) functionality. If neither of those are an option, then you can use a custom macro to do so.
+If you're having issues with Audio, RGB Underglow, backlighting or keys acting weird, then you can reset the EEPROM (persistent setting storage). To force an EEPROM reset, use the [`EE_CLR` keycode](quantum_keycodes.md) or [Bootmagic Lite](feature_bootmagic.md) functionality. If neither of those are an option, then you can use a custom macro to do so.
To wipe the EEPROM, run `eeconfig_init()` from your function or macro to reset most of the settings to default.
diff --git a/docs/squeezing_avr.md b/docs/squeezing_avr.md
index bb8e460024..caf18002c0 100644
--- a/docs/squeezing_avr.md
+++ b/docs/squeezing_avr.md
@@ -192,6 +192,7 @@ That said, there are a number of Pro Micro replacements with ARM controllers:
* [Adafruit KB2040](https://learn.adafruit.com/adafruit-kb2040)
* [SparkFun Pro Micro - RP2040](https://www.sparkfun.com/products/18288)
* [Blok](https://boardsource.xyz/store/628b95b494dfa308a6581622)
+* [Elite-Pi](https://keeb.io/products/elite-pi-usb-c-pro-micro-replacement-rp2040)
There are other, non-Pro Micro compatible boards out there. The most popular being:
* [WeAct Blackpill F411](https://www.aliexpress.com/item/1005001456186625.html) (~$6 USD)