keyboard stuff
1// Copyright 2024-2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <stdint.h>
18
19#if KEYCODE_STRING_ENABLE
20
21/**
22 * @brief Formats a QMK keycode as a human-readable string.
23 *
24 * Given a keycode, like `KC_A`, this function returns a formatted string, like
25 * "KC_A". This is useful for debugging and diagnostics so that keys are more
26 * easily identified than they would be by raw numerical codes.
27 *
28 * @note The returned char* string should be used right away. The string memory
29 * is reused and will be overwritten by the next call to `keycode_string()`.
30 *
31 * Many common QMK keycodes are understood by this function, but not all.
32 * Recognized keycodes include:
33 *
34 * - Most basic keycodes, including letters `KC_A` - `KC_Z`, digits `KC_0` -
35 * `KC_9`, function keys `KC_F1` - `KC_F24`, and modifiers like `KC_LSFT`.
36 *
37 * - Modified basic keycodes, like `S(KC_1)` (Shift + 1 = !).
38 *
39 * - `MO`, `TO`, `TG`, `OSL`, `LM(layer,mod)`, `LT(layer,kc)` layer switches.
40 *
41 * - One-shot mod `OSM(mod)` keycodes.
42 *
43 * - Mod-tap `MT(mod, kc)` keycodes.
44 *
45 * - Tap dance keycodes `TD(i)`.
46 *
47 * - Swap hands keycodes `SH_T(kc)`, `SH_TOGG`, etc.
48 *
49 * - Joystick keycodes `JS_n`.
50 *
51 * - Programmable button keycodes `PB_n`.
52 *
53 * - Unicode `UC(codepoint)` and Unicode Map `UM(i)` and `UP(i,j)` keycodes.
54 *
55 * - Keyboard range keycodes `QK_KB_*`.
56 *
57 * - User range (SAFE_RANGE) keycodes `QK_USER_*`.
58 *
59 * Keycodes involving mods like `OSM`, `LM`, `MT` are fully supported only where
60 * a single mod is applied.
61 *
62 * Unrecognized keycodes are printed numerically as hex values like `0x1ABC`.
63 *
64 * Optionally, use `keycode_string_names_user` or `keycode_string_names_kb` to
65 * define names for additional keycodes or override how any of the above are
66 * formatted.
67 *
68 * @param keycode QMK keycode.
69 * @return Stringified keycode.
70 */
71const char* get_keycode_string(uint16_t keycode);
72
73/** Defines a human-readable name for a keycode. */
74typedef struct {
75 uint16_t keycode;
76 const char* name;
77} keycode_string_name_t;
78
79// clang-format off
80/**
81 * @brief Defines names for additional keycodes for `get_keycode_string()`.
82 *
83 * Define `KEYCODE_STRING_NAMES_USER` in your keymap.c to add names for
84 * additional keycodes to `keycode_string()`. This table may also be used to
85 * override how `keycode_string()` formats a keycode. For example, supposing
86 * keymap.c defines `MYMACRO1` and `MYMACRO2` as custom keycodes:
87 *
88 * KEYCODE_STRING_NAMES_USER(
89 * KEYCODE_STRING_NAME(MYMACRO1),
90 * KEYCODE_STRING_NAME(MYMACRO2),
91 * KEYCODE_STRING_NAME(KC_EXLM),
92 * );
93 *
94 * The above defines names for `MYMACRO1` and `MYMACRO2`, and overrides
95 * `KC_EXLM` to format as "KC_EXLM" instead of the default "S(KC_1)".
96 */
97# define KEYCODE_STRING_NAMES_USER(...) \
98 static const keycode_string_name_t keycode_string_names_user[] = {__VA_ARGS__}; \
99 uint16_t keycode_string_names_size_user = \
100 sizeof(keycode_string_names_user) / sizeof(keycode_string_name_t); \
101 const keycode_string_name_t* keycode_string_names_data_user = \
102 keycode_string_names_user
103
104/** Same as above, but defines keycode string names at the keyboard level. */
105# define KEYCODE_STRING_NAMES_KB(...) \
106 static const keycode_string_name_t keycode_string_names_kb[] = {__VA_ARGS__}; \
107 uint16_t keycode_string_names_size_kb = \
108 sizeof(keycode_string_names_kb) / sizeof(keycode_string_name_t); \
109 const keycode_string_name_t* keycode_string_names_data_kb = \
110 keycode_string_names_kb
111
112/** Helper to define a keycode_string_name_t. */
113# define KEYCODE_STRING_NAME(kc) \
114 { (kc), #kc }
115// clang-format on
116
117extern const keycode_string_name_t* keycode_string_names_data_user;
118extern uint16_t keycode_string_names_size_user;
119extern const keycode_string_name_t* keycode_string_names_data_kb;
120extern uint16_t keycode_string_names_size_kb;
121
122#else
123
124// When keycode_string is disabled, fall back to printing keycodes numerically
125// as decimal values, using get_u16_str() from quantum.c.
126# define get_keycode_string(kc) get_u16_str(kc, ' ')
127
128const char* get_u16_str(uint16_t curr_num, char curr_pad);
129
130# define KEYCODE_STRING_NAMES_USER(...)
131# define KEYCODE_STRING_NAMES_KB(...)
132# define KEYCODE_STRING_NAME(kc)
133
134#endif // KEYCODE_STRING_ENABLE