summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/ChangeLog/20220226/PR15304.md13
-rw-r--r--docs/feature_debounce_type.md1
-rw-r--r--docs/feature_haptic_feedback.md4
-rw-r--r--docs/feature_key_lock.md3
-rw-r--r--docs/feature_pointing_device.md122
-rw-r--r--docs/feature_split_keyboard.md8
-rw-r--r--docs/feature_wpm.md2
-rw-r--r--docs/internals_gpio_control.md24
-rw-r--r--docs/keycodes.md1
-rw-r--r--docs/keycodes_magic.md1
10 files changed, 150 insertions, 29 deletions
diff --git a/docs/ChangeLog/20220226/PR15304.md b/docs/ChangeLog/20220226/PR15304.md
new file mode 100644
index 0000000000..3cdb40db10
--- /dev/null
+++ b/docs/ChangeLog/20220226/PR15304.md
@@ -0,0 +1,13 @@
+### Split Common core now supports Pointing Devices ([#15304](https://github.com/qmk/qmk_firmware/pull/15304))
+
+Pointing devices can now be shared across a split keyboard with support for a single pointing device or a pointing device on each side.
+
+This feature can be enabled with `#define SPLIT_POINTING_ENABLE` and one of the following options:
+
+| Setting | Description |
+|---------------------------|------------------------------------|
+|`POINTING_DEVICE_LEFT` | Pointing device on the left side |
+|`POINTING_DEVICE_RIGHT` | Pointing device on the right side |
+|`POINTING_DEVICE_COMBINED` | Pointing device on both sides |
+
+See the [Pointing Device](../feature_pointing_device.md) documentation for further configuration options.
diff --git a/docs/feature_debounce_type.md b/docs/feature_debounce_type.md
index f37a785b1e..9cd736a24a 100644
--- a/docs/feature_debounce_type.md
+++ b/docs/feature_debounce_type.md
@@ -116,6 +116,7 @@ Where name of algorithm is one of:
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_pr``` - debouncing per row. On any state change, a per-row timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that row, the entire row is pushed. Can improve responsiveness over `sym_defer_g` while being less susceptible than per-key debouncers to noise.
* ```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.
diff --git a/docs/feature_haptic_feedback.md b/docs/feature_haptic_feedback.md
index c8c74cb8f0..bbdf7e122c 100644
--- a/docs/feature_haptic_feedback.md
+++ b/docs/feature_haptic_feedback.md
@@ -167,7 +167,7 @@ List of waveform sequences from the datasheet:
```
#define DRV_GREETING *sequence name or number*
```
-If haptic feedback is enabled, the keyboard will vibrate to a specific sqeuence during startup. That can be selected using the following define:
+If haptic feedback is enabled, the keyboard will vibrate to a specific sequence during startup. That can be selected using the following define:
```
#define DRV_MODE_DEFAULT *sequence name or number*
@@ -207,4 +207,4 @@ With the entry of `#define NO_HAPTIC_LOCKKEYS` in config.h, none of the followin
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
+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.
diff --git a/docs/feature_key_lock.md b/docs/feature_key_lock.md
index 8e6e29f0e6..7681394229 100644
--- a/docs/feature_key_lock.md
+++ b/docs/feature_key_lock.md
@@ -19,4 +19,5 @@ First, enable Key Lock by setting `KEY_LOCK_ENABLE = yes` in your `rules.mk`. Th
Key Lock is only able to hold standard action keys and [One Shot modifier](one_shot_keys.md) keys (for example, if you have your Shift defined as `OSM(KC_LSFT)`).
This does not include any of the QMK special functions (except One Shot modifiers), or shifted versions of keys such as `KC_LPRN`. If it's in the [Basic Keycodes](keycodes_basic.md) list, it can be held.
-Switching layers will not cancel the Key Lock.
+Switching layers will not cancel the Key Lock. The Key Lock can be cancelled by calling the `cancel_key_lock()` function.
+
diff --git a/docs/feature_pointing_device.md b/docs/feature_pointing_device.md
index bd7fb36589..f8de92f3b4 100644
--- a/docs/feature_pointing_device.md
+++ b/docs/feature_pointing_device.md
@@ -30,7 +30,7 @@ The ADNS 5050 sensor uses a serial type protocol for communication, and requires
The CPI range is 125-1375, in increments of 125. Defaults to 500 CPI.
-### ADSN 9800 Sensor
+### ADNS 9800 Sensor
To use the ADNS 9800 sensor, add this to your `rules.mk`
@@ -69,7 +69,7 @@ The Analog Joystick is an analog (ADC) driven sensor. There are a variety of jo
|`ANALOG_JOYSTICK_AXIS_MAX` | (Optional) Sets the upper range to be considered movement. | `1023` |
|`ANALOG_JOYSTICK_SPEED_REGULATOR` | (Optional) The divisor used to slow down movement. (lower makes it faster) | `20` |
|`ANALOG_JOYSTICK_READ_INTERVAL` | (Optional) The interval in milliseconds between reads. | `10` |
-|`ANALOG_JOYSTICK_SPEED_MAX` | (Optional) The maxiumum value used for motion. | `2` |
+|`ANALOG_JOYSTICK_SPEED_MAX` | (Optional) The maximum value used for motion. | `2` |
|`ANALOG_JOYSTICK_CLICK_PIN` | (Optional) The pin wired up to the press switch of the analog stick. | _not defined_ |
@@ -127,11 +127,10 @@ The Pimoroni Trackball module is a I2C based breakout board with an RGB enable t
| Setting | Description | Default |
|-------------------------------------|------------------------------------------------------------------------------------|---------|
|`PIMORONI_TRACKBALL_ADDRESS` | (Required) Sets the I2C Address for the Pimoroni Trackball. | `0x0A` |
-|`PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackpad in milliseconds. | `100` |
-|`PIMORONI_TRACKBALL_INTERVAL_MS` | (Optional) The update/read interval for the sensor in milliseconds. | `8` |
+|`PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackball in milliseconds. | `100` |
|`PIMORONI_TRACKBALL_SCALE` | (Optional) The multiplier used to generate reports from the sensor. | `5` |
|`PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` |
-|`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` |
+|`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` |
### PMW 3360 Sensor
@@ -171,14 +170,35 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
## Common Configuration
-| Setting | Description | Default |
-|-------------------------------|-----------------------------------------------------------------------|---------------|
-|`POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ |
-|`POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ |
-|`POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ |
-|`POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ |
-|`POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ |
-|`POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ |
+| Setting | Description | Default |
+|----------------------------------|-----------------------------------------------------------------------|-------------------|
+|`POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ |
+|`POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ |
+|`POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ |
+|`POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ |
+|`POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ |
+|`POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ |
+|`POINTING_DEVICE_TASK_THROTTLE_MS` | (Optional) Limits the frequency that the sensor is polled for motion. | _not defined_ |
+
+!> When using `SPLIT_POINTING_ENABLE` the `POINTING_DEVICE_MOTION_PIN` functionality is not supported and would recommend `POINTING_DEVICE_TASK_THROTTLE_MS` be set to `1`. Increasing this value will increase transport performance at the cost of possible mouse responsiveness.
+
+
+## Split Keyboard Configuration
+
+The following configuration options are only available when using `SPLIT_POINTING_ENABLE` see [data sync options](feature_split_keyboard.md?id=data-sync-options). The rotation and invert `*_RIGHT` options are only used with `POINTING_DEVICE_COMBINED`. If using `POINTING_DEVICE_LEFT` or `POINTING_DEVICE_RIGHT` use the common configuration above to configure your pointing device.
+
+| Setting | Description | Default |
+|----------------------------------------|-----------------------------------------------------------------------|---------------|
+|`POINTING_DEVICE_LEFT` | Pointing device on the left side (Required - pick one only) | _not defined_ |
+|`POINTING_DEVICE_RIGHT` | Pointing device on the right side (Required - pick one only) | _not defined_ |
+|`POINTING_DEVICE_COMBINED` | Pointing device on both sides (Required - pick one only) | _not defined_ |
+|`POINTING_DEVICE_ROTATION_90_RIGHT` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ |
+|`POINTING_DEVICE_ROTATION_180_RIGHT` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ |
+|`POINTING_DEVICE_ROTATION_270_RIGHT` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ |
+|`POINTING_DEVICE_INVERT_X_RIGHT` | (Optional) Inverts the X axis report. | _not defined_ |
+|`POINTING_DEVICE_INVERT_Y_RIGHT` | (Optional) Inverts the Y axis report. | _not defined_ |
+
+!> If there is a `_RIGHT` configuration option or callback, the [common configuration](feature_pointing_device.md?id=common-configuration) option will work for the left. For correct left/right detection you should setup a [handedness option](feature_split_keyboard?id=setting-handedness), `EE_HANDS` is usually a good option for an existing board that doesn't do handedness by hardware.
## Callbacks and Functions
@@ -188,7 +208,7 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
| `pointing_device_init_kb(void)` | Callback to allow for keyboard level initialization. Useful for additional hardware sensors. |
| `pointing_device_init_user(void)` | Callback to allow for user level initialization. Useful for additional hardware sensors. |
| `pointing_device_task_kb(mouse_report)` | Callback that sends sensor data, so keyboard code can intercept and modify the data. Returns a mouse report. |
-| `pointing_device_task_user(mouse_report)` | Callback that sends sensor data, so user coe can intercept and modify the data. Returns a mouse report. |
+| `pointing_device_task_user(mouse_report)` | Callback that sends sensor data, so user code can intercept and modify the data. Returns a mouse report. |
| `pointing_device_handle_buttons(buttons, pressed, button)` | Callback to handle hardware button presses. Returns a `uint8_t`. |
| `pointing_device_get_cpi(void)` | Gets the current CPI/DPI setting from the sensor, if supported. |
| `pointing_device_set_cpi(uint16_t)` | Sets the CPI/DPI, if supported. |
@@ -196,6 +216,21 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
| `pointing_device_set_report(mouse_report)` | Sets the mouse report to the assigned `mouse_report_t` data structured passed to the function. |
| `pointing_device_send(void)` | Sends the current mouse report to the host system. Function can be replaced. |
| `has_mouse_report_changed(old, new)` | Compares the old and new `mouse_report_t` data and returns true only if it has changed. |
+| `pointing_device_adjust_by_defines(mouse_report)` | Applies rotations and invert configurations to a raw mouse report. |
+
+
+## Split Keyboard Callbacks and Functions
+
+The combined functions below are only available when using `SPLIT_POINTING_ENABLE` and `POINTING_DEVICE_COMBINED`. The 2 callbacks `pointing_device_task_combined_*` replace the single sided equivalents above. See the [combined pointing devices example](feature_pointing_device.md?id=combined-pointing-devices)
+
+| Function | Description |
+|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
+| `pointing_device_set_shared_report(mouse_report)` | Sets the shared mouse report to the assigned `mouse_report_t` data structured passed to the function. |
+| `pointing_device_set_cpi_on_side(bool, uint16_t)` | Sets the CPI/DPI of one side, if supported. Passing `true` will set the left and `false` the right` |
+| `pointing_device_combine_reports(left_report, right_report)` | Returns a combined mouse_report of left_report and right_report (as a `mouse_report_t` data structure) |
+| `pointing_device_task_combined_kb(left_report, right_report)` | Callback, so keyboard code can intercept and modify the data. Returns a combined mouse report. |
+| `pointing_device_task_combined_user(left_report, right_report)` | Callback, so user code can intercept and modify. Returns a combined mouse report using `pointing_device_combine_reports` |
+| `pointing_device_adjust_by_defines_right(mouse_report)` | Applies right side rotations and invert configurations to a raw mouse report. |
# Manipulating Mouse Reports
@@ -242,3 +277,62 @@ case MS_SPECIAL:
```
Recall that the mouse report is set to zero (except the buttons) whenever it is sent, so the scrolling would only occur once in each case.
+
+## Split Examples
+
+The following examples make use the `SPLIT_POINTING_ENABLE` functionality and show how to manipulate the mouse report for a scrolling mode.
+
+### Single Pointing Device
+
+The following example will work with either `POINTING_DEVICE_LEFT` or `POINTING_DEVICE_RIGHT` and enables scrolling mode while on a particular layer.
+
+```c
+
+static bool scrolling_mode = false;
+
+layer_state_t layer_state_set_user(layer_state_t state) {
+ switch (get_highest_layer(state)) {
+ case _RAISE: // If we're on the _RAISE layer enable scrolling mode
+ scrolling_mode = true;
+ pointing_device_set_cpi(2000);
+ break;
+ default:
+ if (scrolling_mode) { // check if we were scrolling before and set disable if so
+ scrolling_mode = false;
+ pointing_device_set_cpi(8000);
+ }
+ break;
+ }
+ return state;
+}
+
+report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
+ if (scrolling_mode) {
+ mouse_report.h = mouse_report.x;
+ mouse_report.v = mouse_report.y;
+ mouse_report.x = 0;
+ mouse_report.y = 0;
+ }
+ return mouse_report;
+}
+
+```
+
+### Combined Pointing Devices
+
+The following example requires `POINTING_DEVICE_COMBINED` and sets the left side pointing device to scroll only.
+
+```c
+void keyboard_post_init_user(void) {
+ pointing_device_set_cpi_on_side(true, 1000); //Set cpi on left side to a low value for slower scrolling.
+ pointing_device_set_cpi_on_side(false, 8000); //Set cpi on right side to a reasonable value for mousing.
+}
+
+report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) {
+ left_report.h = left_report.x;
+ left_report.v = left_report.y;
+ left_report.x = 0;
+ left_report.y = 0;
+ return pointing_device_combine_reports(left_report, right_report);
+}
+```
diff --git a/docs/feature_split_keyboard.md b/docs/feature_split_keyboard.md
index c8ba18beeb..b51593308e 100644
--- a/docs/feature_split_keyboard.md
+++ b/docs/feature_split_keyboard.md
@@ -266,6 +266,14 @@ This enables transmitting the current OLED on/off status to the slave side of th
This enables transmitting the current ST7565 on/off status to the slave side of the split keyboard. The purpose of this feature is to support state (on/off state only) syncing.
+```c
+#define SPLIT_POINTING_ENABLE
+```
+
+This enables transmitting the pointing device status to the master side of the split keyboard. The purpose of this feature is to enable use pointing devices on the slave side.
+
+!> There is additional required configuration for `SPLIT_POINTING_ENABLE` outlined in the [pointing device documentation](feature_pointing_device.md?id=split-keyboard-configuration).
+
### Custom data sync between sides :id=custom-data-sync
QMK's split transport allows for arbitrary data transactions at both the keyboard and user levels. This is modelled on a remote procedure call, with the master invoking a function on the slave side, with the ability to send data from master to slave, process it slave side, and send data back from slave to master.
diff --git a/docs/feature_wpm.md b/docs/feature_wpm.md
index 87145c97e3..9f98ef8336 100644
--- a/docs/feature_wpm.md
+++ b/docs/feature_wpm.md
@@ -16,7 +16,7 @@ For split keyboards using soft serial, the computed WPM score will be available
| `WPM_ALLOW_COUNT_REGRESSION` | _Not defined_ | If defined allows the WPM to be decreased when hitting Delete or Backspace |
| `WPM_UNFILTERED` | _Not defined_ | If undefined (the default), WPM values will be smoothed to avoid sudden changes in value |
| `WPM_SAMPLE_SECONDS` | `5` | This defines how many seconds of typing to average, when calculating WPM |
-| `WPM_SAMPLE_PERIODS` | `50` | This defines how many sampling periods to use when calculating WPM |
+| `WPM_SAMPLE_PERIODS` | `25` | This defines how many sampling periods to use when calculating WPM |
| `WPM_LAUNCH_CONTROL` | _Not defined_ | If defined, WPM values will be calculated using partial buffers when typing begins |
'WPM_UNFILTERED' is potentially useful if you're filtering data in some other way (and also because it reduces the code required for the WPM feature), or if reducing measurement latency to a minimum is important for you.
diff --git a/docs/internals_gpio_control.md b/docs/internals_gpio_control.md
index ccd3f8c74d..e1f1515b71 100644
--- a/docs/internals_gpio_control.md
+++ b/docs/internals_gpio_control.md
@@ -6,17 +6,19 @@ QMK has a GPIO control abstraction layer which is microcontroller agnostic. This
The following functions provide basic control of GPIOs and are found in `platforms/<platform>/gpio.h`.
-|Function |Description | Old AVR Examples | Old ChibiOS/ARM Examples |
-|------------------------|--------------------------------------------------|-------------------------------------------------|-------------------------------------------------|
-| `setPinInput(pin)` | Set pin as input with high impedance (High-Z) | `DDRB &= ~(1<<2)` | `palSetLineMode(pin, PAL_MODE_INPUT)` |
-| `setPinInputHigh(pin)` | Set pin as input with builtin pull-up resistor | `DDRB &= ~(1<<2); PORTB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_INPUT_PULLUP)` |
-| `setPinInputLow(pin)` | Set pin as input with builtin pull-down resistor | N/A (Not supported on AVR) | `palSetLineMode(pin, PAL_MODE_INPUT_PULLDOWN)` |
-| `setPinOutput(pin)` | Set pin as output | `DDRB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_OUTPUT_PUSHPULL)` |
-| `writePinHigh(pin)` | Set pin level as high, assuming it is an output | `PORTB \|= (1<<2)` | `palSetLine(pin)` |
-| `writePinLow(pin)` | Set pin level as low, assuming it is an output | `PORTB &= ~(1<<2)` | `palClearLine(pin)` |
-| `writePin(pin, level)` | Set pin level, assuming it is an output | `(level) ? PORTB \|= (1<<2) : PORTB &= ~(1<<2)` | `(level) ? palSetLine(pin) : palClearLine(pin)` |
-| `readPin(pin)` | Returns the level of the pin | `_SFR_IO8(pin >> 4) & _BV(pin & 0xF)` | `palReadLine(pin)` |
-| `togglePin(pin)` | Invert pin level, assuming it is an output | `PORTB ^= (1<<2)` | `palToggleLine(pin)` |
+| Function | Description | Old AVR Examples | Old ChibiOS/ARM Examples |
+|------------------------------|-----------------------------------------------------|-------------------------------------------------|--------------------------------------------------|
+| `setPinInput(pin)` | Set pin as input with high impedance (High-Z) | `DDRB &= ~(1<<2)` | `palSetLineMode(pin, PAL_MODE_INPUT)` |
+| `setPinInputHigh(pin)` | Set pin as input with builtin pull-up resistor | `DDRB &= ~(1<<2); PORTB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_INPUT_PULLUP)` |
+| `setPinInputLow(pin)` | Set pin as input with builtin pull-down resistor | N/A (Not supported on AVR) | `palSetLineMode(pin, PAL_MODE_INPUT_PULLDOWN)` |
+| `setPinOutput(pin)` | Set pin as output (alias of `setPinOutputPushPull`) | `DDRB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_OUTPUT_PUSHPULL)` |
+| `setPinOutputPushPull(pin)` | Set pin as output, push/pull mode | `DDRB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_OUTPUT_PUSHPULL)` |
+| `setPinOutputOpenDrain(pin)` | Set pin as output, open-drain mode | N/A (Not implemented on AVR) | `palSetLineMode(pin, PAL_MODE_OUTPUT_OPENDRAIN)` |
+| `writePinHigh(pin)` | Set pin level as high, assuming it is an output | `PORTB \|= (1<<2)` | `palSetLine(pin)` |
+| `writePinLow(pin)` | Set pin level as low, assuming it is an output | `PORTB &= ~(1<<2)` | `palClearLine(pin)` |
+| `writePin(pin, level)` | Set pin level, assuming it is an output | `(level) ? PORTB \|= (1<<2) : PORTB &= ~(1<<2)` | `(level) ? palSetLine(pin) : palClearLine(pin)` |
+| `readPin(pin)` | Returns the level of the pin | `_SFR_IO8(pin >> 4) & _BV(pin & 0xF)` | `palReadLine(pin)` |
+| `togglePin(pin)` | Invert pin level, assuming it is an output | `PORTB ^= (1<<2)` | `palToggleLine(pin)` |
## Advanced Settings :id=advanced-settings
diff --git a/docs/keycodes.md b/docs/keycodes.md
index ba06e1b8b6..2ea4fc74e2 100644
--- a/docs/keycodes.md
+++ b/docs/keycodes.md
@@ -326,6 +326,7 @@ See also: [Magic Keycodes](keycodes_magic.md)
|----------------------------------|---------|--------------------------------------------------------------------------|
|`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_TOGGLE_CONTROL_CAPSLOCK` |`CL_TOGG`|Toggle Caps Lock and Left Control swap |
|`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 |
diff --git a/docs/keycodes_magic.md b/docs/keycodes_magic.md
index 7e1b1a4f62..01eb69168e 100644
--- a/docs/keycodes_magic.md
+++ b/docs/keycodes_magic.md
@@ -6,6 +6,7 @@
|----------------------------------|---------|--------------------------------------------------------------------------|
|`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_TOGGLE_CONTROL_CAPSLOCK` |`CL_TOGG`|Toggle Caps Lock and Left Control swap |
|`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 |