summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/_summary.md1
-rw-r--r--docs/config_options.md6
-rw-r--r--docs/feature_autocorrect.md295
-rw-r--r--docs/feature_combo.md2
-rw-r--r--docs/feature_converters.md52
-rw-r--r--docs/feature_encoders.md14
-rw-r--r--docs/feature_pointing_device.md30
-rw-r--r--docs/feature_ps2_mouse.md18
-rw-r--r--docs/feature_unicode.md13
-rw-r--r--docs/ja/feature_ps2_mouse.md16
-rw-r--r--docs/keycodes.md2
-rw-r--r--docs/keycodes_basic.md2
-rw-r--r--docs/quantum_painter.md566
-rw-r--r--docs/squeezing_avr.md1
14 files changed, 757 insertions, 261 deletions
diff --git a/docs/_summary.md b/docs/_summary.md
index a0d2b2a949..ca6fb91a79 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/config_options.md b/docs/config_options.md
index 3e011a5cc9..05e27a835c 100644
--- a/docs/config_options.md
+++ b/docs/config_options.md
@@ -39,11 +39,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
diff --git a/docs/feature_autocorrect.md b/docs/feature_autocorrect.md
new file mode 100644
index 0000000000..480131e5fc
--- /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 `AUTOCORRECT_TOGGLE` 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 `AUTOCORRECT_TOGGLE` keycode to toggle the on/off status for Autocorrect.
+
+### Keycodes :id=keycodes
+
+|Keycode | Short keycode | Description |
+|---------------------|---------------|------------------------------------------------|
+|`AUTOCORRECT_ON` | `CRT_ON` | Turns on the Autocorrect feature. |
+|`AUTOCORRECT_OFF` | `CRT_OFF` | Turns off the Autocorrect feature. |
+|`AUTOCORRECT_TOGGLE` | `CRT_TOG` | 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_combo.md b/docs/feature_combo.md
index 42d965509b..bb0b5d7aa0 100644
--- a/docs/feature_combo.md
+++ b/docs/feature_combo.md
@@ -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_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_pointing_device.md b/docs/feature_pointing_device.md
index 999dd1272d..f2a8994fd2 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.
@@ -487,3 +487,13 @@ 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).
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_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/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..9121385f1a 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/>
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/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/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)