at master 23 kB view raw
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#include "keycode_string.h" 16 17#include <string.h> 18#include "bitwise.h" 19#include "keycode.h" 20#include "progmem.h" 21#include "quantum_keycodes.h" 22#include "util.h" 23 24typedef int_fast8_t index_t; 25 26// clang-format off 27/** Packs a 7-char keycode name, ignoring the third char, as 3 words. */ 28#define KEYCODE_NAME7(c0, c1, unused_c2, c3, c4, c5, c6) \ 29 ((uint16_t)c0) | (((uint16_t)c1) << 8), \ 30 ((uint16_t)c3) | (((uint16_t)c4) << 8), \ 31 ((uint16_t)c5) | (((uint16_t)c6) << 8) 32 33/** 34 * @brief Names of some common keycodes. 35 * 36 * Each (keycode, name) entry is stored flat in 8 bytes in PROGMEM. Names in 37 * this table must be at most 7 chars long and have an underscore '_' for the 38 * third char. This underscore is assumed and not actually stored. 39 * 40 * To save memory, feature-specific key entries are ifdef'd to include them only 41 * when their feature is enabled. 42 */ 43static const uint16_t common_names[] PROGMEM = { 44 KC_TRNS, KEYCODE_NAME7('K', 'C', '_', 'T', 'R', 'N', 'S'), 45 KC_ENT , KEYCODE_NAME7('K', 'C', '_', 'E', 'N', 'T', 0 ), 46 KC_ESC , KEYCODE_NAME7('K', 'C', '_', 'E', 'S', 'C', 0 ), 47 KC_BSPC, KEYCODE_NAME7('K', 'C', '_', 'B', 'S', 'P', 'C'), 48 KC_TAB , KEYCODE_NAME7('K', 'C', '_', 'T', 'A', 'B', 0 ), 49 KC_SPC , KEYCODE_NAME7('K', 'C', '_', 'S', 'P', 'C', 0 ), 50 KC_MINS, KEYCODE_NAME7('K', 'C', '_', 'M', 'I', 'N', 'S'), 51 KC_EQL , KEYCODE_NAME7('K', 'C', '_', 'E', 'Q', 'L', 0 ), 52 KC_LBRC, KEYCODE_NAME7('K', 'C', '_', 'L', 'B', 'R', 'C'), 53 KC_RBRC, KEYCODE_NAME7('K', 'C', '_', 'R', 'B', 'R', 'C'), 54 KC_BSLS, KEYCODE_NAME7('K', 'C', '_', 'B', 'S', 'L', 'S'), 55 KC_NUHS, KEYCODE_NAME7('K', 'C', '_', 'N', 'U', 'H', 'S'), 56 KC_SCLN, KEYCODE_NAME7('K', 'C', '_', 'S', 'C', 'L', 'N'), 57 KC_QUOT, KEYCODE_NAME7('K', 'C', '_', 'Q', 'U', 'O', 'T'), 58 KC_GRV , KEYCODE_NAME7('K', 'C', '_', 'G', 'R', 'V', 0 ), 59 KC_COMM, KEYCODE_NAME7('K', 'C', '_', 'C', 'O', 'M', 'M'), 60 KC_DOT , KEYCODE_NAME7('K', 'C', '_', 'D', 'O', 'T', 0 ), 61 KC_SLSH, KEYCODE_NAME7('K', 'C', '_', 'S', 'L', 'S', 'H'), 62 KC_CAPS, KEYCODE_NAME7('K', 'C', '_', 'C', 'A', 'P', 'S'), 63 KC_PSCR, KEYCODE_NAME7('K', 'C', '_', 'P', 'S', 'C', 'R'), 64 KC_PAUS, KEYCODE_NAME7('K', 'C', '_', 'P', 'A', 'U', 'S'), 65 KC_INS , KEYCODE_NAME7('K', 'C', '_', 'I', 'N', 'S', 0 ), 66 KC_HOME, KEYCODE_NAME7('K', 'C', '_', 'H', 'O', 'M', 'E'), 67 KC_PGUP, KEYCODE_NAME7('K', 'C', '_', 'P', 'G', 'U', 'P'), 68 KC_DEL , KEYCODE_NAME7('K', 'C', '_', 'D', 'E', 'L', 0 ), 69 KC_END , KEYCODE_NAME7('K', 'C', '_', 'E', 'N', 'D', 0 ), 70 KC_PGDN, KEYCODE_NAME7('K', 'C', '_', 'P', 'G', 'D', 'N'), 71 KC_RGHT, KEYCODE_NAME7('K', 'C', '_', 'R', 'G', 'H', 'T'), 72 KC_LEFT, KEYCODE_NAME7('K', 'C', '_', 'L', 'E', 'F', 'T'), 73 KC_DOWN, KEYCODE_NAME7('K', 'C', '_', 'D', 'O', 'W', 'N'), 74 KC_UP , KEYCODE_NAME7('K', 'C', '_', 'U', 'P', 0 , 0 ), 75 KC_NUBS, KEYCODE_NAME7('K', 'C', '_', 'N', 'U', 'B', 'S'), 76 KC_HYPR, KEYCODE_NAME7('K', 'C', '_', 'H', 'Y', 'P', 'R'), 77 KC_MEH , KEYCODE_NAME7('K', 'C', '_', 'M', 'E', 'H', 0 ), 78#ifdef EXTRAKEY_ENABLE 79 KC_WHOM, KEYCODE_NAME7('K', 'C', '_', 'W', 'H', 'O', 'M'), 80 KC_WBAK, KEYCODE_NAME7('K', 'C', '_', 'W', 'B', 'A', 'K'), 81 KC_WFWD, KEYCODE_NAME7('K', 'C', '_', 'W', 'F', 'W', 'D'), 82 KC_WSTP, KEYCODE_NAME7('K', 'C', '_', 'W', 'S', 'T', 'P'), 83 KC_WREF, KEYCODE_NAME7('K', 'C', '_', 'W', 'R', 'E', 'F'), 84 KC_MNXT, KEYCODE_NAME7('K', 'C', '_', 'M', 'N', 'X', 'T'), 85 KC_MPRV, KEYCODE_NAME7('K', 'C', '_', 'M', 'P', 'R', 'V'), 86 KC_MPLY, KEYCODE_NAME7('K', 'C', '_', 'M', 'P', 'L', 'Y'), 87 KC_MUTE, KEYCODE_NAME7('K', 'C', '_', 'M', 'U', 'T', 'E'), 88 KC_VOLU, KEYCODE_NAME7('K', 'C', '_', 'V', 'O', 'L', 'U'), 89 KC_VOLD, KEYCODE_NAME7('K', 'C', '_', 'V', 'O', 'L', 'D'), 90#endif // EXTRAKEY_ENABLE 91#ifdef MOUSEKEY_ENABLE 92 MS_LEFT, KEYCODE_NAME7('M', 'S', '_', 'L', 'E', 'F', 'T'), 93 MS_RGHT, KEYCODE_NAME7('M', 'S', '_', 'R', 'G', 'H', 'T'), 94 MS_UP , KEYCODE_NAME7('M', 'S', '_', 'U', 'P', 0 , 0 ), 95 MS_DOWN, KEYCODE_NAME7('M', 'S', '_', 'D', 'O', 'W', 'N'), 96 MS_WHLL, KEYCODE_NAME7('M', 'S', '_', 'W', 'H', 'L', 'L'), 97 MS_WHLR, KEYCODE_NAME7('M', 'S', '_', 'W', 'H', 'L', 'R'), 98 MS_WHLU, KEYCODE_NAME7('M', 'S', '_', 'W', 'H', 'L', 'U'), 99 MS_WHLD, KEYCODE_NAME7('M', 'S', '_', 'W', 'H', 'L', 'D'), 100#endif // MOUSEKEY_ENABLE 101#ifdef SWAP_HANDS_ENABLE 102 SH_ON , KEYCODE_NAME7('S', 'H', '_', 'O', 'N', 0 , 0 ), 103 SH_OFF , KEYCODE_NAME7('S', 'H', '_', 'O', 'F', 'F', 0 ), 104 SH_MON , KEYCODE_NAME7('S', 'H', '_', 'M', 'O', 'N', 0 ), 105 SH_MOFF, KEYCODE_NAME7('S', 'H', '_', 'M', 'O', 'F', 'F'), 106 SH_TOGG, KEYCODE_NAME7('S', 'H', '_', 'T', 'O', 'G', 'G'), 107 SH_TT , KEYCODE_NAME7('S', 'H', '_', 'T', 'T', 0 , 0 ), 108# if !defined(NO_ACTION_ONESHOT) 109 SH_OS , KEYCODE_NAME7('S', 'H', '_', 'O', 'S', 0 , 0 ), 110# endif // !defined(NO_ACTION_ONESHOT) 111#endif // SWAP_HANDS_ENABLE 112#ifdef LEADER_ENABLE 113 QK_LEAD, KEYCODE_NAME7('Q', 'K', '_', 'L', 'E', 'A', 'D'), 114#endif // LEADER_ENABLE 115#ifdef KEY_LOCK_ENABLE 116 QK_LOCK, KEYCODE_NAME7('Q', 'K', '_', 'L', 'O', 'C', 'K'), 117#endif // KEY_LOCK_ENABLE 118#ifdef TRI_LAYER_ENABLE 119 TL_LOWR, KEYCODE_NAME7('T', 'L', '_', 'L', 'O', 'W', 'R'), 120 TL_UPPR, KEYCODE_NAME7('T', 'L', '_', 'U', 'P', 'P', 'R'), 121#endif // TRI_LAYER_ENABLE 122#ifdef GRAVE_ESC_ENABLE 123 QK_GESC, KEYCODE_NAME7('Q', 'K', '_', 'G', 'E', 'S', 'C'), 124#endif // GRAVE_ESC_ENABLE 125#ifdef CAPS_WORD_ENABLE 126 CW_TOGG, KEYCODE_NAME7('C', 'W', '_', 'T', 'O', 'G', 'G'), 127#endif // CAPS_WORD_ENABLE 128#ifdef SECURE_ENABLE 129 SE_LOCK, KEYCODE_NAME7('S', 'E', '_', 'L', 'O', 'C', 'K'), 130 SE_UNLK, KEYCODE_NAME7('S', 'E', '_', 'U', 'N', 'L', 'K'), 131 SE_TOGG, KEYCODE_NAME7('S', 'E', '_', 'T', 'O', 'G', 'G'), 132 SE_REQ , KEYCODE_NAME7('S', 'E', '_', 'R', 'E', 'Q', 0 ), 133#endif // SECURE_ENABLE 134#ifdef LAYER_LOCK_ENABLE 135 QK_LLCK, KEYCODE_NAME7('Q', 'K', '_', 'L', 'L', 'C', 'K'), 136#endif // LAYER_LOCK_ENABLE 137 EE_CLR , KEYCODE_NAME7('E', 'E', '_', 'C', 'L', 'R', 0 ), 138 QK_BOOT, KEYCODE_NAME7('Q', 'K', '_', 'B', 'O', 'O', 'T'), 139 DB_TOGG, KEYCODE_NAME7('D', 'B', '_', 'T', 'O', 'G', 'G'), 140}; 141// clang-format on 142 143/** Users can override this to define names of additional keycodes. */ 144__attribute__((weak)) const keycode_string_name_t* keycode_string_names_data_user = NULL; 145__attribute__((weak)) uint16_t keycode_string_names_size_user = 0; 146/** Keyboard vendors can override this to define names of additional keycodes. */ 147__attribute__((weak)) const keycode_string_name_t* keycode_string_names_data_kb = NULL; 148__attribute__((weak)) uint16_t keycode_string_names_size_kb = 0; 149/** Names of the 4 mods on each hand. */ 150static const char mod_names[] PROGMEM = "CTL\0SFT\0ALT\0GUI"; 151/** Internal buffer for holding a stringified keycode. */ 152static char buffer[32]; 153#define BUFFER_MAX_LEN (sizeof(buffer) - 1) 154static index_t buffer_len; 155 156/** Finds the name of a keycode in `common_names` or returns NULL. */ 157static const char* search_common_names(uint16_t keycode) { 158 static uint8_t buffer[8]; 159 160 for (int_fast16_t offset = 0; offset < ARRAY_SIZE(common_names); offset += 4) { 161 if (keycode == pgm_read_word(common_names + offset)) { 162 const uint16_t w0 = pgm_read_word(common_names + offset + 1); 163 const uint16_t w1 = pgm_read_word(common_names + offset + 2); 164 const uint16_t w2 = pgm_read_word(common_names + offset + 3); 165 buffer[0] = (uint8_t)w0; 166 buffer[1] = (uint8_t)(w0 >> 8); 167 buffer[2] = '_'; 168 buffer[3] = (uint8_t)w1; 169 buffer[4] = (uint8_t)(w1 >> 8); 170 buffer[5] = (uint8_t)w2; 171 buffer[6] = (uint8_t)(w2 >> 8); 172 buffer[7] = 0; 173 return (const char*)buffer; 174 } 175 } 176 177 return NULL; 178} 179 180/** 181 * @brief Finds the name of a keycode in table or returns NULL. 182 * 183 * @param data Pointer to table to be searched. 184 * @param size Numer of entries in the table. 185 * @return Name string for the keycode, or NULL if not found. 186 */ 187static const char* search_table(const keycode_string_name_t* data, uint16_t size, uint16_t keycode) { 188 if (data != NULL) { 189 for (uint16_t i = 0; i < size; ++i) { 190 if (data[i].keycode == keycode) { 191 return data[i].name; 192 } 193 } 194 } 195 return NULL; 196} 197 198/** Formats `number` in `base`, either 10 or 16. */ 199static char* number_string(uint16_t number, int8_t base) { 200 static char result[7]; 201 result[sizeof(result) - 1] = '\0'; 202 index_t i = sizeof(result) - 1; 203 do { 204 const uint8_t digit = number % base; 205 number /= base; 206 result[--i] = (digit < 10) ? (char)(digit + UINT8_C('0')) : (char)(digit + (UINT8_C('A') - 10)); 207 } while (number > 0 && i > 0); 208 209 if (base == 16 && i >= 2) { 210 result[--i] = 'x'; 211 result[--i] = '0'; 212 } 213 return result + i; 214} 215 216/** Appends `str` to `buffer`, truncating if the result would overflow. */ 217static void append(const char* str) { 218 char* dest = buffer + buffer_len; 219 index_t i; 220 for (i = 0; buffer_len + i < BUFFER_MAX_LEN && str[i]; ++i) { 221 dest[i] = str[i]; 222 } 223 buffer_len += i; 224 buffer[buffer_len] = '\0'; 225} 226 227/** Same as append(), but where `str` is a PROGMEM string. */ 228static void append_P(const char* str) { 229 char* dest = buffer + buffer_len; 230 index_t i; 231 for (i = 0; buffer_len + i < BUFFER_MAX_LEN; ++i) { 232 const char c = pgm_read_byte(&str[i]); 233 if (c == '\0') { 234 break; 235 } 236 dest[i] = c; 237 } 238 buffer_len += i; 239 buffer[buffer_len] = '\0'; 240} 241 242/** Appends a single char to `buffer` if there is space. */ 243static void append_char(char c) { 244 if (buffer_len < BUFFER_MAX_LEN) { 245 buffer[buffer_len] = c; 246 buffer[++buffer_len] = '\0'; 247 } 248} 249 250/** Formats `number` in `base`, either 10 or 16, and appends it to `buffer`. */ 251static void append_number(uint16_t number, int8_t base) { 252 append(number_string(number, base)); 253} 254 255/** Stringifies 5-bit mods and appends it to `buffer`. */ 256static void append_5_bit_mods(uint8_t mods) { 257 const bool is_rhs = mods > 15; 258 const uint8_t csag = mods & 15; 259 if (csag != 0 && (csag & (csag - 1)) == 0) { // One mod is set. 260 append_P(PSTR("MOD_")); 261 append_char(is_rhs ? 'R' : 'L'); 262 append_P(&mod_names[4 * biton(csag)]); 263 } else { // Fallback: write the mod as a hex value. 264 append_number(mods, 16); 265 } 266} 267 268/** 269 * @brief Writes a keycode of the format `name` + "(" + `param` + ")". 270 * @note `name` is a PROGMEM string, `param` is not. 271 */ 272static void append_unary_keycode(const char* name, const char* param) { 273 append_P(name); 274 append_char('('); 275 append(param); 276 append_char(')'); 277} 278 279/** 280 * @brief Writes a keycode of the format `name` + `number`. 281 * @note `name` is a PROGMEM string. 282 */ 283static void append_numbered_keycode(const char* name, uint16_t number) { 284 append_P(name); 285 append_number(number, 10); 286} 287 288/** Stringifies `keycode` and appends it to `buffer`. */ 289static void append_keycode(uint16_t keycode) { 290 // In case there is overlap among tables, search `keycode_string_names_user` 291 // first so that it takes precedence. 292 const char* keycode_name = search_table(keycode_string_names_data_user, keycode_string_names_size_user, keycode); 293 if (keycode_name) { 294 append(keycode_name); 295 return; 296 } 297 keycode_name = search_table(keycode_string_names_data_kb, keycode_string_names_size_kb, keycode); 298 if (keycode_name) { 299 append(keycode_name); 300 return; 301 } 302 keycode_name = search_common_names(keycode); 303 if (keycode_name) { 304 append(keycode_name); 305 return; 306 } 307 308 if (keycode <= 255) { // Basic keycodes. 309 switch (keycode) { 310 // Modifiers KC_LSFT, KC_RCTL, etc. 311 case MODIFIER_KEYCODE_RANGE: { 312 const uint8_t i = keycode - KC_LCTL; 313 const bool is_rhs = i > 3; 314 append_P(PSTR("KC_")); 315 append_char(is_rhs ? 'R' : 'L'); 316 append_P(&mod_names[4 * (i & 3)]); 317 } 318 return; 319 320 // Letters A-Z. 321 case KC_A ... KC_Z: 322 append_P(PSTR("KC_")); 323 append_char((char)(keycode + (UINT8_C('A') - KC_A))); 324 return; 325 326 // Digits 0-9 (NOTE: Unlike the ASCII order, KC_0 comes *after* KC_9.) 327 case KC_1 ... KC_0: 328 append_numbered_keycode(PSTR("KC_"), (keycode - (KC_1 - 1)) % 10); 329 return; 330 331 // Keypad digits. 332 case KC_KP_1 ... KC_KP_0: 333 append_numbered_keycode(PSTR("KC_KP_"), (keycode - (KC_KP_1 - 1)) % 10); 334 return; 335 336 // Function keys. F1-F12 and F13-F24 are coded in separate ranges. 337 case KC_F1 ... KC_F12: 338 append_numbered_keycode(PSTR("KC_F"), keycode - (KC_F1 - 1)); 339 return; 340 341 case KC_F13 ... KC_F24: 342 append_numbered_keycode(PSTR("KC_F"), keycode - (KC_F13 - 13)); 343 return; 344 } 345 } 346 347 // clang-format off 348 switch (keycode) { 349 // A modified keycode, like S(KC_1) for Shift + 1 = !. This implementation 350 // only covers modified keycodes where one modifier is applied, e.g. a 351 // Ctrl + Shift + kc or Hyper + kc keycode is not formatted. 352 case QK_MODS ... QK_MODS_MAX: { 353 uint8_t mods = QK_MODS_GET_MODS(keycode); 354 const bool is_rhs = mods > 15; 355 mods &= 15; 356 if (mods != 0 && (mods & (mods - 1)) == 0) { // One mod is set. 357 const char* name = &mod_names[4 * biton(mods)]; 358 if (is_rhs) { 359 append_char('R'); 360 append_P(name); 361 } else { 362 append_char(pgm_read_byte(&name[0])); 363 } 364 append_char('('); 365 append_keycode(QK_MODS_GET_BASIC_KEYCODE(keycode)); 366 append_char(')'); 367 return; 368 } 369 } break; 370 371#if !defined(NO_ACTION_ONESHOT) 372 case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX: // One-shot mod OSM(mod) key. 373 append_P(PSTR("OSM(")); 374 append_5_bit_mods(QK_ONE_SHOT_MOD_GET_MODS(keycode)); 375 append_char(')'); 376 return; 377#endif // !defined(NO_ACTION_ONESHOT) 378 379 // Various layer switch keys. 380 case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: // Layer-tap LT(layer,kc) key. 381 append_P(PSTR("LT(")); 382 append_number(QK_LAYER_TAP_GET_LAYER(keycode), 10); 383 append_char(','); 384 append_keycode(QK_LAYER_TAP_GET_TAP_KEYCODE(keycode)); 385 append_char(')'); 386 return; 387 388 case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: // LM(layer,mod) key. 389 append_P(PSTR("LM(")); 390 append_number(QK_LAYER_MOD_GET_LAYER(keycode), 10); 391 append_char(','); 392 append_5_bit_mods(QK_LAYER_MOD_GET_MODS(keycode)); 393 append_char(')'); 394 return; 395 396 case QK_TO ... QK_TO_MAX: // TO(layer) key. 397 append_unary_keycode(PSTR("TO"), number_string(QK_TO_GET_LAYER(keycode), 10)); 398 return; 399 400 case QK_MOMENTARY ... QK_MOMENTARY_MAX: // MO(layer) key. 401 append_unary_keycode(PSTR("MO"), number_string(QK_MOMENTARY_GET_LAYER(keycode), 10)); 402 return; 403 404 case QK_DEF_LAYER ... QK_DEF_LAYER_MAX: // DF(layer) key. 405 append_unary_keycode(PSTR("DF"), number_string(QK_DEF_LAYER_GET_LAYER(keycode), 10)); 406 return; 407 408 case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: // TG(layer) key. 409 append_unary_keycode(PSTR("TG"), number_string(QK_TOGGLE_LAYER_GET_LAYER(keycode), 10)); 410 return; 411 412#if !defined(NO_ACTION_ONESHOT) 413 case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: // OSL(layer) key. 414 append_unary_keycode(PSTR("OSL"), number_string(QK_ONE_SHOT_LAYER_GET_LAYER(keycode), 10)); 415 return; 416#endif // !defined(NO_ACTION_ONESHOT) 417 418 case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: // TT(layer) key. 419 append_unary_keycode(PSTR("TT"), number_string(QK_LAYER_TAP_TOGGLE_GET_LAYER(keycode), 10)); 420 return; 421 422 case QK_PERSISTENT_DEF_LAYER ... QK_PERSISTENT_DEF_LAYER_MAX: // PDF(layer) key. 423 append_unary_keycode(PSTR("PDF"), number_string(QK_PERSISTENT_DEF_LAYER_GET_LAYER(keycode), 10)); 424 return; 425 426 // Mod-tap MT(mod,kc) key. This implementation formats the MT keys where 427 // one modifier is applied. For MT keys with multiple modifiers, the mod 428 // arg is written numerically as a hex code. 429 case QK_MOD_TAP ... QK_MOD_TAP_MAX: { 430 uint8_t mods = QK_MOD_TAP_GET_MODS(keycode); 431 const bool is_rhs = mods > 15; 432 const uint8_t csag = mods & 15; 433 if (csag != 0 && (csag & (csag - 1)) == 0) { // One mod is set. 434 append_char(is_rhs ? 'R' : 'L'); 435 append_P(&mod_names[4 * biton(csag)]); 436 append_P(PSTR("_T(")); 437 } else if (mods == MOD_HYPR) { 438 append_P(PSTR("HYPR_T(")); 439 } else if (mods == MOD_MEH) { 440 append_P(PSTR("MEH_T(")); 441 } else { 442 append_P(PSTR("MT(")); 443 append_number(mods, 16); 444 append_char(','); 445 } 446 append_keycode(QK_MOD_TAP_GET_TAP_KEYCODE(keycode)); 447 append_char(')'); 448 } return; 449 450 case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: // Tap dance TD(i) key. 451 append_unary_keycode(PSTR("TD"), number_string(QK_TAP_DANCE_GET_INDEX(keycode), 10)); 452 return; 453 454#ifdef UNICODE_ENABLE 455 case QK_UNICODE ... QK_UNICODE_MAX: // Unicode UC(codepoint) key. 456 append_unary_keycode(PSTR("UC"), number_string(QK_UNICODE_GET_CODE_POINT(keycode), 16)); 457 return; 458#elif defined(UNICODEMAP_ENABLE) 459 case QK_UNICODEMAP ... QK_UNICODEMAP_MAX: // Unicode Map UM(i) key. 460 append_unary_keycode(PSTR("UM"), number_string(QK_UNICODEMAP_GET_INDEX(keycode), 10)); 461 return; 462 463 case QK_UNICODEMAP_PAIR ... QK_UNICODEMAP_PAIR_MAX: { // UP(i,j) key. 464 const uint8_t i = QK_UNICODEMAP_PAIR_GET_UNSHIFTED_INDEX(keycode); 465 const uint8_t j = QK_UNICODEMAP_PAIR_GET_SHIFTED_INDEX(keycode); 466 append_P(PSTR("UP(")); 467 append_number(i, 10); 468 append_char(','); 469 append_number(j, 10); 470 append_char(')'); 471 } return; 472#endif 473#ifdef MOUSEKEY_ENABLE 474 case MS_BTN1 ... MS_BTN8: // Mouse button keycode. 475 append_numbered_keycode(PSTR("MS_BTN"), keycode - (MS_BTN1 - 1)); 476 return; 477#endif // MOUSEKEY_ENABLE 478#ifdef SWAP_HANDS_ENABLE 479 case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX: // Swap Hands SH_T(kc) key. 480 if (!IS_SWAP_HANDS_KEYCODE(keycode)) { 481 append_P(PSTR("SH_T(")); 482 append_keycode(QK_SWAP_HANDS_GET_TAP_KEYCODE(keycode)); 483 append_char(')'); 484 return; 485 } 486 break; 487#endif // SWAP_HANDS_ENABLE 488#ifdef JOYSTICK_ENABLE 489 case JOYSTICK_KEYCODE_RANGE: // Joystick JS_ key. 490 append_numbered_keycode(PSTR("JS_"), keycode - JS_0); 491 return; 492#endif // JOYSTICK_ENABLE 493#ifdef PROGRAMMABLE_BUTTON_ENABLE 494 case PROGRAMMABLE_BUTTON_KEYCODE_RANGE: // Programmable button PB_ key. 495 append_numbered_keycode(PSTR("PB_"), keycode - (PB_1 - 1)); 496 return; 497#endif // PROGRAMMABLE_BUTTON_ENABLE 498 499 case MACRO_KEYCODE_RANGE: // Macro range MC_ keycode. 500 append_numbered_keycode(PSTR("MC_"), keycode - MC_0); 501 return; 502 503 case KB_KEYCODE_RANGE: // Keyboard range keycode. 504 append_numbered_keycode(PSTR("QK_KB_"), keycode - QK_KB_0); 505 return; 506 507 case USER_KEYCODE_RANGE: // User range keycode. 508 append_numbered_keycode(PSTR("QK_USER_"), keycode - QK_USER_0); 509 return; 510 511 // It would take a nontrivial amount of string data to cover some 512 // feature-specific keycodes, such as those for MIDI and lighting. As a 513 // fallback while still providing some information, we stringify 514 // remaining keys in known code ranges as "QK_<feature>+<number>". 515#ifdef MAGIC_ENABLE 516 case MAGIC_KEYCODE_RANGE: 517 append_numbered_keycode(PSTR("QK_MAGIC+"), keycode - QK_MAGIC); 518 return; 519#endif // MAGIC_ENABLE 520#ifdef MIDI_ENABLE 521 case MIDI_KEYCODE_RANGE: 522 append_numbered_keycode(PSTR("QK_MIDI+"), keycode - QK_MIDI); 523 return; 524#endif // MIDI_ENABLE 525#ifdef SEQUENCER_ENABLE 526 case SEQUENCER_KEYCODE_RANGE: 527 append_numbered_keycode(PSTR("QK_SEQUENCER+"), keycode - QK_SEQUENCER); 528 return; 529#endif // SEQUENCER_ENABLE 530#ifdef AUDIO_ENABLE 531 case AUDIO_KEYCODE_RANGE: 532 append_numbered_keycode(PSTR("QK_AUDIO+"), keycode - QK_AUDIO); 533 return; 534#endif // AUDIO_ENABLE 535#if defined(BACKLIGHT_ENABLE) || defined(LED_MATRIX_ENABLE) || defined(RGBLIGHT_ENABLED) || defined(RGB_MATRIX_ENABLE) // Lighting-related features. 536 case QK_LIGHTING ... QK_LIGHTING_MAX: 537 append_numbered_keycode(PSTR("QK_LIGHTING+"), keycode - QK_LIGHTING); 538 return; 539#endif // defined(BACKLIGHT_ENABLE) || defined(LED_MATRIX_ENABLE) || defined(RGBLIGHT_ENABLED) || defined(RGB_MATRIX_ENABLE) 540#ifdef STENO_ENABLE 541 case STENO_KEYCODE_RANGE: 542 append_numbered_keycode(PSTR("QK_STENO+"), keycode - QK_STENO); 543 return; 544#endif // AUDIO_ENABLE 545#ifdef BLUETOOTH_ENABLE 546 case CONNECTION_KEYCODE_RANGE: 547 append_numbered_keycode(PSTR("QK_CONNECTION+"), keycode - QK_CONNECTION); 548 return; 549#endif // BLUETOOTH_ENABLE 550 case QUANTUM_KEYCODE_RANGE: 551 append_numbered_keycode(PSTR("QK_QUANTUM+"), keycode - QK_QUANTUM); 552 return; 553 } 554 // clang-format on 555 556 append_number(keycode, 16); // Fallback: write keycode as hex value. 557} 558 559const char* get_keycode_string(uint16_t keycode) { 560 buffer_len = 0; 561 buffer[0] = '\0'; 562 append_keycode(keycode); 563 return buffer; 564}