diff options
author | Pascal Getreuer <[email protected]> | 2025-03-19 12:45:56 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2025-03-19 20:45:56 +0100 |
commit | 3484f0a0dffd264ae3bef70ce2a8961489c16f50 (patch) | |
tree | 6c9611c3510dc970fd586ee7bc61d9e0265bfd2d /quantum/keycode_string.h | |
parent | 40a446a0ec1f2f7cb8c52538bfefb1b26c951dd4 (diff) | |
download | qmk_firmware-3484f0a0dffd264ae3bef70ce2a8961489c16f50.tar.gz qmk_firmware-3484f0a0dffd264ae3bef70ce2a8961489c16f50.zip |
[Core] get_keycode_string(): function to format keycodes as strings, for more readable debug logging. (#24787)
* keycode_string(): Format keycodes as strings.
This adds the `keycode_string()` function described in
https://getreuer.info/posts/keyboards/keycode-string/index.html
as a core feature.
* Fix formatting.
* keycode_string review revisions.
* Rename keycode_string() -> get_keycode_string() for consistency with
existing string utils like get_u8_str().
* Revise custom keycode names with separate _user and _kb tables.
* Correct indent in builddefs/generic_features.mk.
Co-authored-by: Ryan <[email protected]>
* Add KC_NUHS, KC_NUBS, and KC_CAPS.
* Fix linking error with custom names.
* Attempt at simplifying interface.
* Formatting fix.
* Several fixes and revisions.
* Don't use PSTR in KEYCODE_STRING_NAME, since this fails to build on
AVR. Store custom names in RAM.
* Revise the internal table of common keycode names to use its own
storage representation, still in PROGMEM, and now more efficiently
stored flat in 8 bytes per entry.
* Support Swap Hands keycodes and a few other keycodes.
* Revert "Formatting fix."
This reverts commit 2a2771068c7ee545ffac4103aa07e847a9ec3816.
* Revert "Attempt at simplifying interface."
This reverts commit 8eaf67de76e75bc92d106a8b0decc893fbc65fa5.
* Simplify custom names API by sigprof's suggestion.
* Support more keycodes.
* Add QK_LOCK keycode.
* Add Secure keycodes.
* Add Joystick keycodes.
* Add Programmable Button keycodes.
* Add macro MC_ keycodes.
* For remaining keys in known code ranges, stringify them as
"QK_<feature>+<number>". For instance, "QK_MIDI+7".
* Bug fix and a few improvements.
* Fix missing right-hand bit when displaying 5-bit mods numerically.
* Support KC_HYPR, KC_MEH, HYPR_T(kc), MEH_T(kc).
* Exclude one-shot keycodes when NO_ACTION_ONESHOT is defined.
---------
Co-authored-by: Ryan <[email protected]>
Diffstat (limited to 'quantum/keycode_string.h')
-rw-r--r-- | quantum/keycode_string.h | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/quantum/keycode_string.h b/quantum/keycode_string.h new file mode 100644 index 0000000000..1315613a80 --- /dev/null +++ b/quantum/keycode_string.h @@ -0,0 +1,134 @@ +// Copyright 2024-2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include <stdint.h> + +#if KEYCODE_STRING_ENABLE + +/** + * @brief Formats a QMK keycode as a human-readable string. + * + * Given a keycode, like `KC_A`, this function returns a formatted string, like + * "KC_A". This is useful for debugging and diagnostics so that keys are more + * easily identified than they would be by raw numerical codes. + * + * @note The returned char* string should be used right away. The string memory + * is reused and will be overwritten by the next call to `keycode_string()`. + * + * Many common QMK keycodes are understood by this function, but not all. + * Recognized keycodes include: + * + * - Most basic keycodes, including letters `KC_A` - `KC_Z`, digits `KC_0` - + * `KC_9`, function keys `KC_F1` - `KC_F24`, and modifiers like `KC_LSFT`. + * + * - Modified basic keycodes, like `S(KC_1)` (Shift + 1 = !). + * + * - `MO`, `TO`, `TG`, `OSL`, `LM(layer,mod)`, `LT(layer,kc)` layer switches. + * + * - One-shot mod `OSM(mod)` keycodes. + * + * - Mod-tap `MT(mod, kc)` keycodes. + * + * - Tap dance keycodes `TD(i)`. + * + * - Swap hands keycodes `SH_T(kc)`, `SH_TOGG`, etc. + * + * - Joystick keycodes `JS_n`. + * + * - Programmable button keycodes `PB_n`. + * + * - Unicode `UC(codepoint)` and Unicode Map `UM(i)` and `UP(i,j)` keycodes. + * + * - Keyboard range keycodes `QK_KB_*`. + * + * - User range (SAFE_RANGE) keycodes `QK_USER_*`. + * + * Keycodes involving mods like `OSM`, `LM`, `MT` are fully supported only where + * a single mod is applied. + * + * Unrecognized keycodes are printed numerically as hex values like `0x1ABC`. + * + * Optionally, use `keycode_string_names_user` or `keycode_string_names_kb` to + * define names for additional keycodes or override how any of the above are + * formatted. + * + * @param keycode QMK keycode. + * @return Stringified keycode. + */ +const char* get_keycode_string(uint16_t keycode); + +/** Defines a human-readable name for a keycode. */ +typedef struct { + uint16_t keycode; + const char* name; +} keycode_string_name_t; + +// clang-format off +/** + * @brief Defines names for additional keycodes for `get_keycode_string()`. + * + * Define `KEYCODE_STRING_NAMES_USER` in your keymap.c to add names for + * additional keycodes to `keycode_string()`. This table may also be used to + * override how `keycode_string()` formats a keycode. For example, supposing + * keymap.c defines `MYMACRO1` and `MYMACRO2` as custom keycodes: + * + * KEYCODE_STRING_NAMES_USER( + * KEYCODE_STRING_NAME(MYMACRO1), + * KEYCODE_STRING_NAME(MYMACRO2), + * KEYCODE_STRING_NAME(KC_EXLM), + * ); + * + * The above defines names for `MYMACRO1` and `MYMACRO2`, and overrides + * `KC_EXLM` to format as "KC_EXLM" instead of the default "S(KC_1)". + */ +# define KEYCODE_STRING_NAMES_USER(...) \ + static const keycode_string_name_t keycode_string_names_user[] = {__VA_ARGS__}; \ + uint16_t keycode_string_names_size_user = \ + sizeof(keycode_string_names_user) / sizeof(keycode_string_name_t); \ + const keycode_string_name_t* keycode_string_names_data_user = \ + keycode_string_names_user + +/** Same as above, but defines keycode string names at the keyboard level. */ +# define KEYCODE_STRING_NAMES_KB(...) \ + static const keycode_string_name_t keycode_string_names_kb[] = {__VA_ARGS__}; \ + uint16_t keycode_string_names_size_kb = \ + sizeof(keycode_string_names_kb) / sizeof(keycode_string_name_t); \ + const keycode_string_name_t* keycode_string_names_data_kb = \ + keycode_string_names_kb + +/** Helper to define a keycode_string_name_t. */ +# define KEYCODE_STRING_NAME(kc) \ + { (kc), #kc } +// clang-format on + +extern const keycode_string_name_t* keycode_string_names_data_user; +extern uint16_t keycode_string_names_size_user; +extern const keycode_string_name_t* keycode_string_names_data_kb; +extern uint16_t keycode_string_names_size_kb; + +#else + +// When keycode_string is disabled, fall back to printing keycodes numerically +// as decimal values, using get_u16_str() from quantum.c. +# define get_keycode_string(kc) get_u16_str(kc, ' ') + +const char* get_u16_str(uint16_t curr_num, char curr_pad); + +# define KEYCODE_STRING_NAMES_USER(...) +# define KEYCODE_STRING_NAMES_KB(...) +# define KEYCODE_STRING_NAME(kc) + +#endif // KEYCODE_STRING_ENABLE |