diff options
Diffstat (limited to 'docs')
52 files changed, 1586 insertions, 483 deletions
diff --git a/docs/_summary.md b/docs/_summary.md index 9798ef5127..7e6c062136 100644 --- a/docs/_summary.md +++ b/docs/_summary.md @@ -60,6 +60,7 @@ * [Language-Specific Keycodes](reference_keymap_extras.md) * [Modifier Keys](feature_advanced_keycodes.md) * [Quantum Keycodes](quantum_keycodes.md) + * [Magic Keycodes](keycodes_magic.md) * Advanced Keycodes * [Command](feature_command.md) @@ -77,6 +78,7 @@ * [Combos](feature_combo.md) * [Debounce API](feature_debounce_type.md) * [Key Lock](feature_key_lock.md) + * [Key Overrides](feature_key_overrides.md) * [Layers](feature_layers.md) * [One Shot Keys](one_shot_keys.md) * [Pointing Device](feature_pointing_device.md) @@ -93,6 +95,7 @@ * Hardware Features * Displays * [HD44780 LCD Controller](feature_hd44780.md) + * [ST7565 LCD Driver](feature_st7565.md) * [OLED Driver](feature_oled_driver.md) * Lighting * [Backlight](feature_backlight.md) @@ -101,7 +104,7 @@ * [RGB Matrix](feature_rgb_matrix.md) * [Audio](feature_audio.md) * [Bluetooth](feature_bluetooth.md) - * [Bootmagic](feature_bootmagic.md) + * [Bootmagic Lite](feature_bootmagic.md) * [Custom Matrix](custom_matrix.md) * [DIP Switch](feature_dip_switch.md) * [Encoders](feature_encoders.md) diff --git a/docs/breaking_changes.md b/docs/breaking_changes.md index b0d56a81bd..a1a56bd457 100644 --- a/docs/breaking_changes.md +++ b/docs/breaking_changes.md @@ -100,3 +100,7 @@ This happens immediately after the previous `develop` branch is merged. * [ ] `git pull --ff-only` * [ ] `git merge --no-ff develop` * [ ] `git push upstream master` + +## Post-merge operations + +* (Optional) [update ChibiOS + ChibiOS-Contrib on `develop`](chibios_upgrade_instructions.md) diff --git a/docs/chibios_upgrade_instructions.md b/docs/chibios_upgrade_instructions.md new file mode 100644 index 0000000000..40c2faafcf --- /dev/null +++ b/docs/chibios_upgrade_instructions.md @@ -0,0 +1,56 @@ +# ChibiOS Upgrade Procedure + +ChibiOS and ChibiOS-Contrib need to be updated in tandem -- the latter has a branch tied to the ChibiOS version in use and should not be mixed with different versions. + +## Getting ChibiOS + +* `svn` Initialisation: + * Only needed to be done once + * You might need to separately install `git-svn` package in your OS's package manager + * `git svn init --stdlayout --prefix='svn/' http://svn.osdn.net/svnroot/chibios/` + * `git remote add qmk git@github.com:qmk/ChibiOS.git` +* Updating: + * `git svn fetch` + * First time around this will take several hours + * Subsequent updates will be incremental only +* Tagging example (work out which version first!): + * `git tag -a ver20.3.3 -m ver20.3.3 svn/tags/ver20.3.3` + * `git push qmk ver20.3.3` + * `git tag -a breaking_YYYY_qN -m breaking_YYYY_qN svn/tags/ver20.3.3` + * `git push qmk breaking_YYYY_qN` + +## Getting ChibiOS-Contrib + +* `git` Initialisation: + * `git clone git@github.com:qmk/ChibiOS-Contrib` + * `git remote add upstream https://github.com/ChibiOS/ChibiOS-Contrib` + * `git checkout -b chibios-20.3.x upstream/chibios-20.3.x` +* Updating: + * `git fetch --all --tags --prune` + * `git checkout chibios-20.3.x` + * `git pull --ff-only` + * `git push origin chibios-20.3.x` + * `git tag -a breaking_YYYY_qN -m breaking_YYYY_qN chibios-20.3.x` + * `git push origin breaking_YYYY_qN` + +## Updating submodules + +* Update the submodules + * `cd $QMK_FIRMWARE` + * `git checkout develop` + * `git pull --ff-only` + * `git checkout -b chibios-version-bump` + * `cd lib/chibios` + * `git fetch --all --tags --prune` + * `git checkout breaking_YYYY_qN` + * `cd ../chibios-contrib` + * `git fetch --all --tags --prune` + * `git checkout breaking_YYYY_qN` +* Build everything + * `cd $QMK_FIRMWARE` + * `qmk multibuild -j4` + * Make sure there are no errors +* Push to the repo + * `git commit -am 'Update ChibiOS to XXXXXXXXX'` + * `git push --set-upstream origin chibios-version-bump` +* Make a PR to qmk_firmware with the new branch
\ No newline at end of file diff --git a/docs/cli_commands.md b/docs/cli_commands.md index 4e27622c74..c7468eb5e7 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -109,7 +109,7 @@ qmk config [-ro] [config_token1] [config_token2] [...] [config_tokenN] ## `qmk console` -This command lets you connect to keyboard consoles to get debugging messages. It only works if your keyboard firmware has been compiled with `CONSOLE_ENABLED=yes`. +This command lets you connect to keyboard consoles to get debugging messages. It only works if your keyboard firmware has been compiled with `CONSOLE_ENABLE=yes`. **Usage**: @@ -280,12 +280,12 @@ qmk list-keymaps -kb planck/ez This command creates a new keyboard based on available templates. -This command will prompt for input to guide you though the generation process. +Any arguments that are not provided will prompt for input. If `-u` is not passed and `user.name` is set in .gitconfig, it will be used as the default username in the prompt. **Usage**: ``` -qmk new-keyboard +qmk new-keyboard [-kb KEYBOARD] [-t {avr,ps2avrgb}] -u USERNAME ``` ## `qmk new-keymap` @@ -314,7 +314,18 @@ qmk clean [-a] # Developer Commands -## `qmk cformat` +## `qmk format-text` + +This command formats text files to have proper line endings. + +Every text file in the repository needs to have Unix (LF) line ending. +If you are working on **Windows**, you must ensure that line endings are corrected in order to get your PRs merged. + +``` +qmk format-text +``` + +## `qmk format-c` This command formats C code using clang-format. @@ -325,25 +336,25 @@ Run it with `-a` to format all core code, or pass filenames on the command line **Usage for specified files**: ``` -qmk cformat [file1] [file2] [...] [fileN] +qmk format-c [file1] [file2] [...] [fileN] ``` **Usage for all core files**: ``` -qmk cformat -a +qmk format-c -a ``` **Usage for only changed files against origin/master**: ``` -qmk cformat +qmk format-c ``` **Usage for only changed files against branch_name**: ``` -qmk cformat -b branch_name +qmk format-c -b branch_name ``` ## `qmk docs` @@ -369,7 +380,7 @@ qmk generate-docs ## `qmk generate-rgb-breathe-table` -This command generates a lookup table (LUT) header file for the [RGB Lighting](feature_rgblight.md) feature's breathing animation. Place this file in your keyboard or keymap directory as `rgblight_breathe_table.h` to override the default LUT in `quantum/`. +This command generates a lookup table (LUT) header file for the [RGB Lighting](feature_rgblight.md) feature's breathing animation. Place this file in your keyboard or keymap directory as `rgblight_breathe_table.h` to override the default LUT in `quantum/rgblight/`. **Usage**: @@ -399,14 +410,14 @@ $ qmk kle2json -f kle.txt -f Ψ Wrote out to info.json ``` -## `qmk pyformat` +## `qmk format-python` This command formats python code in `qmk_firmware`. **Usage**: ``` -qmk pyformat +qmk format-python ``` ## `qmk pytest` diff --git a/docs/cli_development.md b/docs/cli_development.md index 07c8f281ba..0f4f401b33 100644 --- a/docs/cli_development.md +++ b/docs/cli_development.md @@ -188,7 +188,7 @@ cli.log.info('Reading from %s and writing to %s', cli.args.filename, cli.args.ou # Testing, and Linting, and Formatting (oh my!) -We use nose2, flake8, and yapf to test, lint, and format code. You can use the `pytest` and `pyformat` subcommands to run these tests: +We use nose2, flake8, and yapf to test, lint, and format code. You can use the `pytest` and `format-py` subcommands to run these tests: ### Testing and Linting @@ -196,7 +196,7 @@ We use nose2, flake8, and yapf to test, lint, and format code. You can use the ` ### Formatting - qmk pyformat + qmk format-py ## Formatting Details diff --git a/docs/compatible_microcontrollers.md b/docs/compatible_microcontrollers.md index 0f5b140de0..865b29feec 100644 --- a/docs/compatible_microcontrollers.md +++ b/docs/compatible_microcontrollers.md @@ -31,6 +31,8 @@ You can also use any ARM chip with USB that [ChibiOS](https://www.chibios.org) s * [STM32F446](https://www.st.com/en/microcontrollers-microprocessors/stm32f446.html) * [STM32G431](https://www.st.com/en/microcontrollers-microprocessors/stm32g4x1.html) * [STM32G474](https://www.st.com/en/microcontrollers-microprocessors/stm32g4x4.html) + * [STM32L412](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x2.html) + * [STM32L422](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x2.html) * [STM32L433](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x3.html) * [STM32L443](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x3.html) diff --git a/docs/config_options.md b/docs/config_options.md index d0f0b316e0..78c1f70fd7 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -51,8 +51,10 @@ This is a C header file that is one of the first things included, and will persi * the number of columns in your keyboard's matrix * `#define MATRIX_ROW_PINS { D0, D5, B5, B6 }` * pins of the rows, from top to bottom + * may be omitted by the keyboard designer if matrix reads are handled in an alternate manner. See [low-level matrix overrides](custom_quantum_functions.md?id=low-level-matrix-overrides) for more information. * `#define MATRIX_COL_PINS { F1, F0, B0, C7, F4, F5, F6, F7, D4, D6, B4, D7 }` * pins of the columns, from left to right + * may be omitted by the keyboard designer if matrix reads are handled in an alternate manner. See [low-level matrix overrides](custom_quantum_functions.md?id=low-level-matrix-overrides) for more information. * `#define MATRIX_IO_DELAY 30` * the delay in microseconds when between changing matrix pin state and reading values * `#define UNUSED_PINS { D1, D2, D3, B1, B2, B3 }` @@ -186,13 +188,27 @@ If you define these options you will enable the associated feature, which may in few ms of delay from this. But if you're doing chording on something with 3-4ms scan times? You probably want this. * `#define COMBO_COUNT 2` - * Set this to the number of combos that you're using in the [Combo](feature_combo.md) feature. + * Set this to the number of combos that you're using in the [Combo](feature_combo.md) feature. Or leave it undefined and programmatically set the count. * `#define COMBO_TERM 200` * how long for the Combo keys to be detected. Defaults to `TAPPING_TERM` if not defined. +* `#define COMBO_MUST_HOLD_MODS` + * Flag for enabling extending timeout on Combos containing modifers +* `#define COMBO_MOD_TERM 200` + * Allows for extending COMBO_TERM for mod keys while mid-combo. +* `#define COMBO_MUST_HOLD_PER_COMBO` + * Flag to enable per-combo COMBO_TERM extension and `get_combo_must_hold()` function +* `#define COMBO_TERM_PER_COMBO` + * Flag to enable per-combo COMBO_TERM extension and `get_combo_term()` function +* `#define COMBO_STRICT_TIMER` + * Only start the combo timer on the first key press instead of on all key presses. +* `#define COMBO_NO_TIMER` + * Disable the combo timer completely for relaxed combos. * `#define TAP_CODE_DELAY 100` * Sets the delay between `register_code` and `unregister_code`, if you're having issues with it registering properly (common on VUSB boards). The value is in milliseconds. * `#define TAP_HOLD_CAPS_DELAY 80` * Sets the delay for Tap Hold keys (`LT`, `MT`) when using `KC_CAPSLOCK` keycode, as this has some special handling on MacOS. The value is in milliseconds, and defaults to 80 ms if not defined. For macOS, you may want to set this to 200 or higher. +* `#define KEY_OVERRIDE_REPEAT_DELAY 500` + * Sets the key repeat interval for [key overrides](feature_key_overrides.md). ## RGB Light Configuration @@ -272,7 +288,7 @@ There are a few different ways to set handedness for split keyboards (listed in ### Other Options * `#define USE_I2C` - * For using I2C instead of Serial (defaults to serial) + * For using I2C instead of Serial (default is serial; serial transport is supported on ARM -- I2C is AVR-only) * `#define SOFT_SERIAL_PIN D0` * When using serial, define this. `D0` or `D1`,`D2`,`D3`,`E6`. @@ -280,6 +296,7 @@ There are a few different ways to set handedness for split keyboards (listed in * `#define MATRIX_ROW_PINS_RIGHT { <row pins> }` * `#define MATRIX_COL_PINS_RIGHT { <col pins> }` * If you want to specify a different pinout for the right half than the left half, you can define `MATRIX_ROW_PINS_RIGHT`/`MATRIX_COL_PINS_RIGHT`. Currently, the size of `MATRIX_ROW_PINS` must be the same as `MATRIX_ROW_PINS_RIGHT` and likewise for the definition of columns. + * may be omitted by the keyboard designer if matrix reads are handled in an alternate manner. See [low-level matrix overrides](custom_quantum_functions.md?id=low-level-matrix-overrides) for more information. * `#define DIRECT_PINS_RIGHT { { F1, F0, B0, C7 }, { F4, F5, F6, F7 } }` * If you want to specify a different direct pinout for the right half than the left half, you can define `DIRECT_PINS_RIGHT`. Currently, the size of `DIRECT_PINS` must be the same as `DIRECT_PINS_RIGHT`. @@ -300,7 +317,7 @@ There are a few different ways to set handedness for split keyboards (listed in * `#define SPLIT_USB_DETECT` * Detect (with timeout) USB connection when delegating master/slave * Default behavior for ARM - * Required for AVR Teensy + * Required for AVR Teensy (without hardware mods) * `#define SPLIT_USB_TIMEOUT 2000` * Maximum timeout when detecting master/slave when using `SPLIT_USB_DETECT` @@ -308,6 +325,28 @@ 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 FORCED_SYNC_THROTTLE_MS 100` + * Deadline for synchronizing data from master to slave when using the QMK-provided split transport. + +* `#define SPLIT_TRANSPORT_MIRROR` + * Mirrors the master-side matrix on the slave when using the QMK-provided split transport. + +* `#define SPLIT_LAYER_STATE_ENABLE` + * Ensures the current layer state is available on the slave when using the QMK-provided split transport. + +* `#define SPLIT_LED_STATE_ENABLE` + * Ensures the current host indicator state (caps/num/scroll) is available on the slave when using the QMK-provided split transport. + +* `#define SPLIT_MODS_ENABLE` + * Ensures the current modifier state (normal, weak, and oneshot) is available on the slave when using the QMK-provided split transport. + +* `#define SPLIT_WPM_ENABLE` + * Ensures the current WPM is available on the slave when using the QMK-provided split transport. + +* `#define SPLIT_TRANSACTION_IDS_KB .....` +* `#define SPLIT_TRANSACTION_IDS_USER .....` + * Allows for custom data sync with the slave when using the QMK-provided split transport. See [custom data sync between sides](feature_split_keyboard.md#custom-data-sync) for more information. + # The `rules.mk` File This is a [make](https://www.gnu.org/software/make/manual/make.html) file that is included by the top-level `Makefile`. It is used to set some information about the MCU that we will be compiling for as well as enabling and disabling certain features. @@ -375,6 +414,8 @@ Use these to enable or disable building certain features. The more you have enab * USB N-Key Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work * `AUDIO_ENABLE` * Enable the audio subsystem. +* `KEY_OVERRIDE_ENABLE` + * Enable the key override feature * `RGBLIGHT_ENABLE` * Enable keyboard underlight functionality * `LEADER_ENABLE` diff --git a/docs/custom_quantum_functions.md b/docs/custom_quantum_functions.md index 694b421e79..494e76996e 100644 --- a/docs/custom_quantum_functions.md +++ b/docs/custom_quantum_functions.md @@ -144,6 +144,14 @@ This is useful for setting up stuff that you may need elsewhere, but isn't hardw * Keyboard/Revision: `void matrix_init_kb(void)` * Keymap: `void matrix_init_user(void)` +### Low-level Matrix Overrides Function Documentation :id=low-level-matrix-overrides + +* GPIO pin initialisation: `void matrix_init_pins(void)` + * This needs to perform the low-level initialisation of all row and column pins. By default this will initialise the input/output state of each of the GPIO pins listed in `MATRIX_ROW_PINS` and `MATRIX_COL_PINS`, based on whether or not the keyboard is set up for `ROW2COL`, `COL2ROW`, or `DIRECT_PINS`. Should the keyboard designer override this function, no initialisation of pin state will occur within QMK itself, instead deferring to the keyboard's override. +* `COL2ROW`-based row reads: `void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)` +* `ROW2COL`-based column reads: `void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)` +* `DIRECT_PINS`-based reads: `void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)` + * These three functions need to perform the low-level retrieval of matrix state of relevant input pins, based on the matrix type. Only one of the functions should be implemented, if needed. By default this will iterate through `MATRIX_ROW_PINS` and `MATRIX_COL_PINS`, configuring the inputs and outputs based on whether or not the keyboard is set up for `ROW2COL`, `COL2ROW`, or `DIRECT_PINS`. Should the keyboard designer override this function, no manipulation of matrix GPIO pin state will occur within QMK itself, instead deferring to the keyboard's override. ## Keyboard Post Initialization code @@ -374,7 +382,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](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 `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. ```c void eeconfig_init_user(void) { // EEPROM is getting reset! diff --git a/docs/de/cli.md b/docs/de/cli.md index 437062ad66..7dc02d505b 100644 --- a/docs/de/cli.md +++ b/docs/de/cli.md @@ -88,14 +88,14 @@ qmk compile <configuratorExport.json> qmk compile -kb <keyboard_name> -km <keymap_name> ``` -## `qmk cformat` +## `qmk format-c` Dieser Befehl formatiert C-Code im clang-Format. Benutze ihn ohne Argumente, um den core-Code zu formatieren, oder benutze Namen von Dateien in der CLI, um den Befehl auf bestimmte Dateien anzuwenden. **Anwendung**: ``` -qmk cformat [file1] [file2] [...] [fileN] +qmk format-c [file1] [file2] [...] [fileN] ``` ## `qmk config` @@ -148,14 +148,14 @@ Dieser Befehl erstellt eine neue Keymap basierend auf einer existierenden Standa qmk new-keymap [-kb KEYBOARD] [-km KEYMAP] ``` -## `qmk pyformat` +## `qmk format-py` Dieser Befehl formatiert Python-Code in `qmk_firmware`. **Anwendung**: ``` -qmk pyformat +qmk format-py ``` ## `qmk pytest` diff --git a/docs/driver_installation_zadig.md b/docs/driver_installation_zadig.md index fd5d3e92fc..137ec8ad64 100644 --- a/docs/driver_installation_zadig.md +++ b/docs/driver_installation_zadig.md @@ -8,8 +8,8 @@ We recommend the use of the [Zadig](https://zadig.akeo.ie/) utility. If you have ## Installation -Put your keyboard into bootloader mode, either by hitting the `RESET` keycode (which may be on a different layer), or by pressing the reset switch that's usually located on the underside of the board. If your keyboard has neither, try holding Escape or Space+`B` as you plug it in (see the [Bootmagic](feature_bootmagic.md) docs for more details). Some boards use [Command](feature_command.md) instead of Bootmagic; in this case, you can enter bootloader mode by hitting Left Shift+Right Shift+`B` or Left Shift+Right Shift+Escape at any point while the keyboard is plugged in. -Some keyboards may have specific instructions for entering the bootloader. For example, the [Bootmagic Lite](feature_bootmagic.md#bootmagic-lite) key (default: Escape) might be on a different key, e.g. Left Control; or the magic combination for Command (default: Left Shift+Right Shift) might require you to hold something else, e.g. Left Control+Right Control. Refer to the board's README file if you are unsure. +Put your keyboard into bootloader mode, either by hitting the `RESET` keycode (which may be on a different layer), or by pressing the reset switch that's usually located on the underside of the board. If your keyboard has neither, try holding Escape or Space+`B` as you plug it in (see the [Bootmagic Lite](feature_bootmagic.md) docs for more details). Some boards use [Command](feature_command.md) instead of Bootmagic; in this case, you can enter bootloader mode by hitting Left Shift+Right Shift+`B` or Left Shift+Right Shift+Escape at any point while the keyboard is plugged in. +Some keyboards may have specific instructions for entering the bootloader. For example, the [Bootmagic Lite](feature_bootmagic.md) key (default: Escape) might be on a different key, e.g. Left Control; or the magic combination for Command (default: Left Shift+Right Shift) might require you to hold something else, e.g. Left Control+Right Control. Refer to the board's README file if you are unsure. To put a device in bootloader mode with USBaspLoader, tap the `RESET` button while holding down the `BOOT` button. Alternatively, hold `BOOT` while inserting the USB cable. @@ -95,3 +95,4 @@ The device name here is the name that appears in Zadig, and may not be what the |`stm32-dfu` |STM32 BOOTLOADER |`0483:DF11` |WinUSB | |`kiibohd` |Kiibohd DFU Bootloader |`1C11:B007` |WinUSB | |`stm32duino` |Maple 003 |`1EAF:0003` |WinUSB | +|`qmk-hid` |(keyboard name) Bootloader |`03EB:2067` |HidUsb | diff --git a/docs/eeprom_driver.md b/docs/eeprom_driver.md index e2c262546d..6dcf10c04d 100644 --- a/docs/eeprom_driver.md +++ b/docs/eeprom_driver.md @@ -31,6 +31,9 @@ Currently QMK supports 24xx-series chips over I2C. As such, requires a working i `#define EXTERNAL_EEPROM_PAGE_SIZE` | Page size of the EEPROM in bytes, as specified in the datasheet | 32 `#define EXTERNAL_EEPROM_ADDRESS_SIZE` | The number of bytes to transmit for the memory location within the EEPROM | 2 `#define EXTERNAL_EEPROM_WRITE_TIME` | Write cycle time of the EEPROM, as specified in the datasheet | 5 +`#define EXTERNAL_EEPROM_WP_PIN` | If defined the WP pin will be toggled appropriately when writing to the EEPROM. | _none_ + +Some I2C EEPROM manufacturers explicitly recommend against hardcoding the WP pin to ground. This is in order to protect the eeprom memory content during power-up/power-down/brown-out conditions at low voltage where the eeprom is still operational, but the i2c master output might be unpredictable. If a WP pin is configured, then having an external pull-up on the WP pin is recommended. Default values and extended descriptions can be found in `drivers/eeprom/eeprom_i2c.h`. diff --git a/docs/es/hardware_avr.md b/docs/es/hardware_avr.md index f8c426381f..ac6a715658 100644 --- a/docs/es/hardware_avr.md +++ b/docs/es/hardware_avr.md @@ -6,26 +6,28 @@ Si aún no lo has hecho, debes leer las [Pautas de teclados](hardware_keyboard_g ## Añadir tu Teclado AVR a QMK -QMK tiene varias características para simplificar el trabajo con teclados AVR. Para la mayoría de los teclados no tienes que escribir ni una sola línea de código. Para empezar, ejecuta el archivo `util/new_keyboard.sh`: +QMK tiene varias características para simplificar el trabajo con teclados AVR. Para la mayoría de los teclados no tienes que escribir ni una sola línea de código. Para empezar, ejecuta `qmk new-keyboard`: ``` -$ ./util/new_keyboard.sh -Generating a new QMK keyboard directory - -Keyboard Name: mycoolkb -Keyboard Type [avr]: -Your Name [John Smith]: - -Copying base template files... done -Copying avr template files... done -Renaming keyboard files... done -Replacing %KEYBOARD% with mycoolkb... done -Replacing %YOUR_NAME% with John Smith... done - -Created a new keyboard called mycoolkb. - -To start working on things, cd into keyboards/mycoolkb, -or open the directory in your favourite text editor. +$ qmk new-keyboard +Ψ Generating a new QMK keyboard directory + +Keyboard Name: mycoolkeeb +Keyboard Type: + 1. avr + 2. ps2avrgb +Please enter your choice: [1] +Your Name: [John Smith] +Ψ Copying base template files... +Ψ Copying avr template files... +Ψ Renaming keyboard.[ch] to mycoolkeeb.[ch]... +Ψ Replacing %YEAR% with 2021... +Ψ Replacing %KEYBOARD% with mycoolkeeb... +Ψ Replacing %YOUR_NAME% with John Smith... + +Ψ Created a new keyboard called mycoolkeeb. +Ψ To start working on things, `cd` into keyboards/mycoolkeeb, +Ψ or open the directory in your preferred text editor. ``` Esto creará todos los archivos necesarios para tu nuevo teclado, y rellenará la configuración con valores predeterminados. Ahora sólo tienes que personalizarlo para tu teclado. diff --git a/docs/faq_keymap.md b/docs/faq_keymap.md index c30e17990f..3de4cd2409 100644 --- a/docs/faq_keymap.md +++ b/docs/faq_keymap.md @@ -31,7 +31,7 @@ QMK has two features, Bootmagic and Command, which allow you to change the behav As a quick fix try holding down `Space`+`Backspace` while you plug in your keyboard. This will reset the stored settings on your keyboard, returning those keys to normal operation. If that doesn't work look here: -* [Bootmagic](feature_bootmagic.md) +* [Bootmagic Lite](feature_bootmagic.md) * [Command](feature_command.md) ## The Menu Key Isn't Working diff --git a/docs/feature_bootmagic.md b/docs/feature_bootmagic.md index 4c655d8e1c..6c66b00679 100644 --- a/docs/feature_bootmagic.md +++ b/docs/feature_bootmagic.md @@ -1,136 +1,15 @@ -# Bootmagic - -There are three separate but related features that allow you to change the behavior of your keyboard without reflashing. While each of them have similar functionality, it is accessed in different ways depending on how your keyboard is configured. - -**Bootmagic** is a system for configuring your keyboard while it initializes. To trigger a Bootmagic command, hold down the Bootmagic key and one or more command keys. - -**Bootmagic Keycodes** are prefixed with `MAGIC_`, and allow you to access the Bootmagic functionality *after* your keyboard has initialized. To use the keycodes, assign them to your keymap as you would any other keycode. - -**Command**, formerly known as **Magic**, is another feature that allows you to control different aspects of your keyboard. While it shares some functionality with Bootmagic, it also allows you to do things that Bootmagic does not, such as printing version information to the console. For more information, see [Command](feature_command.md). - -On some keyboards Bootmagic is disabled by default. If this is the case, it must be explicitly enabled in your `rules.mk` with: - -```make -BOOTMAGIC_ENABLE = full -``` - -?> You may see `yes` being used in place of `full`, and this is okay. However, `yes` is deprecated, and ideally `full` (or `lite`) should be used instead. - -Additionally, you can use [Bootmagic Lite](#bootmagic-lite) (a scaled down, very basic version of Bootmagic) by adding the following to your `rules.mk` file: - -```make -BOOTMAGIC_ENABLE = lite -``` - -## Hotkeys - -Hold down the Bootmagic key (Space by default) and the desired hotkey while plugging in your keyboard. For example, holding Space+`B` should cause it to enter the bootloader. - -|Hotkey |Description | -|------------------|---------------------------------------------| -|Escape |Ignore Bootmagic configuration in EEPROM | -|`B` |Enter the bootloader | -|`D` |Toggle debugging over serial | -|`X` |Toggle key matrix debugging | -|`K` |Toggle keyboard debugging | -|`M` |Toggle mouse debugging | -|`L` |Set "Left Hand" for EE_HANDS handedness | -|`R` |Set "Right Hand" for EE_HANDS handedness | -|Backspace |Clear the EEPROM | -|Caps Lock |Toggle treating Caps Lock as Left Control | -|Left Control |Toggle swapping Caps Lock and Left Control | -|Left Alt |Toggle swapping Left Alt and Left GUI | -|Right Alt |Toggle swapping Right Alt and Right GUI | -|Left GUI |Toggle the GUI keys (useful when gaming) | -|<code>`</code>|Toggle swapping <code>`</code> and Escape| -|`\` |Toggle swapping `\` and Backspace | -|`N` |Toggle N-Key Rollover (NKRO) | -|`0` |Make layer 0 the default layer | -|`1` |Make layer 1 the default layer | -|`2` |Make layer 2 the default layer | -|`3` |Make layer 3 the default layer | -|`4` |Make layer 4 the default layer | -|`5` |Make layer 5 the default layer | -|`6` |Make layer 6 the default layer | -|`7` |Make layer 7 the default layer | - -## Keycodes :id=keycodes - -|Key |Aliases |Description | -|----------------------------------|---------|--------------------------------------------------------------------------| -|`MAGIC_SWAP_CONTROL_CAPSLOCK` |`CL_SWAP`|Swap Caps Lock and Left Control | -|`MAGIC_UNSWAP_CONTROL_CAPSLOCK` |`CL_NORM`|Unswap Caps Lock and Left Control | -|`MAGIC_CAPSLOCK_TO_CONTROL` |`CL_CTRL`|Treat Caps Lock as Control | -|`MAGIC_UNCAPSLOCK_TO_CONTROL` |`CL_CAPS`|Stop treating Caps Lock as Control | -|`MAGIC_SWAP_LCTL_LGUI` |`LCG_SWP`|Swap Left Control and GUI | -|`MAGIC_UNSWAP_LCTL_LGUI` |`LCG_NRM`|Unswap Left Control and GUI | -|`MAGIC_SWAP_RCTL_RGUI` |`RCG_SWP`|Swap Right Control and GUI | -|`MAGIC_UNSWAP_RCTL_RGUI` |`RCG_NRM`|Unswap Right Control and GUI | -|`MAGIC_SWAP_CTL_GUI` |`CG_SWAP`|Swap Control and GUI on both sides | -|`MAGIC_UNSWAP_CTL_GUI` |`CG_NORM`|Unswap Control and GUI on both sides | -|`MAGIC_TOGGLE_CTL_GUI` |`CG_TOGG`|Toggle Control and GUI swap on both sides | -|`MAGIC_SWAP_LALT_LGUI` |`LAG_SWP`|Swap Left Alt and GUI | -|`MAGIC_UNSWAP_LALT_LGUI` |`LAG_NRM`|Unswap Left Alt and GUI | -|`MAGIC_SWAP_RALT_RGUI` |`RAG_SWP`|Swap Right Alt and GUI | -|`MAGIC_UNSWAP_RALT_RGUI` |`RAG_NRM`|Unswap Right Alt and GUI | -|`MAGIC_SWAP_ALT_GUI` |`AG_SWAP`|Swap Alt and GUI on both sides | -|`MAGIC_UNSWAP_ALT_GUI` |`AG_NORM`|Unswap Alt and GUI on both sides | -|`MAGIC_TOGGLE_ALT_GUI` |`AG_TOGG`|Toggle Alt and GUI swap on both sides | -|`MAGIC_NO_GUI` |`GUI_OFF`|Disable the GUI keys | -|`MAGIC_UNNO_GUI` |`GUI_ON` |Enable the GUI keys | -|`MAGIC_SWAP_GRAVE_ESC` |`GE_SWAP`|Swap <code>`</code> and Escape | -|`MAGIC_UNSWAP_GRAVE_ESC` |`GE_NORM`|Unswap <code>`</code> and Escape | -|`MAGIC_SWAP_BACKSLASH_BACKSPACE` |`BS_SWAP`|Swap `\` and Backspace | -|`MAGIC_UNSWAP_BACKSLASH_BACKSPACE`|`BS_NORM`|Unswap `\` and Backspace | -|`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 | -|`MAGIC_EE_HANDS_LEFT` |`EH_LEFT`|Set the master half of a split keyboard as the left hand (for `EE_HANDS`) | -|`MAGIC_EE_HANDS_RIGHT` |`EH_RGHT`|Set the master half of a split keyboard as the right hand (for `EE_HANDS`)| - -## Configuration - -If you would like to change the hotkey assignments for Bootmagic, `#define` these in your `config.h` at either the keyboard or keymap level. - -|Define |Default |Description | -|----------------------------------------|-------------|---------------------------------------------------| -|`BOOTMAGIC_KEY_SALT` |`KC_SPACE` |The Bootmagic key | -|`BOOTMAGIC_KEY_SKIP` |`KC_ESC` |Ignore Bootmagic configuration in EEPROM | -|`BOOTMAGIC_KEY_EEPROM_CLEAR` |`KC_BSPACE` |Clear the EEPROM configuration | -|`BOOTMAGIC_KEY_BOOTLOADER` |`KC_B` |Enter the bootloader | -|`BOOTMAGIC_KEY_DEBUG_ENABLE` |`KC_D` |Toggle debugging over serial | -|`BOOTMAGIC_KEY_DEBUG_MATRIX` |`KC_X` |Toggle matrix debugging | -|`BOOTMAGIC_KEY_DEBUG_KEYBOARD` |`KC_K` |Toggle keyboard debugging | -|`BOOTMAGIC_KEY_DEBUG_MOUSE` |`KC_M` |Toggle mouse debugging | -|`BOOTMAGIC_KEY_EE_HANDS_LEFT` |`KC_L` |Set "Left Hand" for EE_HANDS handedness | -|`BOOTMAGIC_KEY_EE_HANDS_RIGHT` |`KC_R` |Set "Right Hand" for EE_HANDS handedness | -|`BOOTMAGIC_KEY_SWAP_CONTROL_CAPSLOCK` |`KC_LCTRL` |Swap Left Control and Caps Lock | -|`BOOTMAGIC_KEY_CAPSLOCK_TO_CONTROL` |`KC_CAPSLOCK`|Toggle treating Caps Lock as Left Control | -|`BOOTMAGIC_KEY_SWAP_LALT_LGUI` |`KC_LALT` |Toggle swapping Left Alt and Left GUI (for macOS) | -|`BOOTMAGIC_KEY_SWAP_RALT_RGUI` |`KC_RALT` |Toggle swapping Right Alt and Right GUI (for macOS)| -|`BOOTMAGIC_KEY_NO_GUI` |`KC_LGUI` |Toggle the GUI keys (useful when gaming) | -|`BOOTMAGIC_KEY_SWAP_GRAVE_ESC` |`KC_GRAVE` |Toggle swapping <code>`</code> and Escape | -|`BOOTMAGIC_KEY_SWAP_BACKSLASH_BACKSPACE`|`KC_BSLASH` |Toggle swapping `\` and Backspace | -|`BOOTMAGIC_HOST_NKRO` |`KC_N` |Toggle N-Key Rollover (NKRO) | -|`BOOTMAGIC_KEY_DEFAULT_LAYER_0` |`KC_0` |Make layer 0 the default layer | -|`BOOTMAGIC_KEY_DEFAULT_LAYER_1` |`KC_1` |Make layer 1 the default layer | -|`BOOTMAGIC_KEY_DEFAULT_LAYER_2` |`KC_2` |Make layer 2 the default layer | -|`BOOTMAGIC_KEY_DEFAULT_LAYER_3` |`KC_3` |Make layer 3 the default layer | -|`BOOTMAGIC_KEY_DEFAULT_LAYER_4` |`KC_4` |Make layer 4 the default layer | -|`BOOTMAGIC_KEY_DEFAULT_LAYER_5` |`KC_5` |Make layer 5 the default layer | -|`BOOTMAGIC_KEY_DEFAULT_LAYER_6` |`KC_6` |Make layer 6 the default layer | -|`BOOTMAGIC_KEY_DEFAULT_LAYER_7` |`KC_7` |Make layer 7 the default layer | - # Bootmagic Lite :id=bootmagic-lite -In addition to the full blown Bootmagic feature, is the Bootmagic Lite feature that only handles jumping into the bootloader. This is great for boards that don't have a physical reset button but you need a way to jump into the bootloader, and don't want to deal with the headache that Bootmagic can cause. +The Bootmagic Lite feature that only handles jumping into the bootloader. This is great for boards that don't have a physical reset button, giving you a way to jump into the bootloader -To enable this version of Bootmagic, you need to enable it in your `rules.mk` with: +On some keyboards Bootmagic Lite is disabled by default. If this is the case, it must be explicitly enabled in your `rules.mk` with: ```make -BOOTMAGIC_ENABLE = lite +BOOTMAGIC_ENABLE = yes ``` +?> You may see `lite` being used in place of `yes`. + Additionally, you may want to specify which key to use. This is especially useful for keyboards that have unusual matrices. To do so, you need to specify the row and column of the key that you want to use. Add these entries to your `config.h` file: ```c @@ -142,7 +21,7 @@ By default, these are set to 0 and 0, which is usually the "ESC" key on a majori And to trigger the bootloader, you hold this key down when plugging the keyboard in. Just the single key. -!> Using bootmagic lite will **always reset** the EEPROM, so you will lose any settings that have been saved. +!> Using Bootmagic Lite will **always reset** the EEPROM, so you will lose any settings that have been saved. ## Split Keyboards @@ -174,4 +53,10 @@ void bootmagic_lite(void) { } ``` -You can additional feature here. For instance, resetting the eeprom or requiring additional keys to be pressed to trigger bootmagic. Keep in mind that `bootmagic_lite` is called before a majority of features are initialized in the firmware. +You can additional feature here. For instance, resetting the EEPROM or requiring additional keys to be pressed to trigger Bootmagic Lite. Keep in mind that `bootmagic_lite` is called before a majority of features are initialized in the firmware. + +## Addenda + +To manipulate settings that were formerly configured through the now-deprecated full Bootmagic feature, see [Magic Keycodes](keycodes_magic.md). + +The Command feature, formerly known as Magic, also allows you to control different aspects of your keyboard. While it shares some functionality with Magic Keycodes, it also allows you to do things that Magic Keycodes cannot, such as printing version information to the console. For more information, see [Command](feature_command.md). diff --git a/docs/feature_combo.md b/docs/feature_combo.md index d831328f69..d98e6f2ac7 100644 --- a/docs/feature_combo.md +++ b/docs/feature_combo.md @@ -1,24 +1,39 @@ # Combos -The Combo feature is a chording type solution for adding custom actions. It lets you hit multiple keys at once and produce a different effect. For instance, hitting `A` and `S` within the tapping term would hit `ESC` instead, or have it perform even more complex tasks. +The Combo feature is a chording type solution for adding custom actions. It lets you hit multiple keys at once and produce a different effect. For instance, hitting `A` and `S` within the combo term would hit `ESC` instead, or have it perform even more complex tasks. To enable this feature, you need to add `COMBO_ENABLE = yes` to your `rules.mk`. -Additionally, in your `config.h`, you'll need to specify the number of combos that you'll be using, by adding `#define COMBO_COUNT 1` (replacing 1 with the number that you're using). -<!-- At this time, this is necessary --> +Additionally, in your `config.h`, you'll need to specify the number of combos that you'll be using, by adding `#define COMBO_COUNT 1` (replacing 1 with the number that you're using). It is also possible to not define this and instead set the variable `COMBO_LEN` yourself. There's a trick where we don't need to think about this variable at all. More on this later. -Also, by default, the tapping term for the Combos is set to the same value as `TAPPING_TERM` (200 by default on most boards). But you can specify a different value by defining it in your `config.h`. For instance: `#define COMBO_TERM 300` would set the time out period for combos to 300ms. -Then, your `keymap.c` file, you'll need to define a sequence of keys, terminated with `COMBO_END`, and a structure to list the combination of keys, and it's resulting action. +Then, in your `keymap.c` file, you'll need to define a sequence of keys, terminated with `COMBO_END`, and a structure to list the combination of keys, and its resulting action. ```c -const uint16_t PROGMEM test_combo[] = {KC_A, KC_B, COMBO_END}; -combo_t key_combos[COMBO_COUNT] = {COMBO(test_combo, KC_ESC)}; +const uint16_t PROGMEM test_combo1[] = {KC_A, KC_B, COMBO_END}; +const uint16_t PROGMEM test_combo2[] = {KC_C, KC_D, COMBO_END}; +combo_t key_combos[COMBO_COUNT] = { + COMBO(test_combo1, KC_ESC), + COMBO(test_combo2, LCTL(KC_Z)), // keycodes with modifiers are possible too! +}; ``` -This will send "Escape" if you hit the A and B keys. +This will send "Escape" if you hit the A and B keys, and Ctrl+Z when you hit the C and D keys. + +As of [PR#8591](https://github.com/qmk/qmk_firmware/pull/8591/), it is possible to fire combos from ModTap keys and LayerTap keys. So in the above example you could have keys `LSFT_T(KC_A)` and `LT(_LAYER, KC_B)` and it would work. So Home Row Mods and Home Row Combos at same time is now a thing! -!> This method only supports [basic keycodes](keycodes_basic.md). See the examples for more control. +It is also now possible to overlap combos. Before, with the example below both combos would activate when all three keys were pressed. Now only the three key combo will activate. + +```c +const uint16_t PROGMEM test_combo1[] = {LSFT_T(KC_A), LT(_LAYER, KC_B), COMBO_END}; +const uint16_t PROGMEM test_combo2[] = {LSFT_T(KC_A), LT(_LAYER, KC_B), KC_C, COMBO_END}; +combo_t key_combos[COMBO_COUNT] = { + COMBO(test_combo1, KC_ESC) + COMBO(test_combo2, KC_TAB) +}; +``` + +Executing more complex keycodes like ModTaps and LayerTaps is now also possible. ## Examples @@ -27,63 +42,68 @@ If you want to add a list, then you'd use something like this: ```c enum combos { AB_ESC, - JK_TAB + JK_TAB, + QW_SFT, + SD_LAYER, }; const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END}; const uint16_t PROGMEM jk_combo[] = {KC_J, KC_K, COMBO_END}; +const uint16_t PROGMEM qw_combo[] = {KC_Q, KC_W, COMBO_END}; +const uint16_t PROGMEM sd_combo[] = {KC_S, KC_D, COMBO_END}; combo_t key_combos[COMBO_COUNT] = { [AB_ESC] = COMBO(ab_combo, KC_ESC), - [JK_TAB] = COMBO(jk_combo, KC_TAB) + [JK_TAB] = COMBO(jk_combo, KC_TAB), + [QW_SFT] = COMBO(qw_combo, KC_LSFT) + [SD_LAYER] = COMBO(layer_combo, MO(_LAYER)), }; ``` For a more complicated implementation, you can use the `process_combo_event` function to add custom handling. +Additionally, this example shows how you can leave `COMBO_COUNT` undefined. ```c enum combo_events { - ZC_COPY, - XV_PASTE + EM_EMAIL, + BSPC_LSFT_CLEAR, + COMBO_LENGTH }; +uint16_t COMBO_LEN = COMBO_LENGTH; // remove the COMBO_COUNT define and use this instead! -const uint16_t PROGMEM copy_combo[] = {KC_Z, KC_C, COMBO_END}; -const uint16_t PROGMEM paste_combo[] = {KC_X, KC_V, COMBO_END}; +const uint16_t PROGMEM email_combo[] = {KC_E, KC_M, COMBO_END}; +const uint16_t PROGMEM clear_line_combo[] = {KC_BSPC, KC_LSFT, COMBO_END}; -combo_t key_combos[COMBO_COUNT] = { - [ZC_COPY] = COMBO_ACTION(copy_combo), - [XV_PASTE] = COMBO_ACTION(paste_combo), +combo_t key_combos[] = { + [EM_EMAIL] = COMBO_ACTION(email_combo), + [BSPC_LSFT_CLEAR] = COMBO_ACTION(clear_line_combo), }; +/* COMBO_ACTION(x) is same as COMBO(x, KC_NO) */ void process_combo_event(uint16_t combo_index, bool pressed) { switch(combo_index) { - case ZC_COPY: + case EM_EMAIL: if (pressed) { - tap_code16(LCTL(KC_C)); + SEND_STRING("john.doe@example.com"); } break; - case XV_PASTE: + case BSPC_LSFT_CLEAR: if (pressed) { - tap_code16(LCTL(KC_V)); + tap_code16(KC_END); + tap_code16(S(KC_HOME)); + tap_code16(KC_BSPC); } break; } } ``` -This will send Ctrl+C if you hit Z and C, and Ctrl+V if you hit X and V. But you could change this to do stuff like change layers, play sounds, or change settings. - -## Additional Configuration +This will send "john.doe@example.com" if you chord E and M together, and clear the current line with Backspace and Left-Shift. You could change this to do stuff like play sounds or change settings. -If you're using long combos, or even longer combos, you may run into issues with this, as the structure may not be large enough to accommodate what you're doing. +It is worth noting that `COMBO_ACTION`s are not needed anymore. As of [PR#8591](https://github.com/qmk/qmk_firmware/pull/8591/), it is possible to run your own custom keycodes from combos. Just define the custom keycode, program its functionality in `process_record_user`, and define a combo with `COMBO(<key_array>, <your_custom_keycode>)`. -In this case, you can add either `#define EXTRA_LONG_COMBOS` or `#define EXTRA_EXTRA_LONG_COMBOS` in your `config.h` file. - -You may also be able to enable action keys by defining `COMBO_ALLOW_ACTION_KEYS`. - -## 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. +## 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 | |----------|---------------------------------| @@ -91,6 +111,187 @@ You can enable, disable and toggle the Combo feature on the fly. This is useful |`CMB_OFF` |Turns off Combo feature | |`CMB_TOG` |Toggles Combo feature on and off | +# Advanced Configuration +These configuration settings can be set in your `config.h` file. + +## Combo Term +By default, the timeout for the Combos to be recognized is set to 50ms. This can be changed if accidental combo misfires are happening or if you're having difficulties pressing keys at the same time. For instance, `#define COMBO_TERM 40` would set the timeout period for combos to 40ms. + +## Buffer and state sizes +If you're using long combos, or you have a lot of overlapping combos, you may run into issues with this, as the buffers may not be large enough to accommodate what you're doing. In this case, you can configure the sizes of the buffers used. Be aware, larger combo sizes and larger buffers will increase memory usage! + +To configure the amount of keys a combo can be composed of, change the following: + +| Keys | Define to be set | +|------|-----------------------------------| +| 6 | `#define EXTRA_SHORT_COMBOS` | +| 8 | QMK Default | +| 16 | `#define EXTRA_LONG_COMBOS` | +| 32 | `#define EXTRA_EXTRA_LONG_COMBOS` | + +Defining `EXTRA_SHORT_COMBOS` combines a combo's internal state into just one byte. This can, in some cases, save some memory. If it doesn't, no point using it. If you do, you also have to make sure you don't define combos with more than 6 keys. + +Processing combos has two buffers, one for the key presses, another for the combos being activated. Use the following options to configure the sizes of these buffers: + +| Define | Default | +|-------------------------------------|------------------------------------------------------| +| `#define COMBO_KEY_BUFFER_LENGTH 8` | 8 (the key amount `(EXTRA_)EXTRA_LONG_COMBOS` gives) | +| `#define COMBO_BUFFER_LENGTH 4` | 4 | + +## Modifier Combos +If a combo resolves to a Modifier, the window for processing the combo can be extended independently from normal combos. By default, this is disabled but can be enabled with `#define COMBO_MUST_HOLD_MODS`, and the time window can be configured with `#define COMBO_HOLD_TERM 150` (default: `TAPPING_TERM`). With `COMBO_MUST_HOLD_MODS`, you cannot tap the combo any more which makes the combo less prone to misfires. + +## Per Combo Timing, Holding and Tapping +For each combo, it is possible to configure the time window it has to pressed in, if it needs to be held down, or if it needs to be tapped. + +For example, tap-only combos are useful if any (or all) of the underlying keys is a Mod-Tap or a Layer-Tap key. When you tap the combo, you get the combo result. When you press the combo and hold it down, the combo doesn't actually activate. Instead the keys are processed separately as if the combo wasn't even there. + +In order to use these features, the following configuration options and functions need to be defined. Coming up with useful timings and configuration is left as an exercise for the reader. + +| Config Flag | Function | Description | +|-----------------------------|-----------------------------------------------------------|--------------------------------------------------------------------------------------------------------| +| `COMBO_TERM_PER_COMBO` | uint16_t get_combo_term(uint16_t index, combo_t \*combo) | Optional per-combo timeout window. (default: `COMBO_TERM`) | +| `COMBO_MUST_HOLD_PER_COMBO` | bool get_combo_must_hold(uint16_t index, combo_t \*combo) | Controls if a given combo should fire immediately on tap or if it needs to be held. (default: `false`) | +| `COMBO_MUST_TAP_PER_COMBO` | bool get_combo_must_tap(uint16_t index, combo_t \*combo) | Controls if a given combo should fire only if tapped within `COMBO_HOLD_TERM`. (default: `false`) | + +Examples: +```c +uint16_t get_combo_term(uint16_t index, combo_t *combo) { + // decide by combo->keycode + switch (combo->keycode) { + case KC_X: + return 50; + } + + // or with combo index, i.e. its name from enum. + switch (index) { + case COMBO_NAME_HERE: + return 9001; + } + + // And if you're feeling adventurous, you can even decide by the keys in the chord, + // i.e. the exact array of keys you defined for the combo. + // This can be useful if your combos have a common key and you want to apply the + // same combo term for all of them. + if (combo->keys[0] == KC_ENTER) { // if first key in the array is KC_ENTER + return 150; + } + + return COMBO_TERM; +} + +bool get_combo_must_hold(uint16_t index, combo_t *combo) { + // Same as above, decide by keycode, the combo index, or by the keys in the chord. + + if (KEYCODE_IS_MOD(combo->keycode) || + (combo->keycode >= QK_MOMENTARY && combo->keycode <= QK_MOMENTARY_MAX) // MO(kc) keycodes + ) { + return true; + } + + switch (index) { + case COMBO_NAME_HERE: + return true; + } + + return false; +} + +bool get_combo_must_tap(uint16_t index, combo_t *combo) { + // If you want all combos to be tap-only, just uncomment the next line + // return true + + // If you want *all* combos, that have Mod-Tap/Layer-Tap/Momentary keys in its chord, to be tap-only, this is for you: + uint16_t key; + uint8_t idx = 0; + while ((key = pgm_read_word(&combo->keys[idx])) != COMBO_END) { + switch (key) { + case QK_MOD_TAP...QK_MOD_TAP_MAX: + case QK_LAYER_TAP...QK_LAYER_TAP_MAX: + case QK_MOMENTARY...QK_MOMENTARY_MAX: + return true; + } + idx += 1; + } + return false; + +} +``` + +## 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: +```c +enum myCombos { + ..., + COMBO_LENGTH +}; +uint16_t COMBO_LEN = COMBO_LENGTH; +``` +Regardless of the method used to declare `COMBO_LEN`, this also requires to convert the `combo_t key_combos[COMBO_COUNT] = {...};` line to `combo_t key_combos[] = {...};`. + + +## Combo timer + +Normally, the timer is started on the first key press and then reset on every subsequent key press within the `COMBO_TERM`. +Inputting combos is relaxed like this, but also slightly more prone to accidental misfires. + +The next two options alter the behaviour of the timer. + +### `#define COMBO_STRICT_TIMER` + +With `COMBO_STRICT_TIMER`, the timer is started only on the first key press. +Inputting combos is now less relaxed; you need to make sure the full chord is pressed within the `COMBO_TERM`. +Misfires are less common but if you type multiple combos fast, there is a +chance that the latter ones might not activate properly. + +### `#define COMBO_NO_TIMER` + +By defining `COMBO_NO_TIMER`, the timer is disabled completely and combos are activated on the first key release. +This also disables the "must hold" functionalities as they just wouldn't work at all. + +## Customizable key releases + +By defining `COMBO_PROCESS_KEY_RELEASE` and implementing the function `bool process_combo_key_release(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode)`, you can run your custom code on each key release after a combo was activated. For example you could change the RGB colors, activate haptics, or alter the modifiers. + +You can also release a combo early by returning `true` from the function. + +Here's an example where a combo resolves to two modifiers, and on key releases the modifiers are unregistered one by one, depending on which key was released. + +```c +enum combos { + AB_MODS, + COMBO_LENGTH +}; +uint16_t COMBO_LEN = COMBO_LENGTH; + +const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END}; + +combo_t key_combos[] = { + [AB_MODS] = COMBO(ab_combo, LCTL(KC_LSFT)), +}; + +bool process_combo_key_release(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) { + switch (combo_index) { + case AB_MODS: + switch(keycode) { + case KC_A: + unregister_mods(MOD_MASK_CTRL); + break; + case KC_B: + unregister_mods(MOD_MASK_SHIFT); + break; + } + return false; // do not release combo + } + return false; +} +``` +## Layer independent combos + +If you, for example, use multiple base layers for different key layouts, one for QWERTY, and another one for Colemak, you might want your combos to work from the same key positions on all layers. Defining the same combos again for another layout is redundant and takes more memory. The solution is to just check the keycodes from one layer. + +With `#define COMBO_ONLY_FROM_LAYER _LAYER_A` the combos' keys are always checked from layer `_LAYER_A` even though the active layer would be `_LAYER_B`. + ## User callbacks In addition to the keycodes, there are a few functions that you can use to set the status, or check it: @@ -101,3 +302,28 @@ In addition to the keycodes, there are a few functions that you can use to set t | `combo_disable()` | Disables the combo feature, and clears the combo buffer | | `combo_toggle()` | Toggles the state of the combo feature | | `is_combo_enabled()` | Returns the status of the combo feature state (true or false) | + + +# Dictionary Management + +Having 3 places to update when adding new combos or altering old ones does become cumbersome when you have a lot of combos. We can alleviate this with some magic! ... If you consider C macros magic. +First, you need to add `VPATH += keyboards/gboards` to your `rules.mk`. Next, include the file `g/keymap_combo.h` in your `keymap.c`. + +!> This functionality uses the same `process_combo_event` function as `COMBO_ACTION` macros do, so you cannot use the function yourself in your keymap. Instead, you have to define the `case`s of the `switch` statement by themselves within `inject.h`, which `g/keymap_combo.h` will then include into the function. + +Then, write your combos in `combos.def` file in the following manner: + +```c +// name result chord keys +COMB(AB_ESC, KC_ESC, KC_A, KC_B) +COMB(JK_TAB, KC_TAB, KC_J, KC_K) +COMB(JKL_SPC, KC_SPC, KC_J, KC_K, KC_L) +COMB(BSSL_CLR, KC_NO, KC_BSPC, KC_LSFT) // using KC_NO as the resulting keycode is the same as COMBO_ACTION before. +COMB(QW_UNDO, C(KC_Z), KC_Q, KC_W) +SUBS(TH_THE, "the", KC_T, KC_H) // SUBS uses SEND_STRING to output the given string. +... +``` + +Now, you can update only one place to add or alter combos. You don't even need to remember to update the `COMBO_COUNT` or the `COMBO_LEN` variables at all. Everything is taken care of. Magic! + +For small to huge ready made dictionaries of combos, you can check out http://combos.gboards.ca/. diff --git a/docs/feature_command.md b/docs/feature_command.md index a4ce3f5aea..8300066131 100644 --- a/docs/feature_command.md +++ b/docs/feature_command.md @@ -1,6 +1,6 @@ # Command -Command, formerly known as Magic, is a way to change your keyboard's behavior without having to flash or unplug it to use [Bootmagic](feature_bootmagic.md). There is a lot of overlap between this functionality and the [Bootmagic Keycodes](feature_bootmagic.md#keycodes). Wherever possible we encourage you to use that feature instead of Command. +Command, formerly known as Magic, is a way to change your keyboard's behavior without having to flash or unplug it to use [Bootmagic Lite](feature_bootmagic.md). There is a lot of overlap between this functionality and the [Magic Keycodes](keycodes_magic.md). Wherever possible we encourage you to use that feature instead of Command. On some keyboards Command is disabled by default. If this is the case, it must be explicitly enabled in your `rules.mk`: diff --git a/docs/feature_debounce_type.md b/docs/feature_debounce_type.md index 3ad74224c1..306185fe83 100644 --- a/docs/feature_debounce_type.md +++ b/docs/feature_debounce_type.md @@ -121,16 +121,16 @@ DEBOUNCE_TYPE = <name of algorithm> Where name of algorithm is one of: * ```sym_defer_g``` - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE``` milliseconds of no changes has occurred, all input changes are pushed. * This is the current default algorithm. This is the highest performance algorithm with lowest memory usage, and it's also noise-resistant. -* ```sym_eager_pr``` - debouncing per row. On any state change, response is immediate, followed by locking the row ```DEBOUNCE``` milliseconds of no further input for that row. +* ```sym_eager_pr``` - debouncing per row. On any state change, response is immediate, followed by locking the row ```DEBOUNCE``` milliseconds of no further input for that row. For use in keyboards where refreshing ```NUM_KEYS``` 8-bit counters is computationally expensive / low scan rate, and fingers usually only hit one row at a time. This could be appropriate for the ErgoDox models; the matrix is rotated 90°, and hence its "rows" are really columns, and each finger only hits a single "row" at a time in normal use. * ```sym_eager_pk``` - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE``` milliseconds of no further input for that key * ```sym_defer_pk``` - debouncing per key. On any state change, a per-key timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that key, the key status change is pushed. +* ```asym_eager_defer_pk``` - debouncing per key. On a key-down state change, response is immediate, followed by ```DEBOUNCE``` milliseconds of no further input for that key. On a key-up state change, a per-key timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that key, the key-up status change is pushed. ### A couple algorithms that could be implemented in the future: * ```sym_defer_pr``` * ```sym_eager_g``` -* ```asym_eager_defer_pk``` ### Use your own debouncing code You have the option to implement you own debouncing algorithm. To do this: diff --git a/docs/feature_dip_switch.md b/docs/feature_dip_switch.md index 15e449c4c4..43a6a3faf7 100644 --- a/docs/feature_dip_switch.md +++ b/docs/feature_dip_switch.md @@ -23,8 +23,9 @@ or The callback functions can be inserted into your `<keyboard>.c`: ```c -void dip_switch_update_kb(uint8_t index, bool active) { - dip_switch_update_user(index, active); +bool dip_switch_update_kb(uint8_t index, bool active) { + if (!dip_switch_update_user(index, active)) { return false; } + return true; } ``` @@ -32,7 +33,7 @@ void dip_switch_update_kb(uint8_t index, bool active) { or `keymap.c`: ```c -void dip_switch_update_user(uint8_t index, bool active) { +bool dip_switch_update_user(uint8_t index, bool active) { switch (index) { case 0: if(active) { audio_on(); } else { audio_off(); } @@ -57,6 +58,7 @@ void dip_switch_update_user(uint8_t index, bool active) { } break; } + return true; } ``` @@ -64,8 +66,9 @@ Additionally, we support bit mask functions which allow for more complex handlin ```c -void dip_switch_update_mask_kb(uint32_t state) { - dip_switch_update_mask_user(state); +bool dip_switch_update_mask_kb(uint32_t state) { + if (!dip_switch_update_mask_user(state)) { return false; } + return true; } ``` @@ -73,7 +76,7 @@ void dip_switch_update_mask_kb(uint32_t state) { or `keymap.c`: ```c -void dip_switch_update_mask_user(uint32_t state) { +bool dip_switch_update_mask_user(uint32_t state) { if (state & (1UL<<0) && state & (1UL<<1)) { layer_on(_ADJUST); // C on esc } else { @@ -89,6 +92,7 @@ void dip_switch_update_mask_user(uint32_t state) { } else { layer_off(_TEST_B); } + return true; } ``` diff --git a/docs/feature_haptic_feedback.md b/docs/feature_haptic_feedback.md index a092e784c7..469c9c7981 100644 --- a/docs/feature_haptic_feedback.md +++ b/docs/feature_haptic_feedback.md @@ -162,4 +162,28 @@ This will set what sequence HPT_RST will set as the active mode. If not defined, ### DRV2605L Continuous Haptic Mode -This mode sets continuous haptic feedback with the option to increase or decrease strength. +This mode sets continuous haptic feedback with the option to increase or decrease strength. + +## Haptic Key Exclusion +The Haptic Exclusion is implemented as `__attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t *record)` in haptic.c. This allows a re-definition at the required level with the specific requirement / exclusion. + +### NO_HAPTIC_MOD +With the entry of `#define NO_HAPTIC_MOD` in config.h, modifiers from Left Control to Right GUI will not trigger a feedback. This also includes modifiers in a Mod Tap configuration. + +### NO_HAPTIC_FN +With the entry of `#define NO_HAPTIC_FN` in config.h, layer keys will not rigger a feedback. + +### NO_HAPTIC_ALPHA +With the entry of `#define NO_HAPTIC_ALPHA` in config.h, none of the alpha keys (A ... Z) will trigger a feedback. + +### NO_HAPTIC_PUNCTUATION +With the entry of `#define NO_HAPTIC_PUNCTUATION` in config.h, none of the following keys will trigger a feedback: Enter, ESC, Backspace, Space, Minus, Equal, Left Bracket, Right Bracket, Backslash, Non-US Hash, Semicolon, Quote, Grave, Comma, Slash, Dot, Non-US Backslash. + +### NO_HAPTIC_LOCKKEYS +With the entry of `#define NO_HAPTIC_LOCKKEYS` in config.h, none of the following keys will trigger a feedback: Caps Lock, Scroll Lock, Num Lock. + +### NO_HAPTIC_NAV +With the entry of `#define NO_HAPTIC_NAV` in config.h, none of the following keys will trigger a feedback: Print Screen, Pause, Insert, Delete, Page Down, Page Up, Left Arrow, Up Arrow, Right Arrow, Down Arrow, End, Home. + +### NO_HAPTIC_NUMERIC +With the entry of `#define NO_HAPTIC_NUMERIC` in config.h, none of the following keys between 0 and 9 (KC_1 ... KC_0) will trigger a feedback.
\ No newline at end of file diff --git a/docs/feature_key_overrides.md b/docs/feature_key_overrides.md new file mode 100644 index 0000000000..861c4bef5d --- /dev/null +++ b/docs/feature_key_overrides.md @@ -0,0 +1,229 @@ +# Key Overrides + +Key overrides allow you to override modifier-key combinations to send a different modifier-key combination or perform completely custom actions. Don't want `shift` + `1` to type `!` on your computer? Use a key override to make your keyboard type something different when you press `shift` + `1`. The general behavior is like this: If `modifiers w` + `key x` are pressed, replace these keys with `modifiers y` + `key z` in the keyboard report. + +You can use key overrides in a similar way to momentary layer/fn keys to activate custom keycodes/shortcuts, with a number of benefits: You completely keep the original use of the modifier keys, while being able to save space by removing fn keys from your keyboard. You can also easily configure _combinations of modifiers_ to trigger different actions than individual modifiers, and much more. The possibilities are quite vast and this documentation contains a few examples for inspiration throughout. + +##### A few more examples to get started: You could use key overrides to... +- Send `brightness up/down` when pressing `ctrl` + `volume up/down`. +- Send `delete` when pressing `shift` + `backspace`. +- Create custom shortcuts or change existing ones: E.g. Send `ctrl`+`shift`+`z` when `ctrl`+`y` is pressed. +- Run custom code when `ctrl` + `alt` + `esc` is pressed. + +## Setup + +To enable this feature, you need to add `KEY_OVERRIDE_ENABLE = yes` to your `rules.mk`. + +Then, in your `keymap.c` file, you'll need to define the array `key_overrides`, which defines all key overrides to be used. Each override is a value of type `key_override_t`. The array `key_overrides` is `NULL`-terminated and contains pointers to `key_override_t` values (`const key_override_t **`). + +## Creating Key Overrides + +The `key_override_t` struct has many options that allow you to precisely tune your overrides. The full reference is shown below. Instead of manually creating a `key_override_t` value, it is recommended to use these dedicated initializers: + +#### `ko_make_basic(modifiers, key, replacement)` +Returns a `key_override_t`, which sends `replacement` (can be a key-modifer combination), when `key` and `modifiers` are all pressed down. This override still activates if any additional modifiers not specified in `modifiers` are also pressed down. See `ko_make_with_layers_and_negmods` to customize this behavior. + +#### `ko_make_with_layers(modifiers, key, replacement, layers)` +Additionally takes a bitmask `layers` that defines on which layers the override is used. + +#### `ko_make_with_layers_and_negmods(modifiers, key, replacement, layers, negative_mods)` +Additionally takes a bitmask `negative_mods` that defines which modifiers may not be pressed for this override to activate. + +#### `ko_make_with_layers_negmods_and_options(modifiers, key, replacement, layers, negative_mods, options)` +Additionally takes a bitmask `options` that specifies additional options. See `ko_option_t` for available options. + +For more customization possibilities, you may directly create a `key_override_t`, which allows you to customize even more behavior. Read further below for details and examples. + +## Simple Example + +This shows how the mentioned example of sending `delete` when `shift` + `backspace` are pressed is realized: + +```c +const key_override_t delete_key_override = ko_make_basic(MOD_MASK_SHIFT, KC_BSPACE, KC_DELETE); + +// This globally defines all key overrides to be used +const key_override_t **key_overrides = (const key_override_t *[]){ + &delete_key_override, + NULL // Null terminate the array of overrides! +}; +``` + +## Intermediate Difficulty Examples + +### Media Controls & Screen Brightness + +In this example a single key is configured to control media, volume and screen brightness by using key overrides. + +- The key is set to send `play/pause` in the keymap. + +The following key overrides will be configured: + +- `Ctrl` + `play/pause` will send `next track`. +- `Ctrl` + `Shift` + `play/pause` will send `previous track`. +- `Alt` + `play/pause` will send `volume up`. +- `Alt` + `Shift` + `play/pause` will send `volume down`. +- `Ctrl` + `Alt` + `play/pause` will send `brightness up`. +- `Ctrl` + `Alt` + `Shift` + `play/pause` will send `brightness down`. + + +```c +const key_override_t next_track_override = + ko_make_with_layers_negmods_and_options( + MOD_MASK_CTRL, // Trigger modifiers: ctrl + KC_MPLY, // Trigger key: play/pause + KC_MNXT, // Replacement key + ~0, // Activate on all layers + MOD_MASK_SA, // Do not activate when shift or alt are pressed + ko_option_no_reregister_trigger); // Specifies that the play key is not registered again after lifting ctrl + +const key_override_t prev_track_override = ko_make_with_layers_negmods_and_options(MOD_MASK_CS, KC_MPLY, + KC_MPRV, ~0, MOD_MASK_ALT, ko_option_no_reregister_trigger); + +const key_override_t vol_up_override = ko_make_with_layers_negmods_and_options(MOD_MASK_ALT, KC_MPLY, + KC_VOLU, ~0, MOD_MASK_CS, ko_option_no_reregister_trigger); + +const key_override_t vol_down_override = ko_make_with_layers_negmods_and_options(MOD_MASK_SA, KC_MPLY, + KC_VOLD, ~0, MOD_MASK_CTRL, ko_option_no_reregister_trigger); + +const key_override_t brightness_up_override = ko_make_with_layers_negmods_and_options(MOD_MASK_CA, KC_MPLY, + KC_BRIU, ~0, MOD_MASK_SHIFT, ko_option_no_reregister_trigger); + +const key_override_t brightness_down_override = ko_make_basic(MOD_MASK_CSA, KC_MPLY, KC_BRID); + +// This globally defines all key overrides to be used +const key_override_t **key_overrides = (const key_override_t *[]){ + &next_track_override, + &prev_track_override, + &vol_up_override, + &vol_down_override, + &brightness_up_override, + &brightness_down_override, + NULL +}; +``` + +### Flexible macOS-friendly Grave Escape +The [Grave Escape feature](https://docs.qmk.fm/using-qmk/advanced-keycodes/feature_grave_esc) is limited in its configurability and has [bugs when used on macOS](https://docs.qmk.fm/using-qmk/advanced-keycodes/feature_grave_esc#caveats). Key overrides can be used to achieve a similar functionality as Grave Escape, but with more customization and without bugs on macOS. + +```c +// Shift + esc = ~ +const key_override_t tilde_esc_override = ko_make_basic(MOD_MASK_SHIFT, KC_ESC, S(KC_GRAVE)); + +// GUI + esc = ` +const key_override_t grave_esc_override = ko_make_basic(MOD_MASK_GUI, KC_ESC, KC_GRAVE); + +const key_override_t **key_overrides = (const key_override_t *[]){ + &tilde_esc_override, + &grave_esc_override, + NULL +}; +``` + +In addition to not encountering unexpected bugs on macOS, you can also change the behavior as you wish. Instead setting `GUI` + `ESC` = `` ` `` you may change it to an arbitrary other modifier, for example `Ctrl` + `ESC` = `` ` ``. + +## Advanced Examples +### Modifiers as Layer Keys + +Do you really need a dedicated key to toggle your fn layer? With key overrides, perhaps not. This example shows how you can configure to use `rGUI` + `rAlt` (right GUI and right alt) to access a momentary layer like an fn layer. With this you completely eliminate the need to use a dedicated layer key. Of course the choice of modifier keys can be changed as needed, `rGUI` + `rAlt` is just an example here. + +```c +// This is called when the override activates and deactivates. Enable the fn layer on activation and disable on deactivation +bool momentary_layer(bool key_down, void *layer) { + if (key_down) { + layer_on((uint8_t)(uintptr_t)layer); + } else { + layer_off((uint8_t)(uintptr_t)layer); + } + + return false; +} + +const key_override_t fn_override = {.trigger_mods = MOD_BIT(KC_RGUI) | MOD_BIT(KC_RCTL), // + .layers = ~(1 << LAYER_FN), // + .suppressed_mods = MOD_BIT(KC_RGUI) | MOD_BIT(KC_RCTL), // + .options = ko_option_no_unregister_on_other_key_down, // + .negative_mod_mask = (uint8_t) ~(MOD_BIT(KC_RGUI) | MOD_BIT(KC_RCTL)), // + .custom_action = momentary_layer, // + .context = (void *)LAYER_FN, // + .trigger = KC_NO, // + .replacement = KC_NO, // + .enabled = NULL}; +``` + +## 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)`| + +## Reference for `key_override_t` + +Advanced users may need more customization than what is offered by the simple `ko_make` initializers. For this, directly create a `key_override_t` value and set all members. Below is a reference for all members of `key_override_t`. + +| Member | Description | +|--------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `uint16_t trigger` | The non-modifier keycode that triggers the override. This keycode, and the necessary modifiers (`trigger_mods`) must be pressed to activate this override. Set this to the keycode of the key that should activate the override. Set to `KC_NO` to require only the necessary modifiers to be pressed and no non-modifier. | +| `uint8_t trigger_mods` | Which mods need to be down for activation. If both sides of a modifier are set (e.g. left ctrl and right ctrl) then only one is required to be pressed (e.g. left ctrl suffices). Use the `MOD_MASK_XXX` and `MOD_BIT()` macros for this. | +| `layer_state_t layers` | This is a BITMASK (!), defining which layers this override applies to. To use this override on layer i set the ith bit `(1 << i)`. | +| `uint8_t negative_mod_mask` | Which modifiers cannot be down. It must hold that `(active_modifiers & negative_mod_mask) == 0`, otherwise the key override will not be activated. An active override will be deactivated once this is no longer true. | +| `uint8_t suppressed_mods` | Modifiers to 'suppress' while the override is active. To suppress a modifier means that even though the modifier key is held down, the host OS sees the modifier as not pressed. Can be used to suppress the trigger modifiers, as a trivial example. | +| `uint16_t replacement` | The complex keycode to send as replacement when this override is triggered. This can be a simple keycode, a key-modifier combination (e.g. `C(KC_A)`), or `KC_NO` (to register no replacement keycode). Use in combination with suppressed_mods to get the correct modifiers to be sent. | +| `ko_option_t options` | Options controlling the behavior of the override, such as what actions are allowed to activate the override. | +| `bool (*custom_action)(bool activated, void *context)` | If not NULL, this function will be called right before the replacement key is registered, along with the provided context and a flag indicating whether the override was activated or deactivated. This function allows you to run some custom actions for specific key overrides. If you return `false`, the replacement key is not registered/unregistered as it would normally. Return `true` to register and unregister the override normally. | +| `void *context` | A context that will be passed to the custom action function. | +| `bool *enabled` | If this points to false this override will not be used. Set to NULL to always have this override enabled. | + +### Reference for `ko_option_t` + +Bitfield with various options controlling the behavior of a key override. + +| Value | Description | +|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `ko_option_activation_trigger_down` | Allow activating when the trigger key is pressed down. | +| `ko_option_activation_required_mod_down` | Allow activating when a necessary modifier is pressed down. | +| `ko_option_activation_negative_mod_up` | Allow activating when a negative modifier is released. | +| `ko_option_one_mod` | If set, any of the modifiers in `trigger_mods` will be enough to activate the override (logical OR of modifiers). If not set, all the modifiers in `trigger_mods` have to be pressed (logical AND of modifiers). | +| `ko_option_no_unregister_on_other_key_down` | If set, the override will not deactivate when another key is pressed down. Use only if you really know you need this. | +| `ko_option_no_reregister_trigger` | If set, the trigger key will never be registered again after the override is deactivated. | +| `ko_options_default` | The default options used by the `ko_make_xxx` functions | + +## For Advanced Users: Inner Workings + +This section explains how a key override works in detail, explaining where each member of `key_override_t` comes into play. Understanding this is essential to be able to take full advantage of all the options offered by key overrides. + +#### Activation + +When the necessary keys are pressed (`trigger_mods` + `trigger`), the override is 'activated' and the replacement key is registered in the keyboard report (`replacement`), while the `trigger` key is removed from the keyboard report. The trigger modifiers may also be removed from the keyboard report upon activation of an override (`suppressed_mods`). The override will not activate if any of the `negative_modifiers` are pressed. + +Overrides can activate in three different cases: + +1. The trigger key is pressed down and necessary modifiers are already down. +2. A necessary modifier is pressed down, while the trigger key and other necessary modifiers are already down. +3. A negative modifier is released, while all necessary modifiers and the trigger key are already down. + +Use the `option` member to customize which of these events are allowed to activate your overrides (default: all three). + +In any case, a key override can only activate if the `trigger` key is the _last_ non-modifier key that was pressed down. This emulates the behavior of how standard OSes (macOS, Windows, Linux) handle normal key input (to understand: Hold down `a`, then also hold down `b`, then hold down `shift`; `B` will be typed but not `A`). + +#### Deactivation + +An override is 'deactivated' when one of the trigger keys (`trigger_mods`, `trigger`) is lifted, another non-modifier key is pressed down, or one of the `negative_modifiers` is pressed down. When an override deactivates, the `replacement` key is removed from the keyboard report, while the `suppressed_mods` that are still held down are re-added to the keyboard report. By default, the `trigger` key is re-added to the keyboard report if it is still held down and no other non-modifier key has been pressed since. This again emulates the behavior of how standard OSes handle normal key input (To understand: hold down `a`, then also hold down `b`, then also `shift`, then release `b`; `A` will not be typed even though you are holding the `a` and `shift` keys). Use the `option` field `ko_option_no_reregister_trigger` to prevent re-registering the trigger key in all cases. + +#### Key Repeat Delay + +A third way in which standard OS-handling of modifier-key input is emulated in key overrides is with a ['key repeat delay'](https://www.dummies.com/computers/pcs/set-your-keyboards-repeat-delay-and-repeat-rate/). To explain what this is, let's look at how normal keyboard input is handled by mainstream OSes again: If you hold down `a`, followed by `shift`, you will see the letter `a` is first typed, then for a short moment nothing is typed and then repeating `A`s are typed. Take note that, although shift is pressed down just after `a` is pressed, it takes a moment until `A` is typed. This is caused by the aforementioned key repeat delay, and it is a feature that prevents unwanted repeated characters from being typed. + +This applies equally to releasing a modifier: When you hold `shift`, then press `a`, the letter `A` is typed. Now if you release `shift` first, followed by `a` shortly after, you will not see the letter `a` being typed, even though for a short moment of time you were just holding down the key `a`. This is because no modified characters are typed until the key repeat delay has passed. + + This exact behavior is implemented in key overrides as well: If a key override for `shift` + `a` = `b` exists, and `a` is pressed and held, followed by `shift`, you will not immediately see the letter `b` being typed. Instead, this event is deferred for a short moment, until the key repeat delay has passed, measured from the moment when the trigger key (`a`) was pressed down. + +The duration of the key repeat delay is controlled with the `KEY_OVERRIDE_REPEAT_DELAY` macro. Define this value in your `config.h` file to change it. It is 500ms by default. + + +## Difference to Combos + +Note that key overrides are very different from [combos](https://docs.qmk.fm/#/feature_combo). Combos require that you press down several keys almost _at the same time_ and can work with any combination of non-modifier keys. Key overrides work like keyboard shortcuts (e.g. `ctrl` + `z`): They take combinations of _multiple_ modifiers and _one_ non-modifier key to then perform some custom action. Key overrides are implemented with much care to behave just like normal keyboard shortcuts would in regards to the order of pressed keys, timing, and interacton with other pressed keys. There are a number of optional settings that can be used to really fine-tune the behavior of each key override as well. Using key overrides also does not delay key input for regular key presses, which inherently happens in combos and may be undesirable. diff --git a/docs/feature_led_matrix.md b/docs/feature_led_matrix.md index 5134ab6efa..7d7971bbed 100644 --- a/docs/feature_led_matrix.md +++ b/docs/feature_led_matrix.md @@ -52,7 +52,7 @@ Here is an example using 2 drivers. Define these arrays listing all the LEDs in your `<keyboard>.c`: ```c -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | LED address @@ -63,7 +63,7 @@ const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { } ``` -Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3731.pdf) and the header file `drivers/issi/is31fl3731-simple.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` ). +Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3731.pdf) and the header file `drivers/led/issi/is31fl3731-simple.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` ). --- @@ -262,7 +262,7 @@ For inspiration and examples, check out the built-in effects under `quantum/led_ #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_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended +#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_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 @@ -350,30 +350,3 @@ void led_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) { LED_MATRIX_INDICATOR_SET_VALUE(index, value); } ``` - -## Suspended State :id=suspended-state -To use the suspend feature, make sure that `#define LED_DISABLE_WHEN_USB_SUSPENDED true` is added to the `config.h` file. - -Additionally add this to your `<keyboard>.c`: - -```c -void suspend_power_down_kb(void) { - led_matrix_set_suspend_state(true); - suspend_power_down_user(); -} - -void suspend_wakeup_init_kb(void) { - led_matrix_set_suspend_state(false); - suspend_wakeup_init_user(); -} -``` -or add this to your `keymap.c`: -```c -void suspend_power_down_user(void) { - led_matrix_set_suspend_state(true); -} - -void suspend_wakeup_init_user(void) { - led_matrix_set_suspend_state(false); -} -``` diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md index f3b659b1bc..c90aabb9c6 100644 --- a/docs/feature_oled_driver.md +++ b/docs/feature_oled_driver.md @@ -346,6 +346,10 @@ bool oled_scroll_left(void); // Returns true if the screen was not scrolling or stops scrolling bool oled_scroll_off(void); +// Inverts the display +// Returns true if the screen was or is inverted +bool oled_invert(bool invert); + // Returns the maximum number of characters that will fit on a line uint8_t oled_max_chars(void); diff --git a/docs/feature_ps2_mouse.md b/docs/feature_ps2_mouse.md index 8e84e22d8a..776a33150e 100644 --- a/docs/feature_ps2_mouse.md +++ b/docs/feature_ps2_mouse.md @@ -50,7 +50,7 @@ In your keyboard config.h: #endif ``` -## Interrupt Version :id=interrupt-version +### Interrupt Version (AVR/ATMega32u4) :id=interrupt-version-avr The following example uses D2 for clock and D5 for data. You can use any INT or PCINT pin for clock, and any pin for data. @@ -88,7 +88,31 @@ In your keyboard config.h: #endif ``` -## USART Version :id=usart-version +### Interrupt Version (ARM chibios) :id=interrupt-version-chibios + +Pretty much any two pins can be used for the (software) interrupt variant on ARM cores. The example below uses A8 for clock, and A9 for data. + +In rules.mk: + +``` +PS2_MOUSE_ENABLE = yes +PS2_USE_INT = yes +``` + +In your keyboard config.h: + +```c +#define PS2_CLOCK A8 +#define PS2_DATA A9 +``` + +And in the chibios specifig halconf.h: +```c +#define PAL_USE_CALLBACKS TRUE +``` + + +### USART Version :id=usart-version To use USART on the ATMega32u4, you have to use PD5 for clock and PD2 for data. If one of those are unavailable, you need to use interrupt version. @@ -246,6 +270,16 @@ Fine control over the scrolling is supported with the following defines: #define PS2_MOUSE_SCROLL_DIVISOR_V 2 ``` +### Invert Mouse buttons :id=invert-buttons + +To invert the left & right buttons you can put: + +```c +#define PS2_MOUSE_INVERT_BUTTONS +``` + +into config.h. + ### Invert Mouse and Scroll Axes :id=invert-mouse-and-scroll-axes To invert the X and Y axes you can put: diff --git a/docs/feature_rgb_matrix.md b/docs/feature_rgb_matrix.md index 08d5c9c4c6..670d7e09bf 100644 --- a/docs/feature_rgb_matrix.md +++ b/docs/feature_rgb_matrix.md @@ -52,7 +52,7 @@ Here is an example using 2 drivers. Define these arrays listing all the LEDs in your `<keyboard>.c`: ```c -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -64,7 +64,7 @@ const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { } ``` -Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3731.pdf) and the header file `drivers/issi/is31fl3731.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3`). +Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3731.pdf) and the header file `drivers/led/issi/is31fl3731.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3`). --- ### IS31FL3733 :id=is31fl3733 @@ -122,7 +122,7 @@ Currently only 4 drivers are supported, but it would be trivial to support all 8 Define these arrays listing all the LEDs in your `<keyboard>.c`: ```c -const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -134,7 +134,7 @@ const is31_led 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/31FL3733.pdf) and the header file `drivers/issi/is31fl3733.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` for now). +Where `X_Y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3733.pdf) and the header file `drivers/led/issi/is31fl3733.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` for now). --- ### IS31FL3737 :id=is31fl3737 @@ -145,9 +145,22 @@ 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. Configure the hardware via your `config.h`: +| Variable | Description | Default | +|----------|-------------|---------| +| `ISSI_TIMEOUT` | (Optional) How long to wait for i2c messages, in milliseconds | 100 | +| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 | +| `DRIVER_COUNT` | (Required) How many RGB driver IC's are present | | +| `DRIVER_LED_TOTAL` | (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 | | + + +Here is an example using 2 drivers. + ```c // This is a 7-bit address, that gets left-shifted and bit 0 // set to 0 for write, 1 for read (as per I2C protocol) @@ -159,19 +172,21 @@ Configure the hardware via your `config.h`: // ADDR represents A3:A0 of the 7-bit address. // The result is: 0b101(ADDR) #define DRIVER_ADDR_1 0b1010000 -#define DRIVER_ADDR_2 0b1010000 // this is here for compliancy reasons. +#define DRIVER_ADDR_2 0b1010001 #define DRIVER_COUNT 2 -#define DRIVER_1_LED_TOTAL 64 -#define DRIVER_LED_TOTAL DRIVER_1_LED_TOTAL +#define DRIVER_1_LED_TOTAL 30 +#define DRIVER_2_LED_TOTAL 36 +#define DRIVER_LED_TOTAL (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`. -Currently only a single drivers is supported, but it would be trivial to support all 4 combinations. For now define `DRIVER_ADDR_2` as `DRIVER_ADDR_1` +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 g_is31_leds[DRIVER_LED_TOTAL] = { +const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations * driver * | R location @@ -183,7 +198,7 @@ const is31_led 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/issi/is31fl3737.h`. The `driver` is the index of the driver you defined in your `config.h` (Only `0` right 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` for now). --- @@ -228,6 +243,75 @@ Configure the hardware via your `config.h`: ``` --- +### AW20216 :id=aw20216 +There is basic support for addressable RGB matrix lighting with the SPI AW20216 RGB controller. To enable it, add this to your `rules.mk`: + +```makefile +RGB_MATRIX_ENABLE = yes +RGB_MATRIX_DRIVER = AW20216 +``` + +You can use up to 2 AW20216 IC's. Do not specify `DRIVER_<N>_xxx` defines for IC's that are not present on your keyboard. You can define the following items in `config.h`: + +| Variable | Description | Default | +|----------|-------------|---------| +| `DRIVER_1_CS` | (Required) MCU pin connected to first RGB driver chip select line | B13 | +| `DRIVER_2_CS` | (Optional) MCU pin connected to second RGB driver chip select line | | +| `DRIVER_1_EN` | (Required) MCU pin connected to first RGB driver hardware enable line | C13 | +| `DRIVER_2_EN` | (Optional) MCU pin connected to second RGB driver hardware enable line | | +| `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 | | +| `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_DIVISOR` | (Optional) Clock divisor for SPI communication (powers of 2, smaller numbers means faster communication, should not be less than 4) | 4 | + +Here is an example using 2 drivers. + +```c +#define DRIVER_1_CS B13 +#define DRIVER_2_CS B14 +// Hardware enable lines may be connected to the same pin +#define DRIVER_1_EN C13 +#define DRIVER_2_EN C13 + +#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) +``` + +!> 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`. + +Define these arrays listing all the LEDs in your `<keyboard>.c`: + +```c +const aw_led __flash g_aw_leds[DRIVER_LED_TOTAL] = { +/* 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 + * driver pin locations. + * driver + * | R location + * | | G location + * | | | B location + * | | | | */ + { 0, CS1_SW1, CS2_SW1, CS3_SW1 }, + { 0, CS4_SW1, CS5_SW1, CS6_SW1 }, + { 0, CS7_SW1, CS8_SW1, CS9_SW1 }, + { 0, CS10_SW1, CS11_SW1, CS12_SW1 }, + { 0, CS13_SW1, CS14_SW1, CS15_SW1 }, + ... + { 1, CS1_SW1, CS2_SW1, CS3_SW1 }, + { 1, CS13_SW1, CS14_SW1, CS15_SW1 }, + { 1, CS16_SW1, CS17_SW1, CS18_SW1 }, + { 1, CS4_SW2, CS5_SW2, CS6_SW2 }, + ... +}; +``` + +--- ## Common Configuration :id=common-configuration @@ -485,28 +569,29 @@ For inspiration and examples, check out the built-in effects under `quantum/rgb_ These are shorthands to popular colors. The `RGB` ones can be passed to the `setrgb` functions, while the `HSV` ones to the `sethsv` functions. -|RGB |HSV | -|-------------------|-------------------| -|`RGB_WHITE` |`HSV_WHITE` | -|`RGB_RED` |`HSV_RED` | -|`RGB_CORAL` |`HSV_CORAL` | -|`RGB_ORANGE` |`HSV_ORANGE` | -|`RGB_GOLDENROD` |`HSV_GOLDENROD` | -|`RGB_GOLD` |`HSV_GOLD` | -|`RGB_YELLOW` |`HSV_YELLOW` | -|`RGB_CHARTREUSE` |`HSV_CHARTREUSE` | -|`RGB_GREEN` |`HSV_GREEN` | -|`RGB_SPRINGGREEN` |`HSV_SPRINGGREEN` | -|`RGB_TURQUOISE` |`HSV_TURQUOISE` | -|`RGB_TEAL` |`HSV_TEAL` | -|`RGB_CYAN` |`HSV_CYAN` | -|`RGB_AZURE` |`HSV_AZURE` | -|`RGB_BLUE` |`HSV_BLUE` | -|`RGB_PURPLE` |`HSV_PURPLE` | -|`RGB_MAGENTA` |`HSV_MAGENTA` | -|`RGB_PINK` |`HSV_PINK` | - -These are defined in [`rgblight_list.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/rgblight_list.h). Feel free to add to this list! +|RGB |HSV | +|---------------------|---------------------| +|`RGB_AZURE` |`HSV_AZURE` | +|`RGB_BLACK`/`RGB_OFF`|`HSV_BLACK`/`HSV_OFF`| +|`RGB_BLUE` |`HSV_BLUE` | +|`RGB_CHARTREUSE` |`HSV_CHARTREUSE` | +|`RGB_CORAL` |`HSV_CORAL` | +|`RGB_CYAN` |`HSV_CYAN` | +|`RGB_GOLD` |`HSV_GOLD` | +|`RGB_GOLDENROD` |`HSV_GOLDENROD` | +|`RGB_GREEN` |`HSV_GREEN` | +|`RGB_MAGENTA` |`HSV_MAGENTA` | +|`RGB_ORANGE` |`HSV_ORANGE` | +|`RGB_PINK` |`HSV_PINK` | +|`RGB_PURPLE` |`HSV_PURPLE` | +|`RGB_RED` |`HSV_RED` | +|`RGB_SPRINGGREEN` |`HSV_SPRINGGREEN` | +|`RGB_TEAL` |`HSV_TEAL` | +|`RGB_TURQUOISE` |`HSV_TURQUOISE` | +|`RGB_WHITE` |`HSV_WHITE` | +|`RGB_YELLOW` |`HSV_YELLOW` | + +These are defined in [`color.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/color.h). Feel free to add to this list! ## Additional `config.h` Options :id=additional-configh-options @@ -656,30 +741,3 @@ void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) { } } ``` - -### Suspended state :id=suspended-state -To use the suspend feature, make sure that `#define RGB_DISABLE_WHEN_USB_SUSPENDED true` is added to the `config.h` file. - -Additionally add this to your `<keyboard>.c`: - -```c -void suspend_power_down_kb(void) { - rgb_matrix_set_suspend_state(true); - suspend_power_down_user(); -} - -void suspend_wakeup_init_kb(void) { - rgb_matrix_set_suspend_state(false); - suspend_wakeup_init_user(); -} -``` -or add this to your `keymap.c`: -```c -void suspend_power_down_user(void) { - rgb_matrix_set_suspend_state(true); -} - -void suspend_wakeup_init_user(void) { - rgb_matrix_set_suspend_state(false); -} -``` diff --git a/docs/feature_rgblight.md b/docs/feature_rgblight.md index 994a014a28..8484586c05 100644 --- a/docs/feature_rgblight.md +++ b/docs/feature_rgblight.md @@ -119,7 +119,7 @@ if `RGBLIGHT_EFFECT_xxxx` or `RGBLIGHT_ANIMATIONS` is defined, you also have a n Check out [this video](https://youtube.com/watch?v=VKrpPAHlisY) for a demonstration. -Note: For versions older than 0.6.117, The mode numbers were written directly. In `quantum/rgblight.h` there is a contrast table between the old mode number and the current symbol. +Note: For versions older than 0.6.117, The mode numbers were written directly. In `quantum/rgblight/rgblight.h` there is a contrast table between the old mode number and the current symbol. ### Effect and Animation Toggles @@ -326,9 +326,13 @@ would turn the layer 0 (or 1) on and off again three times when `DEBUG` is press Normally lighting layers are not shown when RGB Lighting is disabled (e.g. with `RGB_TOG` keycode). If you would like lighting layers to work even when the RGB Lighting is otherwise off, add `#define RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF` to your `config.h`. +### Retain brightness + +Usually lighting layers apply their configured brightness once activated. If you would like lighting layers to retain the currently used brightness (as returned by `rgblight_get_val()`), add `#define RGBLIGHT_LAYERS_RETAIN_VAL` to your `config.h`. + ## Functions -If you need to change your RGB lighting in code, for example in a macro to change the color whenever you switch layers, QMK provides a set of functions to assist you. See [`rgblight.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/rgblight.h) for the full list, but the most commonly used functions include: +If you need to change your RGB lighting in code, for example in a macro to change the color whenever you switch layers, QMK provides a set of functions to assist you. See [`rgblight.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/rgblight/rgblight.h) for the full list, but the most commonly used functions include: ### Utility Functions |Function |Description | @@ -449,26 +453,27 @@ rgblight_sethsv_at(HSV_GREEN, 2); // led 2 These are shorthands to popular colors. The `RGB` ones can be passed to the `setrgb` functions, while the `HSV` ones to the `sethsv` functions. -|RGB |HSV | -|-------------------|-------------------| -|`RGB_WHITE` |`HSV_WHITE` | -|`RGB_RED` |`HSV_RED` | -|`RGB_CORAL` |`HSV_CORAL` | -|`RGB_ORANGE` |`HSV_ORANGE` | -|`RGB_GOLDENROD` |`HSV_GOLDENROD` | -|`RGB_GOLD` |`HSV_GOLD` | -|`RGB_YELLOW` |`HSV_YELLOW` | -|`RGB_CHARTREUSE` |`HSV_CHARTREUSE` | -|`RGB_GREEN` |`HSV_GREEN` | -|`RGB_SPRINGGREEN` |`HSV_SPRINGGREEN` | -|`RGB_TURQUOISE` |`HSV_TURQUOISE` | -|`RGB_TEAL` |`HSV_TEAL` | -|`RGB_CYAN` |`HSV_CYAN` | -|`RGB_AZURE` |`HSV_AZURE` | -|`RGB_BLUE` |`HSV_BLUE` | -|`RGB_PURPLE` |`HSV_PURPLE` | -|`RGB_MAGENTA` |`HSV_MAGENTA` | -|`RGB_PINK` |`HSV_PINK` | +|RGB |HSV | +|---------------------|---------------------| +|`RGB_AZURE` |`HSV_AZURE` | +|`RGB_BLACK`/`RGB_OFF`|`HSV_BLACK`/`HSV_OFF`| +|`RGB_BLUE` |`HSV_BLUE` | +|`RGB_CHARTREUSE` |`HSV_CHARTREUSE` | +|`RGB_CORAL` |`HSV_CORAL` | +|`RGB_CYAN` |`HSV_CYAN` | +|`RGB_GOLD` |`HSV_GOLD` | +|`RGB_GOLDENROD` |`HSV_GOLDENROD` | +|`RGB_GREEN` |`HSV_GREEN` | +|`RGB_MAGENTA` |`HSV_MAGENTA` | +|`RGB_ORANGE` |`HSV_ORANGE` | +|`RGB_PINK` |`HSV_PINK` | +|`RGB_PURPLE` |`HSV_PURPLE` | +|`RGB_RED` |`HSV_RED` | +|`RGB_SPRINGGREEN` |`HSV_SPRINGGREEN` | +|`RGB_TEAL` |`HSV_TEAL` | +|`RGB_TURQUOISE` |`HSV_TURQUOISE` | +|`RGB_WHITE` |`HSV_WHITE` | +|`RGB_YELLOW` |`HSV_YELLOW` | ```c rgblight_setrgb(RGB_ORANGE); @@ -477,7 +482,7 @@ rgblight_setrgb_at(RGB_GOLD, 3); rgblight_sethsv_range(HSV_WHITE, 0, 6); ``` -These are defined in [`rgblight_list.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/rgblight_list.h). Feel free to add to this list! +These are defined in [`color.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/color.h). Feel free to add to this list! ## Changing the order of the LEDs diff --git a/docs/feature_split_keyboard.md b/docs/feature_split_keyboard.md index 4ebf585f5c..428d581cab 100644 --- a/docs/feature_split_keyboard.md +++ b/docs/feature_split_keyboard.md @@ -8,8 +8,7 @@ QMK Firmware has a generic implementation that is usable by any board, as well a For this, we will mostly be talking about the generic implementation used by the Let's Split and other keyboards. -!> ARM is not yet fully supported for Split Keyboards and has many limitations. Progress is being made, but we have not yet reached 100% feature parity. - +!> ARM split supports most QMK subsystems when using the 'serial' and 'serial_usart' drivers. I2C slave is currently unsupported. ## Compatibility Overview @@ -90,7 +89,13 @@ You can configure the firmware to read a pin on the controller to determine hand #define SPLIT_HAND_PIN B7 ``` -This will read the specified pin. If it's high, then the controller assumes it is the left hand, and if it's low, it's assumed to be the right side. +This will read the specified pin. By default, if it's high, then the controller assumes it is the left hand, and if it's low, it's assumed to be the right side. + +This behaviour can be flipped by adding this to you `config.h` file: + +```c +#define SPLIT_HAND_PIN_LOW_IS_LEFT +``` #### Handedness by Matrix Pin @@ -169,7 +174,7 @@ Because not every split keyboard is identical, there are a number of additional #define USE_I2C ``` -This enables I<sup>2</sup>C support for split keyboards. This isn't strictly for communication, but can be used for OLED or other I<sup>2</sup>C-based devices. +This configures the use of I<sup>2</sup>C support for split keyboard transport (AVR only). ```c #define SOFT_SERIAL_PIN D0 @@ -193,20 +198,115 @@ If you're having issues with serial communication, you can change this value, as * **`5`**: about 20kbps ```c -#define SPLIT_MODS_ENABLE +#define FORCED_SYNC_THROTTLE_MS 100 ``` -This enables transmitting modifier state (normal, weak and oneshot) to the non -primary side of the split keyboard. This adds a few bytes of data to the split -communication protocol and may impact the matrix scan speed when enabled. -The purpose of this feature is to support cosmetic use of modifer state (e.g. -displaying status on an OLED screen). +This sets the maximum number of milliseconds before forcing a synchronization of data from master to slave. Under normal circumstances this sync occurs whenever the data _changes_, for safety a data transfer occurs after this number of milliseconds if no change has been detected since the last sync. ```c #define SPLIT_TRANSPORT_MIRROR ``` -This mirrors the master side matrix to the slave side for features that react or require knowledge of master side key presses on the slave side. This adds a few bytes of data to the split communication protocol and may impact the matrix scan speed when enabled. The purpose of this feature is to support cosmetic use of key events (e.g. RGB reacting to Keypresses). +This mirrors the master side matrix to the slave side for features that react or require knowledge of master side key presses on the slave side. The purpose of this feature is to support cosmetic use of key events (e.g. RGB reacting to keypresses). This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled. + +```c +#define SPLIT_LAYER_STATE_ENABLE +``` + +This enables syncing of the layer state between both halves of the split keyboard. The main purpose of this feature is to enable support for use of things like OLED display of the currently active layer. This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled. + +```c +#define SPLIT_LED_STATE_ENABLE +``` + +This enables syncing of the Host LED status (caps lock, num lock, etc) between both halves of the split keyboard. The main purpose of this feature is to enable support for use of things like OLED display of the Host LED status. This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled. + +```c +#define SPLIT_MODS_ENABLE +``` + +This enables transmitting modifier state (normal, weak and oneshot) to the non primary side of the split keyboard. The purpose of this feature is to support cosmetic use of modifer state (e.g. displaying status on an OLED screen). This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled. + +```c +#define SPLIT_WPM_ENABLE +``` + +This enables transmitting the current WPM to the slave side of the split keyboard. The purpose of this feature is to support cosmetic use of WPM (e.g. displaying the current value on an OLED screen). This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled. + +### Custom data sync between sides :id=custom-data-sync + +QMK's split transport allows for arbitrary data transactions at both the keyboard and user levels. This is modelled on a remote procedure call, with the master invoking a function on the slave side, with the ability to send data from master to slave, process it slave side, and send data back from slave to master. + +To leverage this, a keyboard or user/keymap can define a comma-separated list of _transaction IDs_: + +```c +// for keyboard-level data sync: +#define SPLIT_TRANSACTION_IDS_KB KEYBOARD_SYNC_A, KEYBOARD_SYNC_B +// or, for user: +#define SPLIT_TRANSACTION_IDS_USER USER_SYNC_A, USER_SYNC_B, USER_SYNC_C +``` + +These _transaction IDs_ then need a slave-side handler function to be registered with the split transport, for example: + +```c +typedef struct _master_to_slave_t { + int m2s_data; +} master_to_slave_t; + +typedef struct _slave_to_master_t { + int s2m_data; +} slave_to_master_t; + +void user_sync_a_slave_handler(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) { + const master_to_slave_t *m2s = (const master_to_slave_t*)in_data; + slave_to_master_t *s2m = (slave_to_master_t*)out_data; + s2m->s2m_data = m2s->m2s_data + 5; // whatever comes in, add 5 so it can be sent back +} + +void keyboard_post_init_user(void) { + transaction_register_rpc(USER_SYNC_A, user_sync_a_slave_handler); +} +``` + +The master side can then invoke the slave-side handler - for normal keyboard functionality to be minimally affected, any keyboard- or user-level code attempting to sync data should be throttled: + +```c +void housekeeping_task_user(void) { + if (is_keyboard_master()) { + // Interact with slave every 500ms + static uint32_t last_sync = 0; + if (timer_elapsed32(last_sync) > 500) { + master_to_slave_t m2s = {6}; + slave_to_master_t s2m = {0}; + if(transaction_rpc_exec(USER_SYNC_A, sizeof(m2s), &m2s, sizeof(s2m), &s2m)) { + last_sync = timer_read32(); + dprintf("Slave value: %d\n", s2m.s2m_data); // this will now be 11, as the slave adds 5 + } else { + dprint("Slave sync failed!\n"); + } + } + } +} +``` + +!> It is recommended that any data sync between halves happens during the master side's _housekeeping task_. This ensures timely retries should failures occur. + +If only one-way data transfer is needed, helper methods are provided: + +```c +bool transaction_rpc_exec(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer); +bool transaction_rpc_send(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer); +bool transaction_rpc_recv(int8_t transaction_id, uint8_t target2initiator_buffer_size, void *target2initiator_buffer); +``` + +By default, the inbound and outbound data is limited to a maximum of 32 bytes each. The sizes can be altered if required: + +```c +// Master to slave: +#define RPC_M2S_BUFFER_SIZE 48 +// Slave to master: +#define RPC_S2M_BUFFER_SIZE 48 +``` ### Hardware Configuration Options diff --git a/docs/feature_st7565.md b/docs/feature_st7565.md new file mode 100644 index 0000000000..de3e44d8e9 --- /dev/null +++ b/docs/feature_st7565.md @@ -0,0 +1,274 @@ +# ST7565 LCD Driver + +## Supported Hardware + +LCD modules using ST7565 driver IC, communicating over SPI. + +|Module |IC |Size |Notes | +|------------------------------|-------|------|----------------------------------------------------------| +|Newhaven Display NHD-C12832A1Z|ST7565R|128x32|Used by Ergodox Infinity; primary consumer of this feature| +|Zolentech ZLE12864B |ST7565P|128x64|Requires contrast adjustment | + +## Usage + +To enable the feature, there are three steps. First, when compiling your keyboard, you'll need to add the following to your `rules.mk`: + +```make +ST7565_ENABLE = yes +``` + +Then in your `keymap.c` file, implement the ST7565 task call. This example assumes your keymap has three layers named `_QWERTY`, `_FN` and `_ADJ`: + +```c +#ifdef ST7565_ENABLE +void st7565_task_user(void) { + // Host Keyboard Layer Status + st7565_write_P(PSTR("Layer: "), false); + + switch (get_highest_layer(layer_state)) { + case _QWERTY: + st7565_write_P(PSTR("Default\n"), false); + break; + case _FN: + st7565_write_P(PSTR("FN\n"), false); + break; + case _ADJ: + st7565_write_P(PSTR("ADJ\n"), false); + break; + default: + // Or use the write_ln shortcut over adding '\n' to the end of your string + st7565_write_ln_P(PSTR("Undefined"), false); + } + + // Host Keyboard LED Status + led_t led_state = host_keyboard_led_state(); + st7565_write_P(led_state.num_lock ? PSTR("NUM ") : PSTR(" "), false); + st7565_write_P(led_state.caps_lock ? PSTR("CAP ") : PSTR(" "), false); + st7565_write_P(led_state.scroll_lock ? PSTR("SCR ") : PSTR(" "), false); +} +#endif +``` + +## Logo Example + +In the default font, certain ranges of characters are reserved for a QMK logo. To render this logo to the screen, use the following code example: + +```c +static void render_logo(void) { + static const char PROGMEM qmk_logo[] = { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00 + }; + + st7565_write_P(qmk_logo, false); +} +``` + +## Buffer Read Example +For some purposes, you may need to read the current state of the display buffer. The `st7565_read_raw` function can be used to safely read bytes from the buffer. + +In this example, calling `fade_display` in the `st7565_task_user` function will slowly fade away whatever is on the screen by turning random pixels off over time. +```c +//Setup some mask which can be or'd with bytes to turn off pixels +const uint8_t single_bit_masks[8] = {127, 191, 223, 239, 247, 251, 253, 254}; + +static void fade_display(void) { + //Define the reader structure + display_buffer_reader_t reader; + uint8_t buff_char; + if (random() % 30 == 0) { + srand(timer_read()); + // Fetch a pointer for the buffer byte at index 0. The return structure + // will have the pointer and the number of bytes remaining from this + // index position if we want to perform a sequential read by + // incrementing the buffer pointer + reader = st7565_read_raw(0); + //Loop over the remaining buffer and erase pixels as we go + for (uint16_t i = 0; i < reader.remaining_element_count; i++) { + //Get the actual byte in the buffer by dereferencing the pointer + buff_char = *reader.current_element; + if (buff_char != 0) { + st7565_write_raw_byte(buff_char & single_bit_masks[rand() % 8], i); + } + //increment the pointer to fetch a new byte during the next loop + reader.current_element++; + } + } +} +``` + +## Other Examples + +In split keyboards, it is very common to have two displays that each render different content and are oriented or flipped differently. You can do this by switching which content to render by using the return value from `is_keyboard_master()` or `is_keyboard_left()` found in `split_util.h`, e.g: + +```c +#ifdef ST7565_ENABLE +display_rotation_t st7565_init_user(display_rotation_t rotation) { + if (!is_keyboard_master()) { + return DISPLAY_ROTATION_180; // flips the display 180 degrees if offhand + } + + return rotation; +} + +void st7565_task_user(void) { + if (is_keyboard_master()) { + render_status(); // Renders the current keyboard state (layer, lock, caps, scroll, etc) + } else { + render_logo(); // Renders a static logo + } +} +#endif +``` + +## Basic Configuration + +|Define |Default |Description | +|------------------------|--------------|-----------------------------------------------------------------------------------------------------| +|`ST7565_A0_PIN` |*Not defined* |(Required) The GPIO connected to the display's A0 (data/command) pin | +|`ST7565_RST_PIN` |*Not defined* |(Required) The GPIO connected to the display's reset pin | +|`ST7565_SS_PIN` |*Not defined* |(Required) The GPIO connected to the display's slave select pin | +|`ST7565_SPI_CLK_DIVISOR`|`4` |The SPI clock divisor to use | +|`ST7565_FONT_H` |`"glcdfont.c"`|The font code file to use for custom fonts | +|`ST7565_FONT_START` |`0` |The starting character index for custom fonts | +|`ST7565_FONT_END` |`223` |The ending character index for custom fonts | +|`ST7565_FONT_WIDTH` |`6` |The font width | +|`ST7565_FONT_HEIGHT` |`8` |The font height (untested) | +|`ST7565_TIMEOUT` |`60000` |Turns off the screen after 60000ms of keyboard inactivity. Helps reduce burn-in. Set to 0 to disable.| +|`ST7565_COLUMN_OFFSET` |`0` |Shift output to the right this many pixels. | +|`ST7565_CONTRAST` |`32` |The default contrast level of the display, from 0 to 255. | +|`ST7565_UPDATE_INTERVAL`|`0` |Set the time interval for updating the display in ms. This will improve the matrix scan rate. | + +## Custom sized displays + +The default display size for this feature is 128x32 and all necessary defines are precalculated with that in mind. + +|Define |Default |Description | +|-----------------------|----------|-----------------------------------------------------------------------------------------------------------| +|`ST7565_DISPLAY_WIDTH` |`128` |The width of the display. | +|`ST7565_DISPLAY_HEIGHT`|`32` |The height of the display. | +|`ST7565_MATRIX_SIZE` |`512` |The local buffer size to allocate.<br>`(ST7565_DISPLAY_HEIGHT / 8 * ST7565_DISPLAY_WIDTH)`. | +|`ST7565_BLOCK_TYPE` |`uint16_t`|The unsigned integer type to use for dirty rendering. | +|`ST7565_BLOCK_COUNT` |`16` |The number of blocks the display is divided into for dirty rendering.<br>`(sizeof(ST7565_BLOCK_TYPE) * 8)`.| +|`ST7565_BLOCK_SIZE` |`32` |The size of each block for dirty rendering<br>`(ST7565_MATRIX_SIZE / ST7565_BLOCK_COUNT)`. | + +## API + +```c +// Rotation enum values are flags +typedef enum { + DISPLAY_ROTATION_0, + DISPLAY_ROTATION_180 +} display_rotation_t; + +// Initialize the display, rotating the rendered output based on the define passed in. +// Returns true if the was initialized successfully +bool st7565_init(display_rotation_t rotation); + +// Called at the start of st7565_init, weak function overridable by the user +// rotation - the value passed into st7565_init +// Return new display_rotation_t if you want to override default rotation +display_rotation_t st7565_init_user(display_rotation_t rotation); + +// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering +void st7565_clear(void); + +// Renders the dirty chunks of the buffer to display +void st7565_render(void); + +// Moves cursor to character position indicated by column and line, wraps if out of bounds +// Max column denoted by 'st7565_max_chars()' and max lines by 'st7565_max_lines()' functions +void st7565_set_cursor(uint8_t col, uint8_t line); + +// Advances the cursor to the next page, writing ' ' if true +// Wraps to the begining when out of bounds +void st7565_advance_page(bool clearPageRemainder); + +// Moves the cursor forward 1 character length +// Advance page if there is not enough room for the next character +// Wraps to the begining when out of bounds +void st7565_advance_char(void); + +// Writes a single character to the buffer at current cursor position +// Advances the cursor while writing, inverts the pixels if true +// Main handler that writes character data to the display buffer +void st7565_write_char(const char data, bool invert); + +// Writes a string to the buffer at current cursor position +// Advances the cursor while writing, inverts the pixels if true +void st7565_write(const char *data, bool invert); + +// Writes a string to the buffer at current cursor position +// Advances the cursor while writing, inverts the pixels if true +// Advances the cursor to the next page, wiring ' ' to the remainder of the current page +void st7565_write_ln(const char *data, bool invert); + +// Pans the buffer to the right (or left by passing true) by moving contents of the buffer +// Useful for moving the screen in preparation for new drawing +void st7565_pan(bool left); + +// Returns a pointer to the requested start index in the buffer plus remaining +// buffer length as struct +display_buffer_reader_t st7565_read_raw(uint16_t start_index); + +// Writes a string to the buffer at current cursor position +void st7565_write_raw(const char *data, uint16_t size); + +// Writes a single byte into the buffer at the specified index +void st7565_write_raw_byte(const char data, uint16_t index); + +// Sets a specific pixel on or off +// Coordinates start at top-left and go right and down for positive x and y +void st7565_write_pixel(uint8_t x, uint8_t y, bool on); + +// Writes a PROGMEM string to the buffer at current cursor position +// Advances the cursor while writing, inverts the pixels if true +// Remapped to call 'void st7565_write(const char *data, bool invert);' on ARM +void st7565_write_P(const char *data, bool invert); + +// Writes a PROGMEM string to the buffer at current cursor position +// Advances the cursor while writing, inverts the pixels if true +// Advances the cursor to the next page, wiring ' ' to the remainder of the current page +// Remapped to call 'void st7565_write_ln(const char *data, bool invert);' on ARM +void st7565_write_ln_P(const char *data, bool invert); + +// Writes a PROGMEM string to the buffer at current cursor position +void st7565_write_raw_P(const char *data, uint16_t size); + +// Can be used to manually turn on the screen if it is off +// Returns true if the screen was on or turns on +bool st7565_on(void); + +// Called when st7565_on() turns on the screen, weak function overridable by the user +// Not called if the screen is already on +void st7565_on_user(void); + +// Can be used to manually turn off the screen if it is on +// Returns true if the screen was off or turns off +bool st7565_off(void); + +// Called when st7565_off() turns off the screen, weak function overridable by the user +// Not called if the screen is already off +void st7565_off_user(void); + +// Returns true if the screen is currently on, false if it is +// not +bool st7565_is_on(void); + +// Basically it's st7565_render, but with timeout management and st7565_task_user calling! +void st7565_task(void); + +// Called at the start of st7565_task, weak function overridable by the user +void st7565_task_user(void); + +// Inverts the display +// Returns true if the screen was or is inverted +bool st7565_invert(bool invert); + +// Returns the maximum number of characters that will fit on a line +uint8_t st7565_max_chars(void); + +// Returns the maximum number of lines that will fit on the display +uint8_t st7565_max_lines(void); +``` diff --git a/docs/feature_tap_dance.md b/docs/feature_tap_dance.md index 5d77f3e08d..f4e989921f 100644 --- a/docs/feature_tap_dance.md +++ b/docs/feature_tap_dance.md @@ -50,7 +50,7 @@ The main entry point is `process_tap_dance()`, called from `process_record_quant This means that you have `TAPPING_TERM` time to tap the key again; you do not have to input all the taps within a single `TAPPING_TERM` timeframe. This allows for longer tap counts, with minimal impact on responsiveness. -Our next stop is `matrix_scan_tap_dance()`. This handles the timeout of tap-dance keys. +Our next stop is `tap_dance_task()`. This handles the timeout of tap-dance keys. For the sake of flexibility, tap-dance actions can be either a pair of keycodes, or a user function. The latter allows one to handle higher tap counts, or do extra things, like blink the LEDs, fiddle with the backlighting, and so on. This is accomplished by using an union, and some clever macros. diff --git a/docs/flashing.md b/docs/flashing.md index 83c97444e1..fae9c5d1c4 100644 --- a/docs/flashing.md +++ b/docs/flashing.md @@ -48,7 +48,7 @@ QMK maintains [a fork of the LUFA DFU bootloader](https://github.com/qmk/lufa/tr //#define QMK_LED E6 //#define QMK_SPEAKER C6 ``` -Currently we do not recommend making `QMK_ESC` the same key as the one designated for [Bootmagic Lite](feature_bootmagic.md#bootmagic-lite), as holding it down will cause the MCU to loop back and forth between entering and exiting the bootloader. +Currently we do not recommend making `QMK_ESC` the same key as the one designated for [Bootmagic Lite](feature_bootmagic.md), as holding it down will cause the MCU to loop back and forth between entering and exiting the bootloader. The manufacturer and product strings are automatically pulled from `config.h`, with " Bootloader" appended to the product string. @@ -171,6 +171,52 @@ Flashing sequence: 3. Flash a .hex file 4. Reset the device into application mode (may be done automatically) +### QMK HID + +QMK maintains [a fork of the LUFA HID bootloader](https://github.com/qmk/lufa/tree/master/Bootloaders/HID), which uses a USB HID Endpoint for flashing in the way that the PJRC's Teensy Loader flasher and HalfKay bootloader work. Additionally, it performs a simple matrix scan for exiting the bootloader and returning to the application, as well as flashing an LED/making a ticking noise with a speaker when things are happening. + +To ensure compatibility with the QMK HID bootloader, make sure this block is present in your `rules.mk`: + +```make +# Bootloader selection +BOOTLOADER = qmk-hid +``` + +To enable the additional features, add the following defines to your `config.h`: + +```c +#define QMK_ESC_OUTPUT F1 // COL pin if COL2ROW +#define QMK_ESC_INPUT D5 // ROW pin if COL2ROW +// Optional: +//#define QMK_LED E6 +//#define QMK_SPEAKER C6 +``` + +Currently we do not recommend making `QMK_ESC` the same key as the one designated for [Bootmagic Lite](feature_bootmagic.md), as holding it down will cause the MCU to loop back and forth between entering and exiting the bootloader. + +The manufacturer and product strings are automatically pulled from `config.h`, with " Bootloader" appended to the product string. + +To generate this bootloader, use the `bootloader` target, eg. `make planck/rev4:default:bootloader`. To generate a production-ready .hex file (combining QMK and the bootloader), use the `production` target, eg. `make planck/rev4:default:production`. + +Compatible flashers: + +* TBD + * Currently, you need to either use the [Python script](https://github.com/qmk/lufa/tree/master/Bootloaders/HID/HostLoaderApp_python), or compile [`hid_bootloader_cli`](https://github.com/qmk/lufa/tree/master/Bootloaders/HID/HostLoaderApp), from the LUFA repo. Homebrew may (will) have support for this directly (via `brew install qmk/qmk/hid_bootloader_cli`). + +Flashing sequence: + +1. Enter the bootloader using any of the following methods: + * Press the `RESET` keycode + * Press the `RESET` button on the PCB if available + * short RST to GND quickly +2. Wait for the OS to detect the device +3. Flash a .hex file +4. Reset the device into application mode (may be done automatically) + +### `make` Targets + +* `:qmk-hid`: Checks every 5 seconds until a DFU device is available, and then flashes the firmware. + ## STM32/APM32 DFU All STM32 and APM32 MCUs, except for F103 (see the [STM32duino section](#stm32duino)) come preloaded with a factory bootloader that cannot be modified nor deleted. diff --git a/docs/fr-fr/cli.md b/docs/fr-fr/cli.md index 4281536458..bfa060f2ad 100644 --- a/docs/fr-fr/cli.md +++ b/docs/fr-fr/cli.md @@ -85,14 +85,14 @@ qmk compile <configuratorExport.json> qmk compile -kb <keyboard_name> -km <keymap_name> ``` -## `qmk cformat` +## `qmk format-c` Cette commande formatte le code C en utilisant clang-format. Lancez-la sans arguments pour formatter tout le code core, ou passez les noms de fichiers à la ligne de commande pour la lancer sur des fichiers spécifiques. **Utilisation**: ``` -qmk cformat [file1] [file2] [...] [fileN] +qmk format-c [file1] [file2] [...] [fileN] ``` ## `qmk config` @@ -125,14 +125,14 @@ Cette commande crée une nouvelle keymap basée sur une keymap par défaut d'un qmk new-keymap [-kb KEYBOARD] [-km KEYMAP] ``` -## `qmk pyformat` +## `qmk format-py` Cette commande formate le code python dans `qmk_firmware`. **Utilisation**: ``` -qmk pyformat +qmk format-py ``` ## `qmk pytest` diff --git a/docs/hardware_avr.md b/docs/hardware_avr.md index eb536ca961..3d58cdc055 100644 --- a/docs/hardware_avr.md +++ b/docs/hardware_avr.md @@ -6,26 +6,28 @@ If you have not yet you should read the [Keyboard Guidelines](hardware_keyboard_ ## Adding Your AVR Keyboard to QMK -QMK has a number of features to simplify working with AVR keyboards. For most keyboards you don't have to write a single line of code. To get started, run the `util/new_keyboard.sh` script: +QMK has a number of features to simplify working with AVR keyboards. For most keyboards you don't have to write a single line of code. To get started, run `qmk new-keyboard`: ``` -$ ./util/new_keyboard.sh -Generating a new QMK keyboard directory - -Keyboard Name: mycoolkb -Keyboard Type [avr]: -Your Name [John Smith]: - -Copying base template files... done -Copying avr template files... done -Renaming keyboard files... done -Replacing %KEYBOARD% with mycoolkb... done -Replacing %YOUR_NAME% with John Smith... done - -Created a new keyboard called mycoolkb. - -To start working on things, cd into keyboards/mycoolkb, -or open the directory in your favourite text editor. +$ qmk new-keyboard +Ψ Generating a new QMK keyboard directory + +Keyboard Name: mycoolkeeb +Keyboard Type: + 1. avr + 2. ps2avrgb +Please enter your choice: [1] +Your Name: [John Smith] +Ψ Copying base template files... +Ψ Copying avr template files... +Ψ Renaming keyboard.[ch] to mycoolkeeb.[ch]... +Ψ Replacing %YEAR% with 2021... +Ψ Replacing %KEYBOARD% with mycoolkeeb... +Ψ Replacing %YOUR_NAME% with John Smith... + +Ψ Created a new keyboard called mycoolkeeb. +Ψ To start working on things, `cd` into keyboards/mycoolkeeb, +Ψ or open the directory in your preferred text editor. ``` This will create all the files needed to support your new keyboard, and populate the settings with default values. Now you just need to customize it for your keyboard. diff --git a/docs/hardware_keyboard_guidelines.md b/docs/hardware_keyboard_guidelines.md index 4f32715046..7630b44e0c 100644 --- a/docs/hardware_keyboard_guidelines.md +++ b/docs/hardware_keyboard_guidelines.md @@ -189,9 +189,9 @@ Hardware files (such as plates, cases, pcb) can be contributed to the [qmk.fm re Given the amount of functionality that QMK exposes it's very easy to confuse new users. When putting together the default firmware for your keyboard we recommend limiting your enabled features and options to the minimal set needed to support your hardware. Recommendations for specific features follow. -### Bootmagic and Command +### Magic Keycodes and Command -[Bootmagic](feature_bootmagic.md) and [Command](feature_command.md) are two related features that allow a user to control their keyboard in non-obvious ways. We recommend you think long and hard about if you're going to enable either feature, and how you will expose this functionality. Keep in mind that users who want this functionality can enable it in their personal keymaps without affecting all the novice users who may be using your keyboard as their first programmable board. +[Magic Keycodes](keycodes_magic.md) and [Command](feature_command.md) are two related features that allow a user to control their keyboard in non-obvious ways. We recommend you think long and hard about if you're going to enable either feature, and how you will expose this functionality. Keep in mind that users who want this functionality can enable it in their personal keymaps without affecting all the novice users who may be using your keyboard as their first programmable board. By far the most common problem new users encounter is accidentally triggering Bootmagic while they're plugging in their keyboard. They're holding the keyboard by the bottom, unknowingly pressing in alt and spacebar, and then they find that these keys have been swapped on them. We recommend leaving this feature disabled by default, but if you do turn it on consider setting `BOOTMAGIC_KEY_SALT` to a key that is hard to press while plugging your keyboard in. diff --git a/docs/ja/cli_commands.md b/docs/ja/cli_commands.md index 81cb03cfe5..35937dbbcb 100644 --- a/docs/ja/cli_commands.md +++ b/docs/ja/cli_commands.md @@ -211,7 +211,7 @@ qmk new-keymap [-kb KEYBOARD] [-km KEYMAP] # 開発者用コマンド -## `qmk cformat` +## `qmk format-c` このコマンドは clang-format を使って C コードを整形します。 @@ -222,25 +222,25 @@ qmk new-keymap [-kb KEYBOARD] [-km KEYMAP] **指定したファイルに対する使い方**: ``` -qmk cformat [file1] [file2] [...] [fileN] +qmk format-c [file1] [file2] [...] [fileN] ``` **全てのコアファイルに対する使い方**: ``` -qmk cformat -a +qmk format-c -a ``` **origin/master で変更されたファイルのみに対する使い方**: ``` -qmk cformat +qmk format-c ``` **branch_name で変更されたファイルのみに対する使い方**: ``` -qmk cformat -b branch_name +qmk format-c -b branch_name ``` ## `qmk docs` @@ -275,14 +275,14 @@ $ qmk kle2json -f kle.txt -f Ψ Wrote out to info.json ``` -## `qmk pyformat` +## `qmk format-py` このコマンドは `qmk_firmware` 内の python コードを整形します。 **使用法**: ``` -qmk pyformat +qmk format-py ``` ## `qmk pytest` diff --git a/docs/ja/cli_development.md b/docs/ja/cli_development.md index 47262213ae..28cdd91c1e 100644 --- a/docs/ja/cli_development.md +++ b/docs/ja/cli_development.md @@ -192,7 +192,7 @@ cli.log.info('Reading from %s and writing to %s', cli.args.filename, cli.args.ou # テスト、リントおよびフォーマット -nose2、flake8 および yapf を使ってコードをテスト、リントおよびフォーマットします。これらのテストを実行するために `pytest` と `pyformat` サブコマンドを使うことができます。 +nose2、flake8 および yapf を使ってコードをテスト、リントおよびフォーマットします。これらのテストを実行するために `pytest` と `format-py` サブコマンドを使うことができます。 ### テストとリント @@ -200,7 +200,7 @@ nose2、flake8 および yapf を使ってコードをテスト、リントお ### フォーマット - qmk pyformat + qmk format-py ## フォーマットの詳細 diff --git a/docs/ja/compatible_microcontrollers.md b/docs/ja/compatible_microcontrollers.md index b675b038d2..761a4cda46 100644 --- a/docs/ja/compatible_microcontrollers.md +++ b/docs/ja/compatible_microcontrollers.md @@ -36,6 +36,8 @@ QMK は十分な容量のフラッシュメモリを備えた USB 対応 AVR ま * [STM32F446](https://www.st.com/en/microcontrollers-microprocessors/stm32f446.html) * [STM32G431](https://www.st.com/en/microcontrollers-microprocessors/stm32g4x1.html) * [STM32G474](https://www.st.com/en/microcontrollers-microprocessors/stm32g4x4.html) +* [STM32L412](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x2.html) +* [STM32L422](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x2.html) * [STM32L433](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x3.html) * [STM32L443](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x3.html) diff --git a/docs/ja/feature_dip_switch.md b/docs/ja/feature_dip_switch.md index a0f6aeb003..a5436779f1 100644 --- a/docs/ja/feature_dip_switch.md +++ b/docs/ja/feature_dip_switch.md @@ -28,8 +28,9 @@ DIP スイッチは、以下を `rules.mk` に追加することでサポート コールバック関数を `<keyboard>.c` に記述することができます: ```c -void dip_switch_update_kb(uint8_t index, bool active) { - dip_switch_update_user(index, active); +bool dip_switch_update_kb(uint8_t index, bool active) { + if !(dip_switch_update_user(index, active)) { return false; } + return true; } ``` @@ -37,7 +38,7 @@ void dip_switch_update_kb(uint8_t index, bool active) { あるいは `keymap.c` に記述することもできます: ```c -void dip_switch_update_user(uint8_t index, bool active) { +bool dip_switch_update_user(uint8_t index, bool active) { switch (index) { case 0: if(active) { audio_on(); } else { audio_off(); } @@ -62,6 +63,7 @@ void dip_switch_update_user(uint8_t index, bool active) { } break; } + return true; } ``` @@ -69,8 +71,9 @@ void dip_switch_update_user(uint8_t index, bool active) { ```c -void dip_switch_update_mask_kb(uint32_t state) { - dip_switch_update_mask_user(state); +bool dip_switch_update_mask_kb(uint32_t state) { + if (!dip_switch_update_mask_user(state)) { return false; } + return true; } ``` @@ -78,7 +81,7 @@ void dip_switch_update_mask_kb(uint32_t state) { あるいは `keymap.c` に記述することもできます: ```c -void dip_switch_update_mask_user(uint32_t state) { +bool dip_switch_update_mask_user(uint32_t state) { if (state & (1UL<<0) && state & (1UL<<1)) { layer_on(_ADJUST); // C on esc } else { @@ -94,6 +97,7 @@ void dip_switch_update_mask_user(uint32_t state) { } else { layer_off(_TEST_B); } + return true; } ``` diff --git a/docs/ja/feature_encoders.md b/docs/ja/feature_encoders.md index 7b7f394c83..21f42d38b7 100644 --- a/docs/ja/feature_encoders.md +++ b/docs/ja/feature_encoders.md @@ -51,15 +51,18 @@ ENCODER_ENABLE = yes コールバック関数を `<keyboard>.c` に記述することができます: ```c -void encoder_update_kb(uint8_t index, bool clockwise) { - encoder_update_user(index, clockwise); +bool encoder_update_kb(uint8_t index, bool clockwise) { + if (!encoder_update_user(index, clockwise)) { + return false; + } + } ``` あるいは `keymap.c` に記述することもできます: ```c -void encoder_update_user(uint8_t index, bool clockwise) { +bool encoder_update_user(uint8_t index, bool clockwise) { if (index == 0) { /* First encoder */ if (clockwise) { tap_code(KC_PGDN); @@ -73,6 +76,7 @@ void encoder_update_user(uint8_t index, bool clockwise) { tap_code(KC_UP); } } + return true; } ``` diff --git a/docs/ja/feature_led_matrix.md b/docs/ja/feature_led_matrix.md index 62e22859fb..6511b28249 100644 --- a/docs/ja/feature_led_matrix.md +++ b/docs/ja/feature_led_matrix.md @@ -52,7 +52,7 @@ I2C IS31FL3731 RGB コントローラを使ったアドレス指定可能な LED `<keyboard>.c` に全ての LED を列挙する配列を定義します: - const is31_led g_is31_leds[DRIVER_LED_TOTAL] = { + const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL] = { /* これらの位置については IS31 マニュアルを参照してください * driver * | LED address @@ -61,7 +61,7 @@ I2C IS31FL3731 RGB コントローラを使ったアドレス指定可能な LED .... } -ここで、`Cx_y` は[データシート](https://www.issi.com/WW/pdf/31FL3731.pdf)およびヘッダファイル `drivers/issi/is31fl3731-simple.h` で定義されるマトリックス内の LED の位置です。`driver` は `config.h` で定義したドライバのインデックス(`0`、`1`、`2`、`3`のいずれか)です。 +ここで、`Cx_y` は[データシート](https://www.issi.com/WW/pdf/31FL3731.pdf)およびヘッダファイル `drivers/led/issi/is31fl3731-simple.h` で定義されるマトリックス内の LED の位置です。`driver` は `config.h` で定義したドライバのインデックス(`0`、`1`、`2`、`3`のいずれか)です。 ## キーコード diff --git a/docs/ja/feature_tap_dance.md b/docs/ja/feature_tap_dance.md index 3d9d30ecf0..dd2b8bdb6c 100644 --- a/docs/ja/feature_tap_dance.md +++ b/docs/ja/feature_tap_dance.md @@ -59,7 +59,7 @@ このことは、あなたは再びキーをタップするまでの時間として `TAPPING_TERM` の時間を持っていることを意味します。そのため、あなたは1つの `TAPPING_TERM` の時間内に全てのタップを行う必要はありません。これにより、キーの反応への影響を最小限に抑えながら、より長いタップ回数を可能にします。 -次は `matrix_scan_tap_dance()` です。この関数はタップダンスキーのタイムアウトを制御します。 +次は `tap_dance_task()` です。この関数はタップダンスキーのタイムアウトを制御します。 柔軟性のために、タップダンスは、キーコードの組み合わせにも、ユーザー関数にもなることができます。後者は、より高度なタップ回数の制御や、LED を点滅させたり、バックライトをいじったり、等々の制御を可能にします。これは、1つの共用体と、いくつかの賢いマクロによって成し遂げられています。 diff --git a/docs/ja/hardware_avr.md b/docs/ja/hardware_avr.md index 66be2f71c9..cdc5f8cb86 100644 --- a/docs/ja/hardware_avr.md +++ b/docs/ja/hardware_avr.md @@ -12,26 +12,28 @@ ## AVR を使用したキーボードを QMK に追加する -QMK には AVR を使ったキーボードでの作業を簡略化するための機能が多数あります。大体のキーボードでは1行もコードを書く必要がありません。まずはじめに、`util/new_keyboard.sh` スクリプトを実行します。 +QMK には AVR を使ったキーボードでの作業を簡略化するための機能が多数あります。大体のキーボードでは1行もコードを書く必要がありません。まずはじめに、`qmk new-keyboard` を実行します。 ``` -$ ./util/new_keyboard.sh -Generating a new QMK keyboard directory - -Keyboard Name: mycoolkb -Keyboard Type [avr]: -Your Name [John Smith]: - -Copying base template files... done -Copying avr template files... done -Renaming keyboard files... done -Replacing %KEYBOARD% with mycoolkb... done -Replacing %YOUR_NAME% with John Smith... done - -Created a new keyboard called mycoolkb. - -To start working on things, cd into keyboards/mycoolkb, -or open the directory in your favourite text editor. +$ qmk new-keyboard +Ψ Generating a new QMK keyboard directory + +Keyboard Name: mycoolkeeb +Keyboard Type: + 1. avr + 2. ps2avrgb +Please enter your choice: [1] +Your Name: [John Smith] +Ψ Copying base template files... +Ψ Copying avr template files... +Ψ Renaming keyboard.[ch] to mycoolkeeb.[ch]... +Ψ Replacing %YEAR% with 2021... +Ψ Replacing %KEYBOARD% with mycoolkeeb... +Ψ Replacing %YOUR_NAME% with John Smith... + +Ψ Created a new keyboard called mycoolkeeb. +Ψ To start working on things, `cd` into keyboards/mycoolkeeb, +Ψ or open the directory in your preferred text editor. ``` これにより、新しいキーボードをサポートするために必要なすべてのファイルが作成され、デフォルト値で設定が入力されます。あとはあなたのキーボード用にカスタマイズするだけです。 diff --git a/docs/ja/reference_configurator_support.md b/docs/ja/reference_configurator_support.md index 4fb98fc0ec..83d6d648d0 100644 --- a/docs/ja/reference_configurator_support.md +++ b/docs/ja/reference_configurator_support.md @@ -104,8 +104,6 @@ JSON ファイルをビルドする最も簡単な方法は、[Keyboard Layout E "tags": { "form_factor": "numpad" }, - "width": 4, - "height": 5, "layouts": { "LAYOUT": { "layout": [ diff --git a/docs/ja/reference_info_json.md b/docs/ja/reference_info_json.md index 5b9a1b6b63..7346a63956 100644 --- a/docs/ja/reference_info_json.md +++ b/docs/ja/reference_info_json.md @@ -20,10 +20,6 @@ * キーボードの製品ページ、[QMK.fm/keyboards](https://qmk.fm/keyboards) のページ、あるいはキーボードに関する情報を説明する他のページの URL。 * `maintainer` * メンテナの GitHub のユーザ名、あるいはコミュニティが管理するキーボードの場合は `qmk` -* `width` - * キー単位でのキーボードの幅 -* `height` - * キー単位でのキーボードの高さ * `layouts` * 物理的なレイアウト表現。詳細は以下のセクションを見てください。 diff --git a/docs/keycodes.md b/docs/keycodes.md index 85988f1855..a134c5a1b2 100644 --- a/docs/keycodes.md +++ b/docs/keycodes.md @@ -257,42 +257,6 @@ See also: [Backlighting](feature_backlight.md) |`BL_DEC` |Decrease the backlight level | |`BL_BRTG`|Toggle backlight breathing | -## Bootmagic :id=bootmagic - -See also: [Bootmagic](feature_bootmagic.md) - -|Key |Aliases |Description | -|----------------------------------|---------|--------------------------------------------------------------------------| -|`MAGIC_SWAP_CONTROL_CAPSLOCK` |`CL_SWAP`|Swap Caps Lock and Left Control | -|`MAGIC_UNSWAP_CONTROL_CAPSLOCK` |`CL_NORM`|Unswap Caps Lock and Left Control | -|`MAGIC_CAPSLOCK_TO_CONTROL` |`CL_CTRL`|Treat Caps Lock as Control | -|`MAGIC_UNCAPSLOCK_TO_CONTROL` |`CL_CAPS`|Stop treating Caps Lock as Control | -|`MAGIC_SWAP_LCTL_LGUI` |`LCG_SWP`|Swap Left Control and GUI | -|`MAGIC_UNSWAP_LCTL_LGUI` |`LCG_NRM`|Unswap Left Control and GUI | -|`MAGIC_SWAP_RCTL_RGUI` |`RCG_SWP`|Swap Right Control and GUI | -|`MAGIC_UNSWAP_RCTL_RGUI` |`RCG_NRM`|Unswap Right Control and GUI | -|`MAGIC_SWAP_CTL_GUI` |`CG_SWAP`|Swap Control and GUI on both sides | -|`MAGIC_UNSWAP_CTL_GUI` |`CG_NORM`|Unswap Control and GUI on both sides | -|`MAGIC_TOGGLE_CTL_GUI` |`CG_TOGG`|Toggle Control and GUI swap on both sides | -|`MAGIC_SWAP_LALT_LGUI` |`LAG_SWP`|Swap Left Alt and GUI | -|`MAGIC_UNSWAP_LALT_LGUI` |`LAG_NRM`|Unswap Left Alt and GUI | -|`MAGIC_SWAP_RALT_RGUI` |`RAG_SWP`|Swap Right Alt and GUI | -|`MAGIC_UNSWAP_RALT_RGUI` |`RAG_NRM`|Unswap Right Alt and GUI | -|`MAGIC_SWAP_ALT_GUI` |`AG_SWAP`|Swap Alt and GUI on both sides | -|`MAGIC_UNSWAP_ALT_GUI` |`AG_NORM`|Unswap Alt and GUI on both sides | -|`MAGIC_TOGGLE_ALT_GUI` |`AG_TOGG`|Toggle Alt and GUI swap on both sides | -|`MAGIC_NO_GUI` |`GUI_OFF`|Disable the GUI keys | -|`MAGIC_UNNO_GUI` |`GUI_ON` |Enable the GUI keys | -|`MAGIC_SWAP_GRAVE_ESC` |`GE_SWAP`|Swap <code>`</code> and Escape | -|`MAGIC_UNSWAP_GRAVE_ESC` |`GE_NORM`|Unswap <code>`</code> and Escape | -|`MAGIC_SWAP_BACKSLASH_BACKSPACE` |`BS_SWAP`|Swap `\` and Backspace | -|`MAGIC_UNSWAP_BACKSLASH_BACKSPACE`|`BS_NORM`|Unswap `\` and Backspace | -|`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 | -|`MAGIC_EE_HANDS_LEFT` |`EH_LEFT`|Set the master half of a split keyboard as the left hand (for `EE_HANDS`) | -|`MAGIC_EE_HANDS_RIGHT` |`EH_RGHT`|Set the master half of a split keyboard as the right hand (for `EE_HANDS`)| - ## Bluetooth :id=bluetooth See also: [Bluetooth](feature_bluetooth.md) @@ -354,6 +318,42 @@ See also: [Leader Key](feature_leader_key.md) |---------|------------------------| |`KC_LEAD`|Begins a leader sequence| +## Magic Keycodes :id=magic-keycodes + +See also: [Magic Keycodes](keycodes_magic.md) + +|Key |Aliases |Description | +|----------------------------------|---------|--------------------------------------------------------------------------| +|`MAGIC_SWAP_CONTROL_CAPSLOCK` |`CL_SWAP`|Swap Caps Lock and Left Control | +|`MAGIC_UNSWAP_CONTROL_CAPSLOCK` |`CL_NORM`|Unswap Caps Lock and Left Control | +|`MAGIC_CAPSLOCK_TO_CONTROL` |`CL_CTRL`|Treat Caps Lock as Control | +|`MAGIC_UNCAPSLOCK_TO_CONTROL` |`CL_CAPS`|Stop treating Caps Lock as Control | +|`MAGIC_SWAP_LCTL_LGUI` |`LCG_SWP`|Swap Left Control and GUI | +|`MAGIC_UNSWAP_LCTL_LGUI` |`LCG_NRM`|Unswap Left Control and GUI | +|`MAGIC_SWAP_RCTL_RGUI` |`RCG_SWP`|Swap Right Control and GUI | +|`MAGIC_UNSWAP_RCTL_RGUI` |`RCG_NRM`|Unswap Right Control and GUI | +|`MAGIC_SWAP_CTL_GUI` |`CG_SWAP`|Swap Control and GUI on both sides | +|`MAGIC_UNSWAP_CTL_GUI` |`CG_NORM`|Unswap Control and GUI on both sides | +|`MAGIC_TOGGLE_CTL_GUI` |`CG_TOGG`|Toggle Control and GUI swap on both sides | +|`MAGIC_SWAP_LALT_LGUI` |`LAG_SWP`|Swap Left Alt and GUI | +|`MAGIC_UNSWAP_LALT_LGUI` |`LAG_NRM`|Unswap Left Alt and GUI | +|`MAGIC_SWAP_RALT_RGUI` |`RAG_SWP`|Swap Right Alt and GUI | +|`MAGIC_UNSWAP_RALT_RGUI` |`RAG_NRM`|Unswap Right Alt and GUI | +|`MAGIC_SWAP_ALT_GUI` |`AG_SWAP`|Swap Alt and GUI on both sides | +|`MAGIC_UNSWAP_ALT_GUI` |`AG_NORM`|Unswap Alt and GUI on both sides | +|`MAGIC_TOGGLE_ALT_GUI` |`AG_TOGG`|Toggle Alt and GUI swap on both sides | +|`MAGIC_NO_GUI` |`GUI_OFF`|Disable the GUI keys | +|`MAGIC_UNNO_GUI` |`GUI_ON` |Enable the GUI keys | +|`MAGIC_SWAP_GRAVE_ESC` |`GE_SWAP`|Swap <code>`</code> and Escape | +|`MAGIC_UNSWAP_GRAVE_ESC` |`GE_NORM`|Unswap <code>`</code> and Escape | +|`MAGIC_SWAP_BACKSLASH_BACKSPACE` |`BS_SWAP`|Swap `\` and Backspace | +|`MAGIC_UNSWAP_BACKSLASH_BACKSPACE`|`BS_NORM`|Unswap `\` and Backspace | +|`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 | +|`MAGIC_EE_HANDS_LEFT` |`EH_LEFT`|Set the master half of a split keyboard as the left hand (for `EE_HANDS`) | +|`MAGIC_EE_HANDS_RIGHT` |`EH_RGHT`|Set the master half of a split keyboard as the right hand (for `EE_HANDS`)| + ## MIDI :id=midi See also: [MIDI](feature_midi.md) diff --git a/docs/keycodes_magic.md b/docs/keycodes_magic.md new file mode 100644 index 0000000000..719d820312 --- /dev/null +++ b/docs/keycodes_magic.md @@ -0,0 +1,35 @@ +# Magic Keycodes :id=magic-keycodes + +**Magic Keycodes** are prefixed with `MAGIC_`, and allow you to access the functionality of the deprecated Bootmagic feature *after* your keyboard has initialized. To use the keycodes, assign them to your keymap as you would any other keycode. + +|Key |Aliases |Description | +|----------------------------------|---------|--------------------------------------------------------------------------| +|`MAGIC_SWAP_CONTROL_CAPSLOCK` |`CL_SWAP`|Swap Caps Lock and Left Control | +|`MAGIC_UNSWAP_CONTROL_CAPSLOCK` |`CL_NORM`|Unswap Caps Lock and Left Control | +|`MAGIC_CAPSLOCK_TO_CONTROL` |`CL_CTRL`|Treat Caps Lock as Control | +|`MAGIC_UNCAPSLOCK_TO_CONTROL` |`CL_CAPS`|Stop treating Caps Lock as Control | +|`MAGIC_SWAP_LCTL_LGUI` |`LCG_SWP`|Swap Left Control and GUI | +|`MAGIC_UNSWAP_LCTL_LGUI` |`LCG_NRM`|Unswap Left Control and GUI | +|`MAGIC_SWAP_RCTL_RGUI` |`RCG_SWP`|Swap Right Control and GUI | +|`MAGIC_UNSWAP_RCTL_RGUI` |`RCG_NRM`|Unswap Right Control and GUI | +|`MAGIC_SWAP_CTL_GUI` |`CG_SWAP`|Swap Control and GUI on both sides | +|`MAGIC_UNSWAP_CTL_GUI` |`CG_NORM`|Unswap Control and GUI on both sides | +|`MAGIC_TOGGLE_CTL_GUI` |`CG_TOGG`|Toggle Control and GUI swap on both sides | +|`MAGIC_SWAP_LALT_LGUI` |`LAG_SWP`|Swap Left Alt and GUI | +|`MAGIC_UNSWAP_LALT_LGUI` |`LAG_NRM`|Unswap Left Alt and GUI | +|`MAGIC_SWAP_RALT_RGUI` |`RAG_SWP`|Swap Right Alt and GUI | +|`MAGIC_UNSWAP_RALT_RGUI` |`RAG_NRM`|Unswap Right Alt and GUI | +|`MAGIC_SWAP_ALT_GUI` |`AG_SWAP`|Swap Alt and GUI on both sides | +|`MAGIC_UNSWAP_ALT_GUI` |`AG_NORM`|Unswap Alt and GUI on both sides | +|`MAGIC_TOGGLE_ALT_GUI` |`AG_TOGG`|Toggle Alt and GUI swap on both sides | +|`MAGIC_NO_GUI` |`GUI_OFF`|Disable the GUI keys | +|`MAGIC_UNNO_GUI` |`GUI_ON` |Enable the GUI keys | +|`MAGIC_SWAP_GRAVE_ESC` |`GE_SWAP`|Swap <code>`</code> and Escape | +|`MAGIC_UNSWAP_GRAVE_ESC` |`GE_NORM`|Unswap <code>`</code> and Escape | +|`MAGIC_SWAP_BACKSLASH_BACKSPACE` |`BS_SWAP`|Swap `\` and Backspace | +|`MAGIC_UNSWAP_BACKSLASH_BACKSPACE`|`BS_NORM`|Unswap `\` and Backspace | +|`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 | +|`MAGIC_EE_HANDS_LEFT` |`EH_LEFT`|Set the master half of a split keyboard as the left hand (for `EE_HANDS`) | +|`MAGIC_EE_HANDS_RIGHT` |`EH_RGHT`|Set the master half of a split keyboard as the right hand (for `EE_HANDS`)| diff --git a/docs/ref_functions.md b/docs/ref_functions.md index 27ae95aa93..c6185c8703 100644 --- a/docs/ref_functions.md +++ b/docs/ref_functions.md @@ -93,7 +93,7 @@ And to do so, add `reset_keyboard()` to your function or macro, and this will re ## 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](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 [`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. To wipe the EEPROM, run `eeconfig_init()` from your function or macro to reset most of the settings to default. diff --git a/docs/reference_configurator_support.md b/docs/reference_configurator_support.md index 1b34c85a29..ba3d49e2b2 100644 --- a/docs/reference_configurator_support.md +++ b/docs/reference_configurator_support.md @@ -99,8 +99,6 @@ Use the `keyboard_name` object to set the name of the keyboard. For instruction "tags": { "form_factor": "numpad" }, - "width": 4, - "height": 5, "layouts": { "LAYOUT": { "layout": [ diff --git a/docs/reference_info_json.md b/docs/reference_info_json.md index 30d813e93a..cf492629f3 100644 --- a/docs/reference_info_json.md +++ b/docs/reference_info_json.md @@ -15,10 +15,6 @@ The `info.json` file is a JSON formatted dictionary with the following keys avai * A URL to the keyboard's product page, [QMK.fm/keyboards](https://qmk.fm/keyboards) page, or other page describing information about the keyboard. * `maintainer` * GitHub username of the maintainer, or `qmk` for community maintained boards -* `width` - * Width of the board in Key Units -* `height` - * Height of the board in Key Units * `debounce` * How many milliseconds (ms) to wait for debounce to happen. (Default: 5) * `diode_direction` diff --git a/docs/serial_driver.md b/docs/serial_driver.md index 359fc59551..ed989b0a15 100644 --- a/docs/serial_driver.md +++ b/docs/serial_driver.md @@ -73,7 +73,7 @@ You must also enable the ChibiOS `SERIAL` feature: Do note that the configuration required is for the `SERIAL` peripheral, not the `UART` peripheral. ### USART Full-duplex -Targeting STM32 boards where communication is offloaded to a USART hardware device. The advantage over bitbang is that this provides fast and accurate timings. USART Full-Duplex requires two conductors **without** pull-up resistors instead of one conductor with a pull-up resistor unlike the Half-duplex driver, but it is more efficent as it uses DMA transfers, which can result in even faster transmission speeds. +Targeting STM32 boards where communication is offloaded to a USART hardware device. The advantage over bitbang is that this provides fast and accurate timings. USART Full-Duplex requires two conductors **without** pull-up resistors instead of one conductor with a pull-up resistor unlike the Half-duplex driver. Due to its internal design it is more efficent, which can result in even faster transmission speeds. #### Pin configuration @@ -86,12 +86,13 @@ Please note that `TX` of the master half has to be connected with the `RX` pin o To use the driver, add this to your rules.mk: ```make -SERIAL_DRIVER = usart_duplex +SERIAL_DRIVER = usart ``` Next configure the hardware via your config.h: ```c +#define SERIAL_USART_FULL_DUPLEX // Enable full duplex operation mode. #define SERIAL_USART_TX_PIN B6 // USART TX pin #define SERIAL_USART_RX_PIN B7 // USART RX pin //#define USART1_REMAP // Remap USART TX and RX pins on STM32F103 MCUs, see table below. @@ -104,17 +105,17 @@ Next configure the hardware via your config.h: // 3: 57600 baud // 4: 38400 baud // 5: 19200 baud -#define SERIAL_USART_DRIVER UARTD1 // USART driver of TX and RX pin. default: UARTD1 +#define SERIAL_USART_DRIVER SD1 // USART driver of TX and RX pin. default: SD1 #define SERIAL_USART_TX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7 #define SERIAL_USART_RX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7 #define SERIAL_USART_TIMEOUT 100 // USART driver timeout. default 100 ``` -You must also enable the ChibiOS `UART` with blocking api feature: -* In your board's halconf.h: `#define HAL_USE_UART TRUE` and `#define UART_USE_WAIT TRUE` -* In your board's mcuconf.h: `#define STM32_UART_USE_USARTn TRUE` (where 'n' matches the peripheral number of your selected USART on the MCU) +You must also enable the ChibiOS `SERIAL` feature: +* In your board's halconf.h: `#define HAL_USE_SERIAL TRUE` +* In your board's mcuconf.h: `#define STM32_SERIAL_USE_USARTn TRUE` (where 'n' matches the peripheral number of your selected USART on the MCU) -Do note that the configuration required is for the `UART` peripheral, not the `SERIAL` peripheral. +Do note that the configuration required is for the `SERIAL` peripheral, not the `UART` peripheral. #### Pins for USART Peripherals with Alternate Functions for selected STM32 MCUs diff --git a/docs/syllabus.md b/docs/syllabus.md index ec7f66ba78..ccb382c5d4 100644 --- a/docs/syllabus.md +++ b/docs/syllabus.md @@ -40,6 +40,7 @@ These topics start to dig into some of the features that QMK supports. You don't * [Tap Dance](feature_tap_dance.md) * [Combos](feature_combo.md) * [Userspace](feature_userspace.md) + * [Key Overrides](feature_key_overrides.md) # Advanced Topics @@ -53,7 +54,7 @@ Everything below here requires a lot of foundational knowledge. Besides being ab * **Advanced Features** * [Unicode](feature_unicode.md) * [API](api_overview.md) - * [Bootmagic](feature_bootmagic.md) + * [Bootmagic Lite](feature_bootmagic.md) * **Hardware** * [How Keyboards Work](how_keyboards_work.md) * [How A Keyboard Matrix Works](how_a_matrix_works.md) diff --git a/docs/tap_hold.md b/docs/tap_hold.md index 085bbde16a..71bff30baa 100644 --- a/docs/tap_hold.md +++ b/docs/tap_hold.md @@ -36,29 +36,49 @@ uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { } ``` +## Tap-Or-Hold Decision Modes -## Permissive Hold +The code which decides between the tap and hold actions of dual-role keys supports three different modes, in increasing order of preference for the hold action: -As of [PR#1359](https://github.com/qmk/qmk_firmware/pull/1359/), there is a new `config.h` option: +1. The default mode selects the hold action only if the dual-role key is held down longer than the tapping term. In this mode pressing other keys while the dual-role key is held down does not influence the tap-or-hold decision. + +2. The “permissive hold” mode, in addition to the default behavior, immediately selects the hold action when another key is tapped (pressed and then released) while the dual-role key is held down, even if this happens earlier than the tapping term. If another key is just pressed, but then the dual-role key is released before that other key (and earlier than the tapping term), this mode will still select the tap action. + +3. The “hold on other key press” mode, in addition to the default behavior, immediately selects the hold action when another key is pressed while the dual-role key is held down, even if this happens earlier than the tapping term. + +Note that until the tap-or-hold decision completes (which happens when either the dual-role key is released, or the tapping term has expired, or the extra condition for the selected decision mode is satisfied), key events are delayed and not transmitted to the host immediately. The default mode gives the most delay (if the dual-role key is held down, this mode always waits for the whole tapping term), and the other modes may give less delay when other keys are pressed, because the hold action may be selected earlier. + +### Permissive Hold + +The “permissive hold” mode can be enabled for all dual-role keys by adding the corresponding option to `config.h`: ```c #define PERMISSIVE_HOLD ``` -This makes tap and hold keys (like Mod Tap) work better for fast typists, or for high `TAPPING_TERM` settings. +This makes tap and hold keys (like Layer Tap) work better for fast typists, or for high `TAPPING_TERM` settings. -If you press a Mod Tap key, tap another key (press and release) and then release the Mod Tap key, all within the tapping term, it will output the tapping function for both keys. +If you press a dual-role key, tap another key (press and release) and then release the dual-role key, all within the tapping term, by default the dual-role key will perform its tap action. If the `PERMISSIVE_HOLD` option is enabled, the dual-role key will perform its hold action instead. -For Instance: +An example of a sequence which is affected by the “permissive hold” mode: -- `SFT_T(KC_A)` Down -- `KC_X` Down -- `KC_X` Up -- `SFT_T(KC_A)` Up +- `LT(2, KC_A)` Down +- `KC_L` Down (the `L` key is also mapped to `KC_RGHT` on layer 2) +- `KC_L` Up +- `LT(2, KC_A)` Up + +Normally, if you do all this within the `TAPPING_TERM` (default: 200ms), this will be registered as `al` by the firmware and host system. With the `PERMISSIVE_HOLD` option enabled, the Layer Tap key is considered as a layer switch if another key is tapped, and the above sequence would be registered as `KC_RGHT` (the mapping of `L` on layer 2). + +However, this slightly different sequence will not be affected by the “permissive hold” mode: -Normally, if you do all this within the `TAPPING_TERM` (default: 200ms) this will be registered as `ax` by the firmware and host system. With permissive hold enabled, this modifies how this is handled by considering the Mod Tap keys as a Mod if another key is tapped, and would registered as `X` (`SHIFT`+`x`). +- `LT(2, KC_A)` Down +- `KC_L` Down (the `L` key is also mapped to `KC_RGHT` on layer 2) +- `LT(2, KC_A)` Up +- `KC_L` Up -?> If you have `Ignore Mod Tap Interrupt` enabled, as well, this will modify how both work. The regular key has the modifier added if the first key is released first or if both keys are held longer than the `TAPPING_TERM`. +In the sequence above the dual-role key is released before the other key is released, and if that happens within the tapping term, the “permissive hold” mode will still choose the tap action for the dual-role key, and the sequence will be registered as `al` by the host. + +?> The `PERMISSIVE_HOLD` option also affects Mod Tap keys, but this may not be noticeable if you do not also enable the `IGNORE_MOD_TAP_INTERRUPT` option for those keys, because the default handler for Mod Tap keys also considers both the “nested press” and “rolling press” sequences like shown above as a modifier hold, not the tap action. If you do not enable `IGNORE_MOD_TAP_INTERRUPT`, the effect of `PERMISSIVE_HOLD` on Mod Tap keys would be limited to reducing the delay before the key events are made visible to the host. For more granular control of this feature, you can add the following to your `config.h`: @@ -72,13 +92,60 @@ You can then add the following function to your keymap: bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case LT(1, KC_BSPC): + // Immediately select the hold action when another key is tapped. + return true; + default: + // Do not select the hold action when another key is tapped. + return false; + } +} +``` + +### Hold On Other Key Press + +The “hold on other key press” mode can be enabled for all dual-role keys by adding the corresponding option to `config.h`: + +```c +#define HOLD_ON_OTHER_KEY_PRESS +``` + +This mode makes tap and hold keys (like Layer Tap) work better for fast typists, or for high `TAPPING_TERM` settings. Compared to the “permissive hold” mode, this mode selects the hold action in more cases. + +If you press a dual-role key, press another key, and then release the dual-role key, all within the tapping term, by default the dual-role key will perform its tap action. If the `HOLD_ON_OTHER_KEY_PRESS` option is enabled, the dual-role key will perform its hold action instead. + +An example of a sequence which is affected by the “hold on other key press” mode, but not by the “permissive hold” mode: + +- `LT(2, KC_A)` Down +- `KC_L` Down (the `L` key is also mapped to `KC_RGHT` on layer 2) +- `LT(2, KC_A)` Up +- `KC_L` Up + +Normally, if you do all this within the `TAPPING_TERM` (default: 200ms), this will be registered as `al` by the firmware and host system. With the `HOLD_ON_OTHER_KEY_PRESS` option enabled, the Layer Tap key is considered as a layer switch if another key is pressed, and the above sequence would be registered as `KC_RGHT` (the mapping of `L` on layer 2). + +?> The `HOLD_ON_OTHER_KEY_PRESS` option also affects Mod Tap keys, but this may not be noticeable if you do not also enable the `IGNORE_MOD_TAP_INTERRUPT` option for those keys, because the default handler for Mod Tap keys also considers the “rolling press” sequence like shown above as a modifier hold, not the tap action. If you do not enable `IGNORE_MOD_TAP_INTERRUPT`, the effect of `HOLD_ON_OTHER_KEY_PRESS` on Mod Tap keys would be limited to reducing the delay before the key events are made visible to the host. + +For more granular control of this feature, you can add the following to your `config.h`: + +```c +#define HOLD_ON_OTHER_KEY_PRESS_PER_KEY +``` + +You can then add the following function to your keymap: + +```c +bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case LT(1, KC_BSPC): + // Immediately select the hold action when another key is pressed. return true; default: + // Do not select the hold action when another key is pressed. return false; } } ``` + ## Ignore Mod Tap Interrupt To enable this setting, add this to your `config.h`: @@ -87,23 +154,22 @@ To enable this setting, add this to your `config.h`: #define IGNORE_MOD_TAP_INTERRUPT ``` -Similar to Permissive Hold, this alters how the firmware processes inputs for fast typists. If you press a Mod Tap key, press another key, release the Mod Tap key, and then release the normal key, it would normally output the Mod plus the normal key, even if pressed within the `TAPPING_TERM`. This may not be desirable for rolling combo keys, or for fast typists who have a Mod Tap on a frequently used key (`RCTL_T(KC_QUOT)`, for example). +?> This option affects only the Mod Tap keys; it does not affect other dual-role keys such as Layer Tap. + +By default the tap-or-hold decision for Mod Tap keys strongly prefers the hold action. If you press a Mod Tap key, then press another key while still holding the Mod Tap key down, the Mod Tap press will be handled as a modifier hold even if the Mod Tap key is then released within the tapping term, and irrespective of the order in which those keys are released. Using options such as `PERMISSIVE_HOLD` or `HOLD_ON_OTHER_KEY_PRESS` will not affect the functionality of Mod Tap keys in a major way (these options would still affect the delay until the common code for dual-role keys finishes its tap-or-hold decision, but then the special code for Mod Tap keys will override the result of that decision and choose the hold action if another key was pressed). In fact, by default the tap-or-hold decision for Mod Tap keys is done in the same way as if the `HOLD_ON_OTHER_KEY_PRESS` option was enabled, but without the decreased delay provided by `HOLD_ON_OTHER_KEY_PRESS`. -Setting `Ignore Mod Tap Interrupt` requires holding both keys for the `TAPPING_TERM` to trigger the hold function (the mod). +If the `IGNORE_MOD_TAP_INTERRUPT` option is enabled, Mod Tap keys are no longer treated as a special case, and their behavior will match the behavior of other dual-role keys such as Layer Tap. Then the behavior of Mod Tap keys can be further tuned using other options such as `PERMISSIVE_HOLD` or `HOLD_ON_OTHER_KEY_PRESS`. -For Instance: +An example of a sequence which will be affected by the `IGNORE_MOD_TAP_INTERRUPT` option (assuming that options like `PERMISSIVE_HOLD` or `HOLD_ON_OTHER_KEY_PRESS` are not enabled): - `SFT_T(KC_A)` Down - `KC_X` Down - `SFT_T(KC_A)` Up - `KC_X` Up -Normally, this would send a capital `X` (`SHIFT`+`x`), or, Mod + key. With `Ignore Mod Tap Interrupt` enabled, holding both keys are required for the `TAPPING_TERM` to register the hold action. A quick tap will output `ax` in this case, while a hold on both will still output capital `X` (`SHIFT`+`x`). - - -?> __Note__: This only concerns modifiers and not layer switching keys. +Normally, this would send a capital `X` (`SHIFT`+`x`), even if the sequence is performed faster than the `TAPPING_TERM`. However, if the `IGNORE_MOD_TAP_INTERRUPT` option is enabled, the `SFT_T(KC_A)` key must be held longer than the `TAPPING_TERM` to register the hold action. A quick tap will output `ax` in this case, while a hold will still output a capital `X` (`SHIFT`+`x`). -?> If you have `Permissive Hold` enabled, as well, this will modify how both work. The regular key has the modifier added if the first key is released first or if both keys are held longer than the `TAPPING_TERM`. +However, if the `HOLD_ON_OTHER_KEY_PRESS` option is enabled in addition to `IGNORE_MOD_TAP_INTERRUPT`, the above sequence will again send a capital `X` (`SHIFT`+`x`) even if performed faster that the `TAPPING_TERM`. The difference from the default configuration is that by default the host will receive the key events only after the `SFT_T(KC_A)` key is released, but with the `HOLD_ON_OTHER_KEY_PRESS` option the host will start receiving key events when the `KC_X` key is pressed. For more granular control of this feature, you can add the following to your `config.h`: @@ -117,8 +183,12 @@ You can then add the following function to your keymap: bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case SFT_T(KC_SPC): + // Do not force the mod-tap key press to be handled as a modifier + // if any other key was pressed while the mod-tap key is held down. return true; default: + // Force the mod-tap key press to be handled as a modifier if any + // other key was pressed while the mod-tap key is held down. return false; } } diff --git a/docs/understanding_qmk.md b/docs/understanding_qmk.md index 331b1c893c..e3dd5cb780 100644 --- a/docs/understanding_qmk.md +++ b/docs/understanding_qmk.md @@ -146,6 +146,7 @@ The `process_record()` function itself is deceptively simple, but hidden within * [`bool process_audio(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_audio.c#L19) * [`bool process_steno(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_steno.c#L160) * [`bool process_music(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_music.c#L114) + * [`bool process_key_override(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/5a1b857dea45a17698f6baa7dd1b7a7ea907fb0a/quantum/process_keycode/process_key_override.c#L397) * [`bool process_tap_dance(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_tap_dance.c#L141) * [`bool process_unicode_common(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_unicode_common.c#L169) calls one of: diff --git a/docs/zh-cn/custom_quantum_functions.md b/docs/zh-cn/custom_quantum_functions.md index 27b2edf38f..44cb5cf76d 100644 --- a/docs/zh-cn/custom_quantum_functions.md +++ b/docs/zh-cn/custom_quantum_functions.md @@ -297,7 +297,7 @@ void suspend_wakeup_init_user(void) { 本例使用了Planck键盘示范了如何设置 [RGB背光灯](feature_rgblight.md)使之与层对应 ```c -uint32_t layer_state_set_user(uint32_t state) { +layer_state_t layer_state_set_user(layer_state_t state) { switch (biton32(state)) { case _RAISE: rgblight_setrgb (0x00, 0x00, 0xFF); @@ -321,7 +321,7 @@ uint32_t layer_state_set_user(uint32_t state) { ### `layer_state_set_*` 函数文档 * 键盘/修订: `uint32_t layer_state_set_kb(uint32_t state)` -* 布局: `uint32_t layer_state_set_user(uint32_t state)` +* 布局: `layer_state_t layer_state_set_user(layer_state_t state)` 该`状态`是活动层的bitmask, 详见[布局概述](keymap.md#布局的层状态) @@ -377,7 +377,7 @@ void keyboard_post_init_user(void) { 以上函数会在读EEPROM配置后立即使用该设置来设置默认层RGB颜色。"raw"的值是从你上面基于"union"创建的结构体中转换来的。 ```c -uint32_t layer_state_set_user(uint32_t state) { +layer_state_t layer_state_set_user(layer_state_t state) { switch (biton32(state)) { case _RAISE: if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_magenta(); rgblight_mode_noeeprom(1); } |