Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Doc] Add example to keyboard housekeeping and some minor fixes #19968

Merged
merged 6 commits into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion docs/custom_quantum_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,70 @@ This function gets called at the end of all QMK processing, before starting the

Similar to `matrix_scan_*`, these are called as often as the MCU can handle. To keep your board responsive, it's suggested to do as little as possible during these function calls, potentially throtting their behaviour if you do indeed require implementing something special.

### Example `void housekeeping_task_user(void)` implementation

This example will show you how to use `void housekeeping_task_user(void)` to turn off RGB light. For RGB Matrix just use `#define RGB_MATRIX_TIMEOUT` in your `config.h`.

First add those lines to your user `config.h`.
ForsakenRei marked this conversation as resolved.
Show resolved Hide resolved

```c
#define RGBLIGHT_SLEEP // enable rgblight_suspend() and rgblight_wakeup() in keymap.c
#define RGBLIGHT_TIMEOUT 900000 // ms to wait until rgblight time out, 900K ms is 15min.
```

And add those lines to your `keymap.c`.
ForsakenRei marked this conversation as resolved.
Show resolved Hide resolved

```c
static uint32_t key_timer; // timer for last keyboard activity, use 32bit value and function to make longer idle time possible
static void refresh_rgb(void); // refreshes the activity timer and RGB, invoke whenever any activity happens
static void check_rgb_timeout(void); // checks if enough time has passed for RGB to timeout
bool is_rgb_timeout = false; // store if RGB has timed out or not in a boolean

void refresh_rgb(void) {
key_timer = timer_read32(); // store time of last refresh
if (is_rgb_timeout)
{
is_rgb_timeout = false;
rgblight_wakeup();
}
}
void check_rgb_timeout(void) {
if (!is_rgb_timeout && timer_elapsed32(key_timer) > RGBLIGHT_TIMEOUT) // check if RGB has already timeout and if enough time has passed
{
rgblight_suspend();
is_rgb_timeout = true;
}
}
/* Then, call the above functions from QMK's built in post processing functions like so */
/* Runs at the end of each scan loop, check if RGB timeout has occured or not */
void housekeeping_task_user(void) {
#ifdef RGBLIGHT_TIMEOUT
check_rgb_timeout();
#endif
}
/* Runs after each key press, check if activity occurred */
void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
#ifdef RGBLIGHT_TIMEOUT
if (record->event.pressed)
refresh_rgb();
#endif
}
/* Runs after each encoder tick, check if activity occurred */
void post_encoder_update_user(uint8_t index, bool clockwise) {
#ifdef RGBLIGHT_TIMEOUT
refresh_rgb();
#endif
}
```

# Keyboard Idling/Wake Code

If the board supports it, it can be "idled", by stopping a number of functions. A good example of this is RGB lights or backlights. This can save on power consumption, or may be better behavior for your keyboard.

This is controlled by two functions: `suspend_power_down_*` and `suspend_wakeup_init_*`, which are called when the system board is idled and when it wakes up, respectively.


### Example suspend_power_down_user() and suspend_wakeup_init_user() Implementation
### Example `suspend_power_down_user()` and `suspend_wakeup_init_user()` Implementation


```c
Expand Down
5 changes: 5 additions & 0 deletions docs/feature_advanced_keycodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
return true;
};
```
Alternatively, this can be done with [Key Overrides](feature_key_overrides?id=simple-example).

# Advanced topics :id=advanced-topics

Expand All @@ -180,3 +181,7 @@ This page used to encompass a large set of features. We have moved many sections
## Tap-Hold Configuration Options :id=tap-hold-configuration-options

* [Tap-Hold Configuration Options](tap_hold.md)

## Key Overrides :id=key-overrides

* [Key Overrides](feature_key_overrides.md)
34 changes: 17 additions & 17 deletions docs/feature_key_overrides.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Key Overrides
# Key Overrides :id=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.

Expand All @@ -10,13 +10,13 @@ You can use key overrides in a similar way to momentary layer/fn keys to activat
- 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
## Setup :id=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
## Creating Key Overrides :id=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:

Expand All @@ -34,7 +34,7 @@ Additionally takes a bitmask `options` that specifies additional options. See `k

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
## Simple Example :id=simple-example

This shows how the mentioned example of sending `delete` when `shift` + `backspace` are pressed is realized:

Expand All @@ -48,9 +48,9 @@ const key_override_t **key_overrides = (const key_override_t *[]){
};
```

## Intermediate Difficulty Examples
## Intermediate Difficulty Examples :id=intermediate-difficulty-examples

### Media Controls & Screen Brightness
### Media Controls & Screen Brightness :id=media-controls-amp-screen-brightness

In this example a single key is configured to control media, volume and screen brightness by using key overrides.

Expand Down Expand Up @@ -102,7 +102,7 @@ const key_override_t **key_overrides = (const key_override_t *[]){
};
```

### Flexible macOS-friendly Grave Escape
### Flexible macOS-friendly Grave Escape :id=flexible-macos-friendly-grave-escape
The [Grave Escape feature](feature_grave_esc.md) is limited in its configurability and has [bugs when used on macOS](feature_grave_esc.md#caveats). Key overrides can be used to achieve a similar functionality as Grave Escape, but with more customization and without bugs on macOS.

```c
Expand All @@ -121,8 +121,8 @@ const key_override_t **key_overrides = (const key_override_t *[]){

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
## Advanced Examples :id=advanced-examples
### Modifiers as Layer Keys :id=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.

Expand Down Expand Up @@ -150,15 +150,15 @@ const key_override_t fn_override = {.trigger_mods = MOD_BIT(KC_RGUI) |
.enabled = NULL};
```

## Keycodes
## Keycodes :id=keycodes

|Keycode |Aliases |Description |
|------------------------|---------|----------------------|
|`QK_KEY_OVERRIDE_TOGGLE`|`KO_TOGG`|Toggle key overrides |
|`QK_KEY_OVERRIDE_ON` |`KO_ON` |Turn on key overrides |
|`QK_KEY_OVERRIDE_OFF` |`KO_OFF` |Turn off key overrides|

## Reference for `key_override_t`
## Reference for `key_override_t` :id=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`.

Expand All @@ -175,7 +175,7 @@ Advanced users may need more customization than what is offered by the simple `k
| `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`
## Reference for `ko_option_t` :id=reference-for-ko_option_t

Bitfield with various options controlling the behavior of a key override.

Expand All @@ -189,11 +189,11 @@ Bitfield with various options controlling the behavior of a key override.
| `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
## For Advanced Users: Inner Workings :id=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
#### Activation :id=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.

Expand All @@ -207,11 +207,11 @@ Use the `option` member to customize which of these events are allowed to activa

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
#### Deactivation :id=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
#### Key Repeat Delay :id=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.

Expand All @@ -222,6 +222,6 @@ This applies equally to releasing a modifier: When you hold `shift`, then press
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
## Difference to Combos :id=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.
2 changes: 1 addition & 1 deletion keyboards/gray_studio/space65r3/readme.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Gray Studio 65 R3
# Gray Studio Space65 R3

A 65% keyboard by Graystudio. PCB designed and manufactured by DEMO Studio.

Expand Down