Skip to content

Commit

Permalink
Simplify custom names API by sigprof's suggestion.
Browse files Browse the repository at this point in the history
  • Loading branch information
getreuer committed Jan 27, 2025
1 parent 2f0ec78 commit 78849a0
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 46 deletions.
10 changes: 4 additions & 6 deletions docs/unit_testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down
33 changes: 17 additions & 16 deletions quantum/keycode_string.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
53 changes: 35 additions & 18 deletions quantum/keycode_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_*`.
Expand All @@ -70,44 +72,59 @@ 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

// 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);
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
10 changes: 4 additions & 6 deletions tests/keycode_string/test_keycode_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}},
Expand Down

0 comments on commit 78849a0

Please sign in to comment.