diff --git a/docs/unit_testing.md b/docs/unit_testing.md index a404fc22473e..aec4ec8334de 100644 --- a/docs/unit_testing.md +++ b/docs/unit_testing.md @@ -75,18 +75,16 @@ Use the result of `get_keycode_string()` immediately. Subsequent invocations reu Many common QMK keycodes are recognized by `get_keycode_string()`, but not all. These include some common basic keycodes, layer switch keycodes, mod-taps, one-shot keycodes, tap dance keycodes, and Unicode keycodes. As a fallback, an unrecognized keycode is written as a hex number. -Optionally, `keycode_string_names_user` may be defined to add names for additional keycodes. For example, supposing keymap.c defines `MYMACRO1` and `MYMACRO2` as custom keycodes, the following adds their names: +Optionally, `KEYCODE_STRING_NAMES_USER` may be defined to add names for additional keycodes. For example, supposing keymap.c defines `MYMACRO1` and `MYMACRO2` as custom keycodes, the following adds their names: ```c -const keycode_string_name_t *keycode_string_names_user = -(keycode_string_name_t []){ +KEYCODE_STRING_NAMES_USER( KEYCODE_STRING_NAME(MYMACRO1), KEYCODE_STRING_NAME(MYMACRO2), - KEYCODE_STRING_NAMES_END // End of table sentinel. -}; +); ``` -Similarly, `keycode_string_names_kb` may be defined to add names at the keyboard level. +Similarly, `KEYCODE_STRING_NAMES_KB` may be defined to add names at the keyboard level. # Tracing Variables {#tracing-variables} diff --git a/quantum/keycode_string.c b/quantum/keycode_string.c index 5fb9c486f995..e305e3040810 100644 --- a/quantum/keycode_string.c +++ b/quantum/keycode_string.c @@ -124,12 +124,12 @@ static const uint16_t common_names[] PROGMEM = { }; // clang-format on -__attribute__((weak)) const keycode_string_name_t empty_table[] = {KEYCODE_STRING_NAMES_END}; - /** Users can override this to define names of additional keycodes. */ -__attribute__((weak)) const keycode_string_name_t* keycode_string_names_user = empty_table; +__attribute__((weak)) const keycode_string_name_t* keycode_string_names_data_user = NULL; +__attribute__((weak)) uint16_t keycode_string_names_size_user = 0; /** Keyboard vendors can override this to define names of additional keycodes. */ -__attribute__((weak)) const keycode_string_name_t* keycode_string_names_kb = empty_table; +__attribute__((weak)) const keycode_string_name_t* keycode_string_names_data_kb = NULL; +__attribute__((weak)) uint16_t keycode_string_names_size_kb = 0; /** Names of the 4 mods on each hand. */ static const char mod_names[] PROGMEM = "CTL\0SFT\0ALT\0GUI"; /** Internal buffer for holding a stringified keycode. */ @@ -141,7 +141,7 @@ static index_t buffer_len; static const char* search_common_names(uint16_t keycode) { static uint8_t buffer[8]; - for (int16_t offset = 0; offset < ARRAY_SIZE(common_names); offset += 4) { + for (int_fast16_t offset = 0; offset < ARRAY_SIZE(common_names); offset += 4) { if (keycode == pgm_read_word(common_names + offset)) { const uint16_t w0 = pgm_read_word(common_names + offset + 1); const uint16_t w1 = pgm_read_word(common_names + offset + 2); @@ -162,17 +162,18 @@ static const char* search_common_names(uint16_t keycode) { } /** - * @brief Finds the name of a keycode in `table` or returns NULL. - * - * The last entry of the table must be `KEYCODE_STRING_NAMES_END`. + * @brief Finds the name of a keycode in table or returns NULL. * - * @param table A table of keycode_string_name_t to be searched. + * @param data Pointer to table to be searched. + * @param size Numer of entries in the table. * @return Name string for the keycode, or NULL if not found. */ -static const char* search_table(const keycode_string_name_t* table, uint16_t keycode) { - for (; table->keycode; ++table) { - if (table->keycode == keycode) { - return table->name; +static const char* search_table(const keycode_string_name_t* data, uint16_t size, uint16_t keycode) { + if (data != NULL) { + for (uint16_t i = 0; i < size; ++i) { + if (data[i].keycode == keycode) { + return data[i].name; + } } } return NULL; @@ -263,12 +264,12 @@ static void append_unary_keycode(const char* name, const char* param) { static void append_keycode(uint16_t keycode) { // In case there is overlap among tables, search `keycode_string_names_user` // first so that it takes precedence. - const char* keycode_name = search_table(keycode_string_names_user, keycode); + const char* keycode_name = search_table(keycode_string_names_data_user, keycode_string_names_size_user, keycode); if (keycode_name) { append(keycode_name); return; } - keycode_name = search_table(keycode_string_names_kb, keycode); + keycode_name = search_table(keycode_string_names_data_kb, keycode_string_names_size_kb, keycode); if (keycode_name) { append(keycode_name); return; @@ -439,7 +440,7 @@ static void append_keycode(uint16_t keycode) { append_char(','); append_number(j, 10); append_char(')'); - } return dest; + } return; #endif #ifdef MOUSEKEY_ENABLE case MS_BTN1 ... MS_BTN8: // Mouse button keycode. diff --git a/quantum/keycode_string.h b/quantum/keycode_string.h index cda1b2749718..eea0fe6297eb 100644 --- a/quantum/keycode_string.h +++ b/quantum/keycode_string.h @@ -44,6 +44,8 @@ * * - Tap dance keycodes `TD(i)`. * + * - Swap hands keycodes `SH_T(kc)`, `SH_TOGG`, etc. + * * - Unicode `UC(codepoint)` and Unicode Map `UM(i)` and `UP(i,j)` keycodes. * * - Keyboard range keycodes `QK_KB_*`. @@ -70,37 +72,48 @@ typedef struct { const char* name; } keycode_string_name_t; +// clang-format off /** - * @brief Names for additional keycodes for `get_keycode_string()`. - * - * @note The table *must* end with `KEYCODE_STRING_NAMES_END`. + * @brief Defines names for additional keycodes for `get_keycode_string()`. * - * Define the `custom_keycode_names` table in your keymap.c to add names for + * 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: * - * const keycode_string_name_t* keycode_string_names_user = - * (keycode_string_name_t []){ - * KEYCODE_STRING_NAME(MYMACRO1), - * KEYCODE_STRING_NAME(MYMACRO2), - * KEYCODE_STRING_NAME(KC_EXLM), - * KEYCODE_STRING_NAMES_END // End of table sentinel. - * }; + * 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)". */ -extern const keycode_string_name_t* keycode_string_names_user; -/** Same as `keycode_string_names_user`, but for use at the keyboard level. */ -extern const keycode_string_name_t* keycode_string_names_kb; +# 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 } -/** Makes end-of-table sentinel for a table of keycode_string_name_t. */ -# define KEYCODE_STRING_NAMES_END \ - { 0, NULL } +// 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 @@ -108,6 +121,10 @@ extern const keycode_string_name_t* keycode_string_names_kb; // 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); +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 diff --git a/tests/keycode_string/test_keycode_string.cpp b/tests/keycode_string/test_keycode_string.cpp index 7cb78aabd5ce..c796f81a3633 100644 --- a/tests/keycode_string/test_keycode_string.cpp +++ b/tests/keycode_string/test_keycode_string.cpp @@ -24,16 +24,14 @@ enum { // clang-format off extern "C" { -const keycode_string_name_t* keycode_string_names_kb = (keycode_string_name_t []){ +KEYCODE_STRING_NAMES_KB( KEYCODE_STRING_NAME(MYMACRO1), - KEYCODE_STRING_NAMES_END // End of table sentinel. -}; +); -const keycode_string_name_t* keycode_string_names_user = (keycode_string_name_t []){ +KEYCODE_STRING_NAMES_USER( KEYCODE_STRING_NAME(MYMACRO2), KEYCODE_STRING_NAME(KC_EXLM), - KEYCODE_STRING_NAMES_END // End of table sentinel. -}; +); const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = { {{9, 0}, {8, 0}, {7, 0}, {6, 0}, {5, 0}, {4, 0}, {3, 0}, {2, 0}, {1, 0}, {0, 0}},