[Test] Reset timer for every unit test and provide timestamps for log messages (#17028)

master
Stefan Kerkmann 2022-12-14 16:31:08 +01:00 committed by GitHub
parent e2ab98f960
commit 962e4c0e18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1011 additions and 41 deletions

View File

@ -24,6 +24,8 @@ $(TEST)_SRC := \
tests/test_common/matrix.c \ tests/test_common/matrix.c \
tests/test_common/test_driver.cpp \ tests/test_common/test_driver.cpp \
tests/test_common/keyboard_report_util.cpp \ tests/test_common/keyboard_report_util.cpp \
tests/test_common/keycode_util.cpp \
tests/test_common/keycode_table.cpp \
tests/test_common/test_fixture.cpp \ tests/test_common/test_fixture.cpp \
tests/test_common/test_keymap_key.cpp \ tests/test_common/test_keymap_key.cpp \
tests/test_common/test_logger.cpp \ tests/test_common/test_logger.cpp \

View File

@ -57,6 +57,7 @@ subcommands = [
'qmk.cli.generate.keyboard_c', 'qmk.cli.generate.keyboard_c',
'qmk.cli.generate.keyboard_h', 'qmk.cli.generate.keyboard_h',
'qmk.cli.generate.keycodes', 'qmk.cli.generate.keycodes',
'qmk.cli.generate.keycodes_tests',
'qmk.cli.generate.rgb_breathe_table', 'qmk.cli.generate.rgb_breathe_table',
'qmk.cli.generate.rules_mk', 'qmk.cli.generate.rules_mk',
'qmk.cli.generate.version_h', 'qmk.cli.generate.version_h',

View File

@ -0,0 +1,39 @@
"""Used by the make system to generate a keycode lookup table from keycodes_{version}.json
"""
from milc import cli
from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
from qmk.commands import dump_lines
from qmk.path import normpath
from qmk.keycodes import load_spec
def _generate_defines(lines, keycodes):
lines.append('')
lines.append('std::map<uint16_t, std::string> KEYCODE_ID_TABLE = {')
for key, value in keycodes["keycodes"].items():
lines.append(f' {{{value.get("key")}, "{value.get("key")}"}},')
lines.append('};')
@cli.argument('-v', '--version', arg_only=True, required=True, help='Version of keycodes to generate.')
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.subcommand('Used by the make system to generate a keycode lookup table from keycodes_{version}.json', hidden=True)
def generate_keycodes_tests(cli):
"""Generates a keycode to identifier lookup table for unit test output.
"""
# Build the keycodes.h file.
keycodes_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '// clang-format off']
keycodes_h_lines.append('extern "C" {\n#include <keycode.h>\n}')
keycodes_h_lines.append('#include <map>')
keycodes_h_lines.append('#include <string>')
keycodes_h_lines.append('#include <cstdint>')
keycodes = load_spec(cli.args.version)
_generate_defines(keycodes_h_lines, keycodes)
# Show the results
dump_lines(cli.args.output, keycodes_h_lines, cli.args.quiet)

View File

@ -15,8 +15,9 @@
*/ */
#include "timer.h" #include "timer.h"
#include <stdatomic.h>
static uint32_t current_time = 0; static atomic_uint_least32_t current_time = 0;
void timer_init(void) { void timer_init(void) {
current_time = 0; current_time = 0;

View File

@ -143,8 +143,8 @@ void action_tapping_process(keyrecord_t record) {
# define TAP_GET_RETRO_TAPPING true # define TAP_GET_RETRO_TAPPING true
# endif # endif
# define MAYBE_RETRO_SHIFTING(ev) (TAP_GET_RETRO_TAPPING && (RETRO_SHIFT + 0) != 0 && TIMER_DIFF_16((ev).time, tapping_key.event.time) < (RETRO_SHIFT + 0)) # define MAYBE_RETRO_SHIFTING(ev) (TAP_GET_RETRO_TAPPING && (RETRO_SHIFT + 0) != 0 && TIMER_DIFF_16((ev).time, tapping_key.event.time) < (RETRO_SHIFT + 0))
# define TAP_IS_LT IS_LT(tapping_keycode) # define TAP_IS_LT IS_QK_LAYER_TAP(tapping_keycode)
# define TAP_IS_MT IS_MT(tapping_keycode) # define TAP_IS_MT IS_QK_MOD_TAP(tapping_keycode)
# define TAP_IS_RETRO IS_RETRO(tapping_keycode) # define TAP_IS_RETRO IS_RETRO(tapping_keycode)
# else # else
# define TAP_GET_RETRO_TAPPING false # define TAP_GET_RETRO_TAPPING false

View File

@ -405,7 +405,7 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
# elif defined(IGNORE_MOD_TAP_INTERRUPT) # elif defined(IGNORE_MOD_TAP_INTERRUPT)
const bool is_hold_on_interrupt = false; const bool is_hold_on_interrupt = false;
# else # else
const bool is_hold_on_interrupt = IS_MT(keycode); const bool is_hold_on_interrupt = IS_QK_MOD_TAP(keycode);
# endif # endif
# endif # endif
if (IS_RETRO(keycode) if (IS_RETRO(keycode)

View File

@ -22,9 +22,8 @@
# define AUTO_SHIFT_TIMEOUT 175 # define AUTO_SHIFT_TIMEOUT 175
#endif #endif
#define IS_LT(kc) ((kc) >= QK_LAYER_TAP && (kc) <= QK_LAYER_TAP_MAX) #define IS_RETRO(kc) (IS_QK_MOD_TAP(kc) || IS_QK_LAYER_TAP(kc))
#define IS_MT(kc) ((kc) >= QK_MOD_TAP && (kc) <= QK_MOD_TAP_MAX)
#define IS_RETRO(kc) (IS_MT(kc) || IS_LT(kc))
#define DO_GET_AUTOSHIFT_TIMEOUT(keycode, record, ...) record #define DO_GET_AUTOSHIFT_TIMEOUT(keycode, record, ...) record
// clang-format off // clang-format off
#define AUTO_SHIFT_ALPHA KC_A ... KC_Z #define AUTO_SHIFT_ALPHA KC_A ... KC_Z

View File

@ -0,0 +1,52 @@
// Copyright 2022 Stefan Kerkmann
// SPDX-License-Identifier: GPL-2.0-or-later
#include "test_common.hpp"
class KeycodeToIdentifierSuite : public ::testing::TestWithParam<std::pair<std::uint16_t, std::string>> {};
TEST_P(KeycodeToIdentifierSuite, ConversionTests) {
ASSERT_EQ(get_keycode_identifier_or_default(GetParam().first), GetParam().second);
}
INSTANTIATE_TEST_CASE_P(ConversionTestsP, KeycodeToIdentifierSuite,
// clang-format off
::testing::Values(
// Goto layer
std::make_pair(TO(0), "TO(0)"),
std::make_pair(TO(0x1F), "TO(31)"),
// Momentary switch layer
std::make_pair(MO(0), "MO(0)"),
std::make_pair(MO(0x1F), "MO(31)"),
// Set default layer
std::make_pair(DF(0), "DF(0)"),
std::make_pair(DF(0x1F), "DF(31)"),
// Toggle layer
std::make_pair(TG(0), "TG(0)"),
std::make_pair(TG(0x1F), "TG(31)"),
// One-shot layer
std::make_pair(OSL(0), "OSL(0)"),
std::make_pair(OSL(0x1F), "OSL(31)"),
// One-shot mod
std::make_pair(OSM(MOD_LSFT), "OSM(MOD_LSFT)"),
std::make_pair(OSM(MOD_LSFT | MOD_LCTL), "OSM(MOD_LCTL | MOD_LSFT)"),
// Layer Mod
std::make_pair(LM(0, MOD_LSFT), "LM(0, MOD_LSFT)"),
std::make_pair(LM(0xF, MOD_LSFT), "LM(15, MOD_LSFT)"),
std::make_pair(LM(0xF, MOD_LSFT | MOD_LCTL), "LM(15, MOD_LCTL | MOD_LSFT)"),
// Layer tap toggle
std::make_pair(TT(0), "TT(0)"),
std::make_pair(TT(0x1F), "TT(31)"),
// Layer tap
std::make_pair(LT(0, KC_A), "LT(0, KC_A)"),
std::make_pair(LT(0xF, KC_SPACE), "LT(15, KC_SPACE)"),
std::make_pair(LT(1, KC_SPC), "LT(1, KC_SPACE)"),
// Mod tap
std::make_pair(MT(MOD_LCTL, KC_A), "MT(MOD_LCTL, KC_A)"),
std::make_pair(MT(MOD_LCTL | MOD_LSFT, KC_A), "MT(MOD_LCTL | MOD_LSFT, KC_A)"),
std::make_pair(ALT_T(KC_TAB), "MT(MOD_LALT, KC_TAB)"),
// Mods
std::make_pair(LCTL(KC_A), "QK_MODS(KC_A, QK_LCTL)"),
std::make_pair(HYPR(KC_SPACE), "QK_MODS(KC_SPACE, QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI)")
));
// clang-format on

View File

@ -505,7 +505,8 @@ class CapsWordDoubleTapShift : public ::testing::WithParamInterface<CapsWordDoub
TEST_P(CapsWordDoubleTapShift, Activation) { TEST_P(CapsWordDoubleTapShift, Activation) {
TestDriver driver; TestDriver driver;
KeymapKey left_shift(0, 0, 0, GetParam().left_shift_keycode); KeymapKey left_shift(0, 0, 0, GetParam().left_shift_keycode);
set_keymap({left_shift}); KeymapKey esc(0, 0, 1, KC_ESCAPE);
set_keymap({left_shift, esc});
// clang-format off // clang-format off
EXPECT_CALL(driver, send_keyboard_mock(AnyOf( EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
@ -524,6 +525,12 @@ TEST_P(CapsWordDoubleTapShift, Activation) {
EXPECT_EQ(is_caps_word_on(), true); EXPECT_EQ(is_caps_word_on(), true);
testing::Mock::VerifyAndClearExpectations(&driver); testing::Mock::VerifyAndClearExpectations(&driver);
// We have to manually reset the internal state of the caps word state
// machine at this point. This due to imperfect test isolation which can't
// reset the caps word double shift timer on test case setup.
idle_for(CAPS_WORD_IDLE_TIMEOUT);
tap_key(esc);
} }
// Double tap doesn't count if another key is pressed between the taps. // Double tap doesn't count if another key is pressed between the taps.

View File

@ -15,11 +15,16 @@
*/ */
#include "keyboard_report_util.hpp" #include "keyboard_report_util.hpp"
#include <cstdint>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
using namespace testing; using namespace testing;
extern std::map<uint16_t, std::string> KEYCODE_ID_TABLE;
namespace { namespace {
std::vector<uint8_t> get_keys(const report_keyboard_t& report) { std::vector<uint8_t> get_keys(const report_keyboard_t& report) {
std::vector<uint8_t> result; std::vector<uint8_t> result;
#if defined(NKRO_ENABLE) #if defined(NKRO_ENABLE)
@ -36,6 +41,19 @@ std::vector<uint8_t> get_keys(const report_keyboard_t& report) {
std::sort(result.begin(), result.end()); std::sort(result.begin(), result.end());
return result; return result;
} }
std::vector<uint8_t> get_mods(const report_keyboard_t& report) {
std::vector<uint8_t> result;
for (size_t i = 0; i < 8; i++) {
if (report.mods & (1 << i)) {
uint8_t code = KC_LEFT_CTRL + i;
result.emplace_back(code);
}
}
std::sort(result.begin(), result.end());
return result;
}
} // namespace } // namespace
bool operator==(const report_keyboard_t& lhs, const report_keyboard_t& rhs) { bool operator==(const report_keyboard_t& lhs, const report_keyboard_t& rhs) {
@ -44,21 +62,36 @@ bool operator==(const report_keyboard_t& lhs, const report_keyboard_t& rhs) {
return lhs.mods == rhs.mods && lhskeys == rhskeys; return lhs.mods == rhs.mods && lhskeys == rhskeys;
} }
std::ostream& operator<<(std::ostream& stream, const report_keyboard_t& report) { std::ostream& operator<<(std::ostream& os, const report_keyboard_t& report) {
auto keys = get_keys(report); auto keys = get_keys(report);
auto mods = get_mods(report);
// TODO: This should probably print friendly names for the keys os << std::setw(10) << std::left << "report: ";
stream << "Keyboard Report: Mods (" << (uint32_t)report.mods << ") Keys (";
if (!keys.size() && !mods.size()) {
return os << "empty" << std::endl;
}
os << "(";
for (auto key = keys.cbegin(); key != keys.cend();) { for (auto key = keys.cbegin(); key != keys.cend();) {
stream << +(*key); os << KEYCODE_ID_TABLE.at(*key);
key++; key++;
if (key != keys.cend()) { if (key != keys.cend()) {
stream << ","; os << ", ";
} }
} }
return stream << ")" << std::endl; os << ") [";
for (auto mod = mods.cbegin(); mod != mods.cend();) {
os << KEYCODE_ID_TABLE.at(*mod);
mod++;
if (mod != mods.cend()) {
os << ", ";
}
}
return os << "]" << std::endl;
} }
KeyboardReportMatcher::KeyboardReportMatcher(const std::vector<uint8_t>& keys) { KeyboardReportMatcher::KeyboardReportMatcher(const std::vector<uint8_t>& keys) {

View File

@ -0,0 +1,663 @@
// Copyright 2022 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
88888888888 888 d8b .d888 d8b 888 d8b
888 888 Y8P d88P" Y8P 888 Y8P
888 888 888 888
888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b
888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K
888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b.
888 888 888 888 X88 888 888 888 Y8b. 888 X88
888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P'
888 888
888 888
888 888
.d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888
d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888
888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888
Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888
"Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888
888
Y8b d88P
"Y88P"
*******************************************************************************/
// clang-format off
extern "C" {
#include <keycode.h>
}
#include <map>
#include <string>
#include <cstdint>
std::map<uint16_t, std::string> KEYCODE_ID_TABLE = {
{KC_NO, "KC_NO"},
{KC_TRANSPARENT, "KC_TRANSPARENT"},
{KC_A, "KC_A"},
{KC_B, "KC_B"},
{KC_C, "KC_C"},
{KC_D, "KC_D"},
{KC_E, "KC_E"},
{KC_F, "KC_F"},
{KC_G, "KC_G"},
{KC_H, "KC_H"},
{KC_I, "KC_I"},
{KC_J, "KC_J"},
{KC_K, "KC_K"},
{KC_L, "KC_L"},
{KC_M, "KC_M"},
{KC_N, "KC_N"},
{KC_O, "KC_O"},
{KC_P, "KC_P"},
{KC_Q, "KC_Q"},
{KC_R, "KC_R"},
{KC_S, "KC_S"},
{KC_T, "KC_T"},
{KC_U, "KC_U"},
{KC_V, "KC_V"},
{KC_W, "KC_W"},
{KC_X, "KC_X"},
{KC_Y, "KC_Y"},
{KC_Z, "KC_Z"},
{KC_1, "KC_1"},
{KC_2, "KC_2"},
{KC_3, "KC_3"},
{KC_4, "KC_4"},
{KC_5, "KC_5"},
{KC_6, "KC_6"},
{KC_7, "KC_7"},
{KC_8, "KC_8"},
{KC_9, "KC_9"},
{KC_0, "KC_0"},
{KC_ENTER, "KC_ENTER"},
{KC_ESCAPE, "KC_ESCAPE"},
{KC_BACKSPACE, "KC_BACKSPACE"},
{KC_TAB, "KC_TAB"},
{KC_SPACE, "KC_SPACE"},
{KC_MINUS, "KC_MINUS"},
{KC_EQUAL, "KC_EQUAL"},
{KC_LEFT_BRACKET, "KC_LEFT_BRACKET"},
{KC_RIGHT_BRACKET, "KC_RIGHT_BRACKET"},
{KC_BACKSLASH, "KC_BACKSLASH"},
{KC_NONUS_HASH, "KC_NONUS_HASH"},
{KC_SEMICOLON, "KC_SEMICOLON"},
{KC_QUOTE, "KC_QUOTE"},
{KC_GRAVE, "KC_GRAVE"},
{KC_COMMA, "KC_COMMA"},
{KC_DOT, "KC_DOT"},
{KC_SLASH, "KC_SLASH"},
{KC_CAPS_LOCK, "KC_CAPS_LOCK"},
{KC_F1, "KC_F1"},
{KC_F2, "KC_F2"},
{KC_F3, "KC_F3"},
{KC_F4, "KC_F4"},
{KC_F5, "KC_F5"},
{KC_F6, "KC_F6"},
{KC_F7, "KC_F7"},
{KC_F8, "KC_F8"},
{KC_F9, "KC_F9"},
{KC_F10, "KC_F10"},
{KC_F11, "KC_F11"},
{KC_F12, "KC_F12"},
{KC_PRINT_SCREEN, "KC_PRINT_SCREEN"},
{KC_SCROLL_LOCK, "KC_SCROLL_LOCK"},
{KC_PAUSE, "KC_PAUSE"},
{KC_INSERT, "KC_INSERT"},
{KC_HOME, "KC_HOME"},
{KC_PAGE_UP, "KC_PAGE_UP"},
{KC_DELETE, "KC_DELETE"},
{KC_END, "KC_END"},
{KC_PAGE_DOWN, "KC_PAGE_DOWN"},
{KC_RIGHT, "KC_RIGHT"},
{KC_LEFT, "KC_LEFT"},
{KC_DOWN, "KC_DOWN"},
{KC_UP, "KC_UP"},
{KC_NUM_LOCK, "KC_NUM_LOCK"},
{KC_KP_SLASH, "KC_KP_SLASH"},
{KC_KP_ASTERISK, "KC_KP_ASTERISK"},
{KC_KP_MINUS, "KC_KP_MINUS"},
{KC_KP_PLUS, "KC_KP_PLUS"},
{KC_KP_ENTER, "KC_KP_ENTER"},
{KC_KP_1, "KC_KP_1"},
{KC_KP_2, "KC_KP_2"},
{KC_KP_3, "KC_KP_3"},
{KC_KP_4, "KC_KP_4"},
{KC_KP_5, "KC_KP_5"},
{KC_KP_6, "KC_KP_6"},
{KC_KP_7, "KC_KP_7"},
{KC_KP_8, "KC_KP_8"},
{KC_KP_9, "KC_KP_9"},
{KC_KP_0, "KC_KP_0"},
{KC_KP_DOT, "KC_KP_DOT"},
{KC_NONUS_BACKSLASH, "KC_NONUS_BACKSLASH"},
{KC_APPLICATION, "KC_APPLICATION"},
{KC_KB_POWER, "KC_KB_POWER"},
{KC_KP_EQUAL, "KC_KP_EQUAL"},
{KC_F13, "KC_F13"},
{KC_F14, "KC_F14"},
{KC_F15, "KC_F15"},
{KC_F16, "KC_F16"},
{KC_F17, "KC_F17"},
{KC_F18, "KC_F18"},
{KC_F19, "KC_F19"},
{KC_F20, "KC_F20"},
{KC_F21, "KC_F21"},
{KC_F22, "KC_F22"},
{KC_F23, "KC_F23"},
{KC_F24, "KC_F24"},
{KC_EXECUTE, "KC_EXECUTE"},
{KC_HELP, "KC_HELP"},
{KC_MENU, "KC_MENU"},
{KC_SELECT, "KC_SELECT"},
{KC_STOP, "KC_STOP"},
{KC_AGAIN, "KC_AGAIN"},
{KC_UNDO, "KC_UNDO"},
{KC_CUT, "KC_CUT"},
{KC_COPY, "KC_COPY"},
{KC_PASTE, "KC_PASTE"},
{KC_FIND, "KC_FIND"},
{KC_KB_MUTE, "KC_KB_MUTE"},
{KC_KB_VOLUME_UP, "KC_KB_VOLUME_UP"},
{KC_KB_VOLUME_DOWN, "KC_KB_VOLUME_DOWN"},
{KC_LOCKING_CAPS_LOCK, "KC_LOCKING_CAPS_LOCK"},
{KC_LOCKING_NUM_LOCK, "KC_LOCKING_NUM_LOCK"},
{KC_LOCKING_SCROLL_LOCK, "KC_LOCKING_SCROLL_LOCK"},
{KC_KP_COMMA, "KC_KP_COMMA"},
{KC_KP_EQUAL_AS400, "KC_KP_EQUAL_AS400"},
{KC_INTERNATIONAL_1, "KC_INTERNATIONAL_1"},
{KC_INTERNATIONAL_2, "KC_INTERNATIONAL_2"},
{KC_INTERNATIONAL_3, "KC_INTERNATIONAL_3"},
{KC_INTERNATIONAL_4, "KC_INTERNATIONAL_4"},
{KC_INTERNATIONAL_5, "KC_INTERNATIONAL_5"},
{KC_INTERNATIONAL_6, "KC_INTERNATIONAL_6"},
{KC_INTERNATIONAL_7, "KC_INTERNATIONAL_7"},
{KC_INTERNATIONAL_8, "KC_INTERNATIONAL_8"},
{KC_INTERNATIONAL_9, "KC_INTERNATIONAL_9"},
{KC_LANGUAGE_1, "KC_LANGUAGE_1"},
{KC_LANGUAGE_2, "KC_LANGUAGE_2"},
{KC_LANGUAGE_3, "KC_LANGUAGE_3"},
{KC_LANGUAGE_4, "KC_LANGUAGE_4"},
{KC_LANGUAGE_5, "KC_LANGUAGE_5"},
{KC_LANGUAGE_6, "KC_LANGUAGE_6"},
{KC_LANGUAGE_7, "KC_LANGUAGE_7"},
{KC_LANGUAGE_8, "KC_LANGUAGE_8"},
{KC_LANGUAGE_9, "KC_LANGUAGE_9"},
{KC_ALTERNATE_ERASE, "KC_ALTERNATE_ERASE"},
{KC_SYSTEM_REQUEST, "KC_SYSTEM_REQUEST"},
{KC_CANCEL, "KC_CANCEL"},
{KC_CLEAR, "KC_CLEAR"},
{KC_PRIOR, "KC_PRIOR"},
{KC_RETURN, "KC_RETURN"},
{KC_SEPARATOR, "KC_SEPARATOR"},
{KC_OUT, "KC_OUT"},
{KC_OPER, "KC_OPER"},
{KC_CLEAR_AGAIN, "KC_CLEAR_AGAIN"},
{KC_CRSEL, "KC_CRSEL"},
{KC_EXSEL, "KC_EXSEL"},
{KC_SYSTEM_POWER, "KC_SYSTEM_POWER"},
{KC_SYSTEM_SLEEP, "KC_SYSTEM_SLEEP"},
{KC_SYSTEM_WAKE, "KC_SYSTEM_WAKE"},
{KC_AUDIO_MUTE, "KC_AUDIO_MUTE"},
{KC_AUDIO_VOL_UP, "KC_AUDIO_VOL_UP"},
{KC_AUDIO_VOL_DOWN, "KC_AUDIO_VOL_DOWN"},
{KC_MEDIA_NEXT_TRACK, "KC_MEDIA_NEXT_TRACK"},
{KC_MEDIA_PREV_TRACK, "KC_MEDIA_PREV_TRACK"},
{KC_MEDIA_STOP, "KC_MEDIA_STOP"},
{KC_MEDIA_PLAY_PAUSE, "KC_MEDIA_PLAY_PAUSE"},
{KC_MEDIA_SELECT, "KC_MEDIA_SELECT"},
{KC_MEDIA_EJECT, "KC_MEDIA_EJECT"},
{KC_MAIL, "KC_MAIL"},
{KC_CALCULATOR, "KC_CALCULATOR"},
{KC_MY_COMPUTER, "KC_MY_COMPUTER"},
{KC_WWW_SEARCH, "KC_WWW_SEARCH"},
{KC_WWW_HOME, "KC_WWW_HOME"},
{KC_WWW_BACK, "KC_WWW_BACK"},
{KC_WWW_FORWARD, "KC_WWW_FORWARD"},
{KC_WWW_STOP, "KC_WWW_STOP"},
{KC_WWW_REFRESH, "KC_WWW_REFRESH"},
{KC_WWW_FAVORITES, "KC_WWW_FAVORITES"},
{KC_MEDIA_FAST_FORWARD, "KC_MEDIA_FAST_FORWARD"},
{KC_MEDIA_REWIND, "KC_MEDIA_REWIND"},
{KC_BRIGHTNESS_UP, "KC_BRIGHTNESS_UP"},
{KC_BRIGHTNESS_DOWN, "KC_BRIGHTNESS_DOWN"},
{KC_CONTROL_PANEL, "KC_CONTROL_PANEL"},
{KC_ASSISTANT, "KC_ASSISTANT"},
{KC_MS_UP, "KC_MS_UP"},
{KC_MS_DOWN, "KC_MS_DOWN"},
{KC_MS_LEFT, "KC_MS_LEFT"},
{KC_MS_RIGHT, "KC_MS_RIGHT"},
{KC_MS_BTN1, "KC_MS_BTN1"},
{KC_MS_BTN2, "KC_MS_BTN2"},
{KC_MS_BTN3, "KC_MS_BTN3"},
{KC_MS_BTN4, "KC_MS_BTN4"},
{KC_MS_BTN5, "KC_MS_BTN5"},
{KC_MS_BTN6, "KC_MS_BTN6"},
{KC_MS_BTN7, "KC_MS_BTN7"},
{KC_MS_BTN8, "KC_MS_BTN8"},
{KC_MS_WH_UP, "KC_MS_WH_UP"},
{KC_MS_WH_DOWN, "KC_MS_WH_DOWN"},
{KC_MS_WH_LEFT, "KC_MS_WH_LEFT"},
{KC_MS_WH_RIGHT, "KC_MS_WH_RIGHT"},
{KC_MS_ACCEL0, "KC_MS_ACCEL0"},
{KC_MS_ACCEL1, "KC_MS_ACCEL1"},
{KC_MS_ACCEL2, "KC_MS_ACCEL2"},
{KC_LEFT_CTRL, "KC_LEFT_CTRL"},
{KC_LEFT_SHIFT, "KC_LEFT_SHIFT"},
{KC_LEFT_ALT, "KC_LEFT_ALT"},
{KC_LEFT_GUI, "KC_LEFT_GUI"},
{KC_RIGHT_CTRL, "KC_RIGHT_CTRL"},
{KC_RIGHT_SHIFT, "KC_RIGHT_SHIFT"},
{KC_RIGHT_ALT, "KC_RIGHT_ALT"},
{KC_RIGHT_GUI, "KC_RIGHT_GUI"},
{SH_TG, "SH_TG"},
{SH_TT, "SH_TT"},
{SH_MON, "SH_MON"},
{SH_MOFF, "SH_MOFF"},
{SH_OFF, "SH_OFF"},
{SH_ON, "SH_ON"},
{SH_OS, "SH_OS"},
{MAGIC_SWAP_CONTROL_CAPSLOCK, "MAGIC_SWAP_CONTROL_CAPSLOCK"},
{MAGIC_UNSWAP_CONTROL_CAPSLOCK, "MAGIC_UNSWAP_CONTROL_CAPSLOCK"},
{MAGIC_TOGGLE_CONTROL_CAPSLOCK, "MAGIC_TOGGLE_CONTROL_CAPSLOCK"},
{MAGIC_UNCAPSLOCK_TO_CONTROL, "MAGIC_UNCAPSLOCK_TO_CONTROL"},
{MAGIC_CAPSLOCK_TO_CONTROL, "MAGIC_CAPSLOCK_TO_CONTROL"},
{MAGIC_SWAP_LALT_LGUI, "MAGIC_SWAP_LALT_LGUI"},
{MAGIC_UNSWAP_LALT_LGUI, "MAGIC_UNSWAP_LALT_LGUI"},
{MAGIC_SWAP_RALT_RGUI, "MAGIC_SWAP_RALT_RGUI"},
{MAGIC_UNSWAP_RALT_RGUI, "MAGIC_UNSWAP_RALT_RGUI"},
{MAGIC_UNNO_GUI, "MAGIC_UNNO_GUI"},
{MAGIC_NO_GUI, "MAGIC_NO_GUI"},
{MAGIC_TOGGLE_GUI, "MAGIC_TOGGLE_GUI"},
{MAGIC_SWAP_GRAVE_ESC, "MAGIC_SWAP_GRAVE_ESC"},
{MAGIC_UNSWAP_GRAVE_ESC, "MAGIC_UNSWAP_GRAVE_ESC"},
{MAGIC_SWAP_BACKSLASH_BACKSPACE, "MAGIC_SWAP_BACKSLASH_BACKSPACE"},
{MAGIC_UNSWAP_BACKSLASH_BACKSPACE, "MAGIC_UNSWAP_BACKSLASH_BACKSPACE"},
{MAGIC_TOGGLE_BACKSLASH_BACKSPACE, "MAGIC_TOGGLE_BACKSLASH_BACKSPACE"},
{MAGIC_HOST_NKRO, "MAGIC_HOST_NKRO"},
{MAGIC_UNHOST_NKRO, "MAGIC_UNHOST_NKRO"},
{MAGIC_TOGGLE_NKRO, "MAGIC_TOGGLE_NKRO"},
{MAGIC_SWAP_ALT_GUI, "MAGIC_SWAP_ALT_GUI"},
{MAGIC_UNSWAP_ALT_GUI, "MAGIC_UNSWAP_ALT_GUI"},
{MAGIC_TOGGLE_ALT_GUI, "MAGIC_TOGGLE_ALT_GUI"},
{MAGIC_SWAP_LCTL_LGUI, "MAGIC_SWAP_LCTL_LGUI"},
{MAGIC_UNSWAP_LCTL_LGUI, "MAGIC_UNSWAP_LCTL_LGUI"},
{MAGIC_SWAP_RCTL_RGUI, "MAGIC_SWAP_RCTL_RGUI"},
{MAGIC_UNSWAP_RCTL_RGUI, "MAGIC_UNSWAP_RCTL_RGUI"},
{MAGIC_SWAP_CTL_GUI, "MAGIC_SWAP_CTL_GUI"},
{MAGIC_UNSWAP_CTL_GUI, "MAGIC_UNSWAP_CTL_GUI"},
{MAGIC_TOGGLE_CTL_GUI, "MAGIC_TOGGLE_CTL_GUI"},
{MAGIC_EE_HANDS_LEFT, "MAGIC_EE_HANDS_LEFT"},
{MAGIC_EE_HANDS_RIGHT, "MAGIC_EE_HANDS_RIGHT"},
{MAGIC_SWAP_ESCAPE_CAPSLOCK, "MAGIC_SWAP_ESCAPE_CAPSLOCK"},
{MAGIC_UNSWAP_ESCAPE_CAPSLOCK, "MAGIC_UNSWAP_ESCAPE_CAPSLOCK"},
{MAGIC_TOGGLE_ESCAPE_CAPSLOCK, "MAGIC_TOGGLE_ESCAPE_CAPSLOCK"},
{QK_MIDI_ON, "QK_MIDI_ON"},
{QK_MIDI_OFF, "QK_MIDI_OFF"},
{QK_MIDI_TOGGLE, "QK_MIDI_TOGGLE"},
{QK_MIDI_NOTE_C_0, "QK_MIDI_NOTE_C_0"},
{QK_MIDI_NOTE_C_SHARP_0, "QK_MIDI_NOTE_C_SHARP_0"},
{QK_MIDI_NOTE_D_0, "QK_MIDI_NOTE_D_0"},
{QK_MIDI_NOTE_D_SHARP_0, "QK_MIDI_NOTE_D_SHARP_0"},
{QK_MIDI_NOTE_E_0, "QK_MIDI_NOTE_E_0"},
{QK_MIDI_NOTE_F_0, "QK_MIDI_NOTE_F_0"},
{QK_MIDI_NOTE_F_SHARP_0, "QK_MIDI_NOTE_F_SHARP_0"},
{QK_MIDI_NOTE_G_0, "QK_MIDI_NOTE_G_0"},
{QK_MIDI_NOTE_G_SHARP_0, "QK_MIDI_NOTE_G_SHARP_0"},
{QK_MIDI_NOTE_A_0, "QK_MIDI_NOTE_A_0"},
{QK_MIDI_NOTE_A_SHARP_0, "QK_MIDI_NOTE_A_SHARP_0"},
{QK_MIDI_NOTE_B_0, "QK_MIDI_NOTE_B_0"},
{QK_MIDI_NOTE_C_1, "QK_MIDI_NOTE_C_1"},
{QK_MIDI_NOTE_C_SHARP_1, "QK_MIDI_NOTE_C_SHARP_1"},
{QK_MIDI_NOTE_D_1, "QK_MIDI_NOTE_D_1"},
{QK_MIDI_NOTE_D_SHARP_1, "QK_MIDI_NOTE_D_SHARP_1"},
{QK_MIDI_NOTE_E_1, "QK_MIDI_NOTE_E_1"},
{QK_MIDI_NOTE_F_1, "QK_MIDI_NOTE_F_1"},
{QK_MIDI_NOTE_F_SHARP_1, "QK_MIDI_NOTE_F_SHARP_1"},
{QK_MIDI_NOTE_G_1, "QK_MIDI_NOTE_G_1"},
{QK_MIDI_NOTE_G_SHARP_1, "QK_MIDI_NOTE_G_SHARP_1"},
{QK_MIDI_NOTE_A_1, "QK_MIDI_NOTE_A_1"},
{QK_MIDI_NOTE_A_SHARP_1, "QK_MIDI_NOTE_A_SHARP_1"},
{QK_MIDI_NOTE_B_1, "QK_MIDI_NOTE_B_1"},
{QK_MIDI_NOTE_C_2, "QK_MIDI_NOTE_C_2"},
{QK_MIDI_NOTE_C_SHARP_2, "QK_MIDI_NOTE_C_SHARP_2"},
{QK_MIDI_NOTE_D_2, "QK_MIDI_NOTE_D_2"},
{QK_MIDI_NOTE_D_SHARP_2, "QK_MIDI_NOTE_D_SHARP_2"},
{QK_MIDI_NOTE_E_2, "QK_MIDI_NOTE_E_2"},
{QK_MIDI_NOTE_F_2, "QK_MIDI_NOTE_F_2"},
{QK_MIDI_NOTE_F_SHARP_2, "QK_MIDI_NOTE_F_SHARP_2"},
{QK_MIDI_NOTE_G_2, "QK_MIDI_NOTE_G_2"},
{QK_MIDI_NOTE_G_SHARP_2, "QK_MIDI_NOTE_G_SHARP_2"},
{QK_MIDI_NOTE_A_2, "QK_MIDI_NOTE_A_2"},
{QK_MIDI_NOTE_A_SHARP_2, "QK_MIDI_NOTE_A_SHARP_2"},
{QK_MIDI_NOTE_B_2, "QK_MIDI_NOTE_B_2"},
{QK_MIDI_NOTE_C_3, "QK_MIDI_NOTE_C_3"},
{QK_MIDI_NOTE_C_SHARP_3, "QK_MIDI_NOTE_C_SHARP_3"},
{QK_MIDI_NOTE_D_3, "QK_MIDI_NOTE_D_3"},
{QK_MIDI_NOTE_D_SHARP_3, "QK_MIDI_NOTE_D_SHARP_3"},
{QK_MIDI_NOTE_E_3, "QK_MIDI_NOTE_E_3"},
{QK_MIDI_NOTE_F_3, "QK_MIDI_NOTE_F_3"},
{QK_MIDI_NOTE_F_SHARP_3, "QK_MIDI_NOTE_F_SHARP_3"},
{QK_MIDI_NOTE_G_3, "QK_MIDI_NOTE_G_3"},
{QK_MIDI_NOTE_G_SHARP_3, "QK_MIDI_NOTE_G_SHARP_3"},
{QK_MIDI_NOTE_A_3, "QK_MIDI_NOTE_A_3"},
{QK_MIDI_NOTE_A_SHARP_3, "QK_MIDI_NOTE_A_SHARP_3"},
{QK_MIDI_NOTE_B_3, "QK_MIDI_NOTE_B_3"},
{QK_MIDI_NOTE_C_4, "QK_MIDI_NOTE_C_4"},
{QK_MIDI_NOTE_C_SHARP_4, "QK_MIDI_NOTE_C_SHARP_4"},
{QK_MIDI_NOTE_D_4, "QK_MIDI_NOTE_D_4"},
{QK_MIDI_NOTE_D_SHARP_4, "QK_MIDI_NOTE_D_SHARP_4"},
{QK_MIDI_NOTE_E_4, "QK_MIDI_NOTE_E_4"},
{QK_MIDI_NOTE_F_4, "QK_MIDI_NOTE_F_4"},
{QK_MIDI_NOTE_F_SHARP_4, "QK_MIDI_NOTE_F_SHARP_4"},
{QK_MIDI_NOTE_G_4, "QK_MIDI_NOTE_G_4"},
{QK_MIDI_NOTE_G_SHARP_4, "QK_MIDI_NOTE_G_SHARP_4"},
{QK_MIDI_NOTE_A_4, "QK_MIDI_NOTE_A_4"},
{QK_MIDI_NOTE_A_SHARP_4, "QK_MIDI_NOTE_A_SHARP_4"},
{QK_MIDI_NOTE_B_4, "QK_MIDI_NOTE_B_4"},
{QK_MIDI_NOTE_C_5, "QK_MIDI_NOTE_C_5"},
{QK_MIDI_NOTE_C_SHARP_5, "QK_MIDI_NOTE_C_SHARP_5"},
{QK_MIDI_NOTE_D_5, "QK_MIDI_NOTE_D_5"},
{QK_MIDI_NOTE_D_SHARP_5, "QK_MIDI_NOTE_D_SHARP_5"},
{QK_MIDI_NOTE_E_5, "QK_MIDI_NOTE_E_5"},
{QK_MIDI_NOTE_F_5, "QK_MIDI_NOTE_F_5"},
{QK_MIDI_NOTE_F_SHARP_5, "QK_MIDI_NOTE_F_SHARP_5"},
{QK_MIDI_NOTE_G_5, "QK_MIDI_NOTE_G_5"},
{QK_MIDI_NOTE_G_SHARP_5, "QK_MIDI_NOTE_G_SHARP_5"},
{QK_MIDI_NOTE_A_5, "QK_MIDI_NOTE_A_5"},
{QK_MIDI_NOTE_A_SHARP_5, "QK_MIDI_NOTE_A_SHARP_5"},
{QK_MIDI_NOTE_B_5, "QK_MIDI_NOTE_B_5"},
{QK_MIDI_OCTAVE_N2, "QK_MIDI_OCTAVE_N2"},
{QK_MIDI_OCTAVE_N1, "QK_MIDI_OCTAVE_N1"},
{QK_MIDI_OCTAVE_0, "QK_MIDI_OCTAVE_0"},
{QK_MIDI_OCTAVE_1, "QK_MIDI_OCTAVE_1"},
{QK_MIDI_OCTAVE_2, "QK_MIDI_OCTAVE_2"},
{QK_MIDI_OCTAVE_3, "QK_MIDI_OCTAVE_3"},
{QK_MIDI_OCTAVE_4, "QK_MIDI_OCTAVE_4"},
{QK_MIDI_OCTAVE_5, "QK_MIDI_OCTAVE_5"},
{QK_MIDI_OCTAVE_6, "QK_MIDI_OCTAVE_6"},
{QK_MIDI_OCTAVE_7, "QK_MIDI_OCTAVE_7"},
{QK_MIDI_OCTAVE_DOWN, "QK_MIDI_OCTAVE_DOWN"},
{QK_MIDI_OCTAVE_UP, "QK_MIDI_OCTAVE_UP"},
{QK_MIDI_TRANSPOSE_N6, "QK_MIDI_TRANSPOSE_N6"},
{QK_MIDI_TRANSPOSE_N5, "QK_MIDI_TRANSPOSE_N5"},
{QK_MIDI_TRANSPOSE_N4, "QK_MIDI_TRANSPOSE_N4"},
{QK_MIDI_TRANSPOSE_N3, "QK_MIDI_TRANSPOSE_N3"},
{QK_MIDI_TRANSPOSE_N2, "QK_MIDI_TRANSPOSE_N2"},
{QK_MIDI_TRANSPOSE_N1, "QK_MIDI_TRANSPOSE_N1"},
{QK_MIDI_TRANSPOSE_0, "QK_MIDI_TRANSPOSE_0"},
{QK_MIDI_TRANSPOSE_1, "QK_MIDI_TRANSPOSE_1"},
{QK_MIDI_TRANSPOSE_2, "QK_MIDI_TRANSPOSE_2"},
{QK_MIDI_TRANSPOSE_3, "QK_MIDI_TRANSPOSE_3"},
{QK_MIDI_TRANSPOSE_4, "QK_MIDI_TRANSPOSE_4"},
{QK_MIDI_TRANSPOSE_5, "QK_MIDI_TRANSPOSE_5"},
{QK_MIDI_TRANSPOSE_6, "QK_MIDI_TRANSPOSE_6"},
{QK_MIDI_TRANSPOSE_DOWN, "QK_MIDI_TRANSPOSE_DOWN"},
{QK_MIDI_TRANSPOSE_UP, "QK_MIDI_TRANSPOSE_UP"},
{QK_MIDI_VELOCITY_0, "QK_MIDI_VELOCITY_0"},
{QK_MIDI_VELOCITY_1, "QK_MIDI_VELOCITY_1"},
{QK_MIDI_VELOCITY_2, "QK_MIDI_VELOCITY_2"},
{QK_MIDI_VELOCITY_3, "QK_MIDI_VELOCITY_3"},
{QK_MIDI_VELOCITY_4, "QK_MIDI_VELOCITY_4"},
{QK_MIDI_VELOCITY_5, "QK_MIDI_VELOCITY_5"},
{QK_MIDI_VELOCITY_6, "QK_MIDI_VELOCITY_6"},
{QK_MIDI_VELOCITY_7, "QK_MIDI_VELOCITY_7"},
{QK_MIDI_VELOCITY_8, "QK_MIDI_VELOCITY_8"},
{QK_MIDI_VELOCITY_9, "QK_MIDI_VELOCITY_9"},
{QK_MIDI_VELOCITY_10, "QK_MIDI_VELOCITY_10"},
{QK_MIDI_VELOCITY_DOWN, "QK_MIDI_VELOCITY_DOWN"},
{QK_MIDI_VELOCITY_UP, "QK_MIDI_VELOCITY_UP"},
{QK_MIDI_CHANNEL_1, "QK_MIDI_CHANNEL_1"},
{QK_MIDI_CHANNEL_2, "QK_MIDI_CHANNEL_2"},
{QK_MIDI_CHANNEL_3, "QK_MIDI_CHANNEL_3"},
{QK_MIDI_CHANNEL_4, "QK_MIDI_CHANNEL_4"},
{QK_MIDI_CHANNEL_5, "QK_MIDI_CHANNEL_5"},
{QK_MIDI_CHANNEL_6, "QK_MIDI_CHANNEL_6"},
{QK_MIDI_CHANNEL_7, "QK_MIDI_CHANNEL_7"},
{QK_MIDI_CHANNEL_8, "QK_MIDI_CHANNEL_8"},
{QK_MIDI_CHANNEL_9, "QK_MIDI_CHANNEL_9"},
{QK_MIDI_CHANNEL_10, "QK_MIDI_CHANNEL_10"},
{QK_MIDI_CHANNEL_11, "QK_MIDI_CHANNEL_11"},
{QK_MIDI_CHANNEL_12, "QK_MIDI_CHANNEL_12"},
{QK_MIDI_CHANNEL_13, "QK_MIDI_CHANNEL_13"},
{QK_MIDI_CHANNEL_14, "QK_MIDI_CHANNEL_14"},
{QK_MIDI_CHANNEL_15, "QK_MIDI_CHANNEL_15"},
{QK_MIDI_CHANNEL_16, "QK_MIDI_CHANNEL_16"},
{QK_MIDI_CHANNEL_DOWN, "QK_MIDI_CHANNEL_DOWN"},
{QK_MIDI_CHANNEL_UP, "QK_MIDI_CHANNEL_UP"},
{QK_MIDI_ALL_NOTES_OFF, "QK_MIDI_ALL_NOTES_OFF"},
{QK_MIDI_SUSTAIN, "QK_MIDI_SUSTAIN"},
{QK_MIDI_PORTAMENTO, "QK_MIDI_PORTAMENTO"},
{QK_MIDI_SOSTENUTO, "QK_MIDI_SOSTENUTO"},
{QK_MIDI_SOFT, "QK_MIDI_SOFT"},
{QK_MIDI_LEGATO, "QK_MIDI_LEGATO"},
{QK_MIDI_MODULATION, "QK_MIDI_MODULATION"},
{QK_MIDI_MODULATION_SPEED_DOWN, "QK_MIDI_MODULATION_SPEED_DOWN"},
{QK_MIDI_MODULATION_SPEED_UP, "QK_MIDI_MODULATION_SPEED_UP"},
{QK_MIDI_PITCH_BEND_DOWN, "QK_MIDI_PITCH_BEND_DOWN"},
{QK_MIDI_PITCH_BEND_UP, "QK_MIDI_PITCH_BEND_UP"},
{SQ_ON, "SQ_ON"},
{SQ_OFF, "SQ_OFF"},
{SQ_TOG, "SQ_TOG"},
{SQ_TMPD, "SQ_TMPD"},
{SQ_TMPU, "SQ_TMPU"},
{SQ_RESD, "SQ_RESD"},
{SQ_RESU, "SQ_RESU"},
{SQ_SALL, "SQ_SALL"},
{SQ_SCLR, "SQ_SCLR"},
{QK_JOYSTICK_BUTTON_0, "QK_JOYSTICK_BUTTON_0"},
{QK_JOYSTICK_BUTTON_1, "QK_JOYSTICK_BUTTON_1"},
{QK_JOYSTICK_BUTTON_2, "QK_JOYSTICK_BUTTON_2"},
{QK_JOYSTICK_BUTTON_3, "QK_JOYSTICK_BUTTON_3"},
{QK_JOYSTICK_BUTTON_4, "QK_JOYSTICK_BUTTON_4"},
{QK_JOYSTICK_BUTTON_5, "QK_JOYSTICK_BUTTON_5"},
{QK_JOYSTICK_BUTTON_6, "QK_JOYSTICK_BUTTON_6"},
{QK_JOYSTICK_BUTTON_7, "QK_JOYSTICK_BUTTON_7"},
{QK_JOYSTICK_BUTTON_8, "QK_JOYSTICK_BUTTON_8"},
{QK_JOYSTICK_BUTTON_9, "QK_JOYSTICK_BUTTON_9"},
{QK_JOYSTICK_BUTTON_10, "QK_JOYSTICK_BUTTON_10"},
{QK_JOYSTICK_BUTTON_11, "QK_JOYSTICK_BUTTON_11"},
{QK_JOYSTICK_BUTTON_12, "QK_JOYSTICK_BUTTON_12"},
{QK_JOYSTICK_BUTTON_13, "QK_JOYSTICK_BUTTON_13"},
{QK_JOYSTICK_BUTTON_14, "QK_JOYSTICK_BUTTON_14"},
{QK_JOYSTICK_BUTTON_15, "QK_JOYSTICK_BUTTON_15"},
{QK_JOYSTICK_BUTTON_16, "QK_JOYSTICK_BUTTON_16"},
{QK_JOYSTICK_BUTTON_17, "QK_JOYSTICK_BUTTON_17"},
{QK_JOYSTICK_BUTTON_18, "QK_JOYSTICK_BUTTON_18"},
{QK_JOYSTICK_BUTTON_19, "QK_JOYSTICK_BUTTON_19"},
{QK_JOYSTICK_BUTTON_20, "QK_JOYSTICK_BUTTON_20"},
{QK_JOYSTICK_BUTTON_21, "QK_JOYSTICK_BUTTON_21"},
{QK_JOYSTICK_BUTTON_22, "QK_JOYSTICK_BUTTON_22"},
{QK_JOYSTICK_BUTTON_23, "QK_JOYSTICK_BUTTON_23"},
{QK_JOYSTICK_BUTTON_24, "QK_JOYSTICK_BUTTON_24"},
{QK_JOYSTICK_BUTTON_25, "QK_JOYSTICK_BUTTON_25"},
{QK_JOYSTICK_BUTTON_26, "QK_JOYSTICK_BUTTON_26"},
{QK_JOYSTICK_BUTTON_27, "QK_JOYSTICK_BUTTON_27"},
{QK_JOYSTICK_BUTTON_28, "QK_JOYSTICK_BUTTON_28"},
{QK_JOYSTICK_BUTTON_29, "QK_JOYSTICK_BUTTON_29"},
{QK_JOYSTICK_BUTTON_30, "QK_JOYSTICK_BUTTON_30"},
{QK_JOYSTICK_BUTTON_31, "QK_JOYSTICK_BUTTON_31"},
{QK_PROGRAMMABLE_BUTTON_1, "QK_PROGRAMMABLE_BUTTON_1"},
{QK_PROGRAMMABLE_BUTTON_2, "QK_PROGRAMMABLE_BUTTON_2"},
{QK_PROGRAMMABLE_BUTTON_3, "QK_PROGRAMMABLE_BUTTON_3"},
{QK_PROGRAMMABLE_BUTTON_4, "QK_PROGRAMMABLE_BUTTON_4"},
{QK_PROGRAMMABLE_BUTTON_5, "QK_PROGRAMMABLE_BUTTON_5"},
{QK_PROGRAMMABLE_BUTTON_6, "QK_PROGRAMMABLE_BUTTON_6"},
{QK_PROGRAMMABLE_BUTTON_7, "QK_PROGRAMMABLE_BUTTON_7"},
{QK_PROGRAMMABLE_BUTTON_8, "QK_PROGRAMMABLE_BUTTON_8"},
{QK_PROGRAMMABLE_BUTTON_9, "QK_PROGRAMMABLE_BUTTON_9"},
{QK_PROGRAMMABLE_BUTTON_10, "QK_PROGRAMMABLE_BUTTON_10"},
{QK_PROGRAMMABLE_BUTTON_11, "QK_PROGRAMMABLE_BUTTON_11"},
{QK_PROGRAMMABLE_BUTTON_12, "QK_PROGRAMMABLE_BUTTON_12"},
{QK_PROGRAMMABLE_BUTTON_13, "QK_PROGRAMMABLE_BUTTON_13"},
{QK_PROGRAMMABLE_BUTTON_14, "QK_PROGRAMMABLE_BUTTON_14"},
{QK_PROGRAMMABLE_BUTTON_15, "QK_PROGRAMMABLE_BUTTON_15"},
{QK_PROGRAMMABLE_BUTTON_16, "QK_PROGRAMMABLE_BUTTON_16"},
{QK_PROGRAMMABLE_BUTTON_17, "QK_PROGRAMMABLE_BUTTON_17"},
{QK_PROGRAMMABLE_BUTTON_18, "QK_PROGRAMMABLE_BUTTON_18"},
{QK_PROGRAMMABLE_BUTTON_19, "QK_PROGRAMMABLE_BUTTON_19"},
{QK_PROGRAMMABLE_BUTTON_20, "QK_PROGRAMMABLE_BUTTON_20"},
{QK_PROGRAMMABLE_BUTTON_21, "QK_PROGRAMMABLE_BUTTON_21"},
{QK_PROGRAMMABLE_BUTTON_22, "QK_PROGRAMMABLE_BUTTON_22"},
{QK_PROGRAMMABLE_BUTTON_23, "QK_PROGRAMMABLE_BUTTON_23"},
{QK_PROGRAMMABLE_BUTTON_24, "QK_PROGRAMMABLE_BUTTON_24"},
{QK_PROGRAMMABLE_BUTTON_25, "QK_PROGRAMMABLE_BUTTON_25"},
{QK_PROGRAMMABLE_BUTTON_26, "QK_PROGRAMMABLE_BUTTON_26"},
{QK_PROGRAMMABLE_BUTTON_27, "QK_PROGRAMMABLE_BUTTON_27"},
{QK_PROGRAMMABLE_BUTTON_28, "QK_PROGRAMMABLE_BUTTON_28"},
{QK_PROGRAMMABLE_BUTTON_29, "QK_PROGRAMMABLE_BUTTON_29"},
{QK_PROGRAMMABLE_BUTTON_30, "QK_PROGRAMMABLE_BUTTON_30"},
{QK_PROGRAMMABLE_BUTTON_31, "QK_PROGRAMMABLE_BUTTON_31"},
{QK_PROGRAMMABLE_BUTTON_32, "QK_PROGRAMMABLE_BUTTON_32"},
{QK_AUDIO_ON, "QK_AUDIO_ON"},
{QK_AUDIO_OFF, "QK_AUDIO_OFF"},
{QK_AUDIO_TOGGLE, "QK_AUDIO_TOGGLE"},
{QK_AUDIO_CLICKY_TOGGLE, "QK_AUDIO_CLICKY_TOGGLE"},
{QK_AUDIO_CLICKY_ON, "QK_AUDIO_CLICKY_ON"},
{QK_AUDIO_CLICKY_OFF, "QK_AUDIO_CLICKY_OFF"},
{QK_AUDIO_CLICKY_UP, "QK_AUDIO_CLICKY_UP"},
{QK_AUDIO_CLICKY_DOWN, "QK_AUDIO_CLICKY_DOWN"},
{QK_AUDIO_CLICKY_RESET, "QK_AUDIO_CLICKY_RESET"},
{QK_MUSIC_ON, "QK_MUSIC_ON"},
{QK_MUSIC_OFF, "QK_MUSIC_OFF"},
{QK_MUSIC_TOGGLE, "QK_MUSIC_TOGGLE"},
{QK_MUSIC_MODE_NEXT, "QK_MUSIC_MODE_NEXT"},
{QK_AUDIO_VOICE_NEXT, "QK_AUDIO_VOICE_NEXT"},
{QK_AUDIO_VOICE_PREVIOUS, "QK_AUDIO_VOICE_PREVIOUS"},
{QK_STENO_BOLT, "QK_STENO_BOLT"},
{QK_STENO_GEMINI, "QK_STENO_GEMINI"},
{QK_STENO_COMB, "QK_STENO_COMB"},
{QK_STENO_COMB_MAX, "QK_STENO_COMB_MAX"},
{QK_MACRO_0, "QK_MACRO_0"},
{QK_MACRO_1, "QK_MACRO_1"},
{QK_MACRO_2, "QK_MACRO_2"},
{QK_MACRO_3, "QK_MACRO_3"},
{QK_MACRO_4, "QK_MACRO_4"},
{QK_MACRO_5, "QK_MACRO_5"},
{QK_MACRO_6, "QK_MACRO_6"},
{QK_MACRO_7, "QK_MACRO_7"},
{QK_MACRO_8, "QK_MACRO_8"},
{QK_MACRO_9, "QK_MACRO_9"},
{QK_MACRO_10, "QK_MACRO_10"},
{QK_MACRO_11, "QK_MACRO_11"},
{QK_MACRO_12, "QK_MACRO_12"},
{QK_MACRO_13, "QK_MACRO_13"},
{QK_MACRO_14, "QK_MACRO_14"},
{QK_MACRO_15, "QK_MACRO_15"},
{QK_MACRO_16, "QK_MACRO_16"},
{QK_MACRO_17, "QK_MACRO_17"},
{QK_MACRO_18, "QK_MACRO_18"},
{QK_MACRO_19, "QK_MACRO_19"},
{QK_MACRO_20, "QK_MACRO_20"},
{QK_MACRO_21, "QK_MACRO_21"},
{QK_MACRO_22, "QK_MACRO_22"},
{QK_MACRO_23, "QK_MACRO_23"},
{QK_MACRO_24, "QK_MACRO_24"},
{QK_MACRO_25, "QK_MACRO_25"},
{QK_MACRO_26, "QK_MACRO_26"},
{QK_MACRO_27, "QK_MACRO_27"},
{QK_MACRO_28, "QK_MACRO_28"},
{QK_MACRO_29, "QK_MACRO_29"},
{QK_MACRO_30, "QK_MACRO_30"},
{QK_MACRO_31, "QK_MACRO_31"},
{QK_BACKLIGHT_ON, "QK_BACKLIGHT_ON"},
{QK_BACKLIGHT_OFF, "QK_BACKLIGHT_OFF"},
{QK_BACKLIGHT_TOGGLE, "QK_BACKLIGHT_TOGGLE"},
{QK_BACKLIGHT_DOWN, "QK_BACKLIGHT_DOWN"},
{QK_BACKLIGHT_UP, "QK_BACKLIGHT_UP"},
{QK_BACKLIGHT_STEP, "QK_BACKLIGHT_STEP"},
{QK_BACKLIGHT_TOGGLE_BREATHING, "QK_BACKLIGHT_TOGGLE_BREATHING"},
{RGB_TOG, "RGB_TOG"},
{RGB_MODE_FORWARD, "RGB_MODE_FORWARD"},
{RGB_MODE_REVERSE, "RGB_MODE_REVERSE"},
{RGB_HUI, "RGB_HUI"},
{RGB_HUD, "RGB_HUD"},
{RGB_SAI, "RGB_SAI"},
{RGB_SAD, "RGB_SAD"},
{RGB_VAI, "RGB_VAI"},
{RGB_VAD, "RGB_VAD"},
{RGB_SPI, "RGB_SPI"},
{RGB_SPD, "RGB_SPD"},
{RGB_MODE_PLAIN, "RGB_MODE_PLAIN"},
{RGB_MODE_BREATHE, "RGB_MODE_BREATHE"},
{RGB_MODE_RAINBOW, "RGB_MODE_RAINBOW"},
{RGB_MODE_SWIRL, "RGB_MODE_SWIRL"},
{RGB_MODE_SNAKE, "RGB_MODE_SNAKE"},
{RGB_MODE_KNIGHT, "RGB_MODE_KNIGHT"},
{RGB_MODE_XMAS, "RGB_MODE_XMAS"},
{RGB_MODE_GRADIENT, "RGB_MODE_GRADIENT"},
{RGB_MODE_RGBTEST, "RGB_MODE_RGBTEST"},
{RGB_MODE_TWINKLE, "RGB_MODE_TWINKLE"},
{QK_BOOTLOADER, "QK_BOOTLOADER"},
{QK_REBOOT, "QK_REBOOT"},
{QK_DEBUG_TOGGLE, "QK_DEBUG_TOGGLE"},
{QK_CLEAR_EEPROM, "QK_CLEAR_EEPROM"},
{QK_MAKE, "QK_MAKE"},
{QK_AUTO_SHIFT_DOWN, "QK_AUTO_SHIFT_DOWN"},
{QK_AUTO_SHIFT_UP, "QK_AUTO_SHIFT_UP"},
{QK_AUTO_SHIFT_REPORT, "QK_AUTO_SHIFT_REPORT"},
{QK_AUTO_SHIFT_ON, "QK_AUTO_SHIFT_ON"},
{QK_AUTO_SHIFT_OFF, "QK_AUTO_SHIFT_OFF"},
{QK_AUTO_SHIFT_TOGGLE, "QK_AUTO_SHIFT_TOGGLE"},
{QK_GRAVE_ESCAPE, "QK_GRAVE_ESCAPE"},
{QK_VELOCIKEY_TOGGLE, "QK_VELOCIKEY_TOGGLE"},
{QK_SPACE_CADET_LEFT_CTRL_PARENTHESIS_OPEN, "QK_SPACE_CADET_LEFT_CTRL_PARENTHESIS_OPEN"},
{QK_SPACE_CADET_RIGHT_CTRL_PARENTHESIS_CLOSE, "QK_SPACE_CADET_RIGHT_CTRL_PARENTHESIS_CLOSE"},
{QK_SPACE_CADET_LEFT_SHIFT_PARENTHESIS_OPEN, "QK_SPACE_CADET_LEFT_SHIFT_PARENTHESIS_OPEN"},
{QK_SPACE_CADET_RIGHT_SHIFT_PARENTHESIS_CLOSE, "QK_SPACE_CADET_RIGHT_SHIFT_PARENTHESIS_CLOSE"},
{QK_SPACE_CADET_LEFT_ALT_PARENTHESIS_OPEN, "QK_SPACE_CADET_LEFT_ALT_PARENTHESIS_OPEN"},
{QK_SPACE_CADET_RIGHT_ALT_PARENTHESIS_CLOSE, "QK_SPACE_CADET_RIGHT_ALT_PARENTHESIS_CLOSE"},
{QK_SPACE_CADET_RIGHT_SHIFT_ENTER, "QK_SPACE_CADET_RIGHT_SHIFT_ENTER"},
{QK_OUTPUT_AUTO, "QK_OUTPUT_AUTO"},
{QK_OUTPUT_USB, "QK_OUTPUT_USB"},
{QK_OUTPUT_BLUETOOTH, "QK_OUTPUT_BLUETOOTH"},
{QK_UNICODE_MODE_NEXT, "QK_UNICODE_MODE_NEXT"},
{QK_UNICODE_MODE_PREVIOUS, "QK_UNICODE_MODE_PREVIOUS"},
{QK_UNICODE_MODE_MACOS, "QK_UNICODE_MODE_MACOS"},
{QK_UNICODE_MODE_LINUX, "QK_UNICODE_MODE_LINUX"},
{QK_UNICODE_MODE_WINDOWS, "QK_UNICODE_MODE_WINDOWS"},
{QK_UNICODE_MODE_BSD, "QK_UNICODE_MODE_BSD"},
{QK_UNICODE_MODE_WINCOMPOSE, "QK_UNICODE_MODE_WINCOMPOSE"},
{QK_UNICODE_MODE_EMACS, "QK_UNICODE_MODE_EMACS"},
{QK_HAPTIC_ON, "QK_HAPTIC_ON"},
{QK_HAPTIC_OFF, "QK_HAPTIC_OFF"},
{QK_HAPTIC_TOGGLE, "QK_HAPTIC_TOGGLE"},
{QK_HAPTIC_RESET, "QK_HAPTIC_RESET"},
{QK_HAPTIC_FEEDBACK_TOGGLE, "QK_HAPTIC_FEEDBACK_TOGGLE"},
{QK_HAPTIC_BUZZ_TOGGLE, "QK_HAPTIC_BUZZ_TOGGLE"},
{QK_HAPTIC_MODE_NEXT, "QK_HAPTIC_MODE_NEXT"},
{QK_HAPTIC_MODE_PREVIOUS, "QK_HAPTIC_MODE_PREVIOUS"},
{QK_HAPTIC_CONTINUOUS_TOGGLE, "QK_HAPTIC_CONTINUOUS_TOGGLE"},
{QK_HAPTIC_CONTINUOUS_UP, "QK_HAPTIC_CONTINUOUS_UP"},
{QK_HAPTIC_CONTINUOUS_DOWN, "QK_HAPTIC_CONTINUOUS_DOWN"},
{QK_HAPTIC_DWELL_UP, "QK_HAPTIC_DWELL_UP"},
{QK_HAPTIC_DWELL_DOWN, "QK_HAPTIC_DWELL_DOWN"},
{QK_COMBO_ON, "QK_COMBO_ON"},
{QK_COMBO_OFF, "QK_COMBO_OFF"},
{QK_COMBO_TOGGLE, "QK_COMBO_TOGGLE"},
{QK_DYNAMIC_MACRO_RECORD_START_1, "QK_DYNAMIC_MACRO_RECORD_START_1"},
{QK_DYNAMIC_MACRO_RECORD_START_2, "QK_DYNAMIC_MACRO_RECORD_START_2"},
{QK_DYNAMIC_MACRO_RECORD_STOP, "QK_DYNAMIC_MACRO_RECORD_STOP"},
{QK_DYNAMIC_MACRO_PLAY_1, "QK_DYNAMIC_MACRO_PLAY_1"},
{QK_DYNAMIC_MACRO_PLAY_2, "QK_DYNAMIC_MACRO_PLAY_2"},
{QK_LEADER, "QK_LEADER"},
{QK_LOCK, "QK_LOCK"},
{QK_ONE_SHOT_ON, "QK_ONE_SHOT_ON"},
{QK_ONE_SHOT_OFF, "QK_ONE_SHOT_OFF"},
{QK_ONE_SHOT_TOGGLE, "QK_ONE_SHOT_TOGGLE"},
{QK_KEY_OVERRIDE_TOGGLE, "QK_KEY_OVERRIDE_TOGGLE"},
{QK_KEY_OVERRIDE_ON, "QK_KEY_OVERRIDE_ON"},
{QK_KEY_OVERRIDE_OFF, "QK_KEY_OVERRIDE_OFF"},
{QK_SECURE_LOCK, "QK_SECURE_LOCK"},
{QK_SECURE_UNLOCK, "QK_SECURE_UNLOCK"},
{QK_SECURE_TOGGLE, "QK_SECURE_TOGGLE"},
{QK_SECURE_REQUEST, "QK_SECURE_REQUEST"},
{QK_DYNAMIC_TAPPING_TERM_PRINT, "QK_DYNAMIC_TAPPING_TERM_PRINT"},
{QK_DYNAMIC_TAPPING_TERM_UP, "QK_DYNAMIC_TAPPING_TERM_UP"},
{QK_DYNAMIC_TAPPING_TERM_DOWN, "QK_DYNAMIC_TAPPING_TERM_DOWN"},
{QK_CAPS_WORD_TOGGLE, "QK_CAPS_WORD_TOGGLE"},
{QK_AUTOCORRECT_ON, "QK_AUTOCORRECT_ON"},
{QK_AUTOCORRECT_OFF, "QK_AUTOCORRECT_OFF"},
{QK_AUTOCORRECT_TOGGLE, "QK_AUTOCORRECT_TOGGLE"},
{SAFE_RANGE, "SAFE_RANGE"},
};

View File

@ -0,0 +1,128 @@
#include "keycode_util.hpp"
#include <cstdint>
extern "C" {
#include "action_code.h"
#include "keycode.h"
#include "quantum_keycodes.h"
#include "util.h"
}
#include <string>
#include <iomanip>
#include <map>
extern std::map<uint16_t, std::string> KEYCODE_ID_TABLE;
std::string get_mods(uint8_t mods) {
std::stringstream s;
if ((mods & MOD_RCTL) == MOD_RCTL) {
s << XSTR(MOD_RCTL) << " | ";
} else if ((mods & MOD_LCTL) == MOD_LCTL) {
s << XSTR(MOD_LCTL) << " | ";
}
if ((mods & MOD_RSFT) == MOD_RSFT) {
s << XSTR(MOD_RSFT) << " | ";
} else if ((mods & MOD_LSFT) == MOD_LSFT) {
s << XSTR(MOD_LSFT) << " | ";
}
if ((mods & MOD_RALT) == MOD_RALT) {
s << XSTR(MOD_RALT) << " | ";
} else if ((mods & MOD_LALT) == MOD_LALT) {
s << XSTR(MOD_LALT) << " | ";
}
if ((mods & MOD_RGUI) == MOD_RGUI) {
s << XSTR(MOD_RGUI) << " | ";
} else if ((mods & MOD_LGUI) == MOD_LGUI) {
s << XSTR(MOD_LGUI) << " | ";
}
auto _mods = s.str();
if (_mods.size()) {
_mods.resize(_mods.size() - 3);
}
return std::string(_mods);
}
std::string get_qk_mods(uint16_t keycode) {
std::stringstream s;
if ((keycode & QK_RCTL) == QK_RCTL) {
s << XSTR(QK_RCTL) << " | ";
} else if ((keycode & QK_LCTL) == QK_LCTL) {
s << XSTR(QK_LCTL) << " | ";
}
if ((keycode & QK_RSFT) == QK_RSFT) {
s << XSTR(QK_RSFT) << " | ";
} else if ((keycode & QK_LSFT) == QK_LSFT) {
s << XSTR(QK_LSFT) << " | ";
}
if ((keycode & QK_RALT) == QK_RALT) {
s << XSTR(QK_RALT) << " | ";
} else if ((keycode & QK_LALT) == QK_LALT) {
s << XSTR(QK_LALT) << " | ";
}
if ((keycode & QK_RGUI) == QK_RGUI) {
s << XSTR(QK_RGUI) << " | ";
} else if ((keycode & QK_LGUI) == QK_LGUI) {
s << XSTR(QK_LGUI) << " | ";
}
auto _mods = s.str();
if (_mods.size()) {
_mods.resize(_mods.size() - 3);
}
return std::string(_mods);
}
std::string generate_identifier(uint16_t kc) {
std::stringstream s;
if (IS_QK_MOD_TAP(kc)) {
s << "MT(" << get_mods(QK_MOD_TAP_GET_MODS(kc)) << ", " << KEYCODE_ID_TABLE.at(kc & 0xFF) << ")";
} else if (IS_QK_LAYER_TAP(kc)) {
s << "LT(" << +QK_LAYER_TAP_GET_LAYER(kc) << ", " << KEYCODE_ID_TABLE.at(kc & 0xFF) << ")";
} else if (IS_QK_TO(kc)) {
s << "TO(" << +QK_TO_GET_LAYER(kc) << ")";
} else if (IS_QK_MOMENTARY(kc)) {
s << "MO(" << +QK_MOMENTARY_GET_LAYER(kc) << ")";
} else if (IS_QK_DEF_LAYER(kc)) {
s << "DF(" << +QK_DEF_LAYER_GET_LAYER(kc) << ")";
} else if (IS_QK_TOGGLE_LAYER(kc)) {
s << "TG(" << +QK_TOGGLE_LAYER_GET_LAYER(kc) << ")";
} else if (IS_QK_LAYER_TAP_TOGGLE(kc)) {
s << "TT(" << +QK_LAYER_TAP_TOGGLE_GET_LAYER(kc) << ")";
} else if (IS_QK_ONE_SHOT_LAYER(kc)) {
s << "OSL(" << +QK_ONE_SHOT_LAYER_GET_LAYER(kc) << ")";
} else if (IS_QK_LAYER_MOD(kc)) {
s << "LM(" << +QK_LAYER_MOD_GET_LAYER(kc) << ", " << get_mods(QK_LAYER_MOD_GET_MODS(kc)) << ")";
} else if (IS_QK_ONE_SHOT_MOD(kc)) {
s << "OSM(" << get_mods(QK_ONE_SHOT_MOD_GET_MODS(kc)) << ")";
} else if (IS_QK_MODS(kc)) {
s << "QK_MODS(" << KEYCODE_ID_TABLE.at(QK_MODS_GET_BASIC_KEYCODE(kc)) << ", " << get_qk_mods(kc) << ")";
} else if (IS_QK_TAP_DANCE(kc)) {
s << "TD(" << +(kc & 0xFF) << ")";
} else {
// Fallback - we didn't found any matching keycode, generate the hex representation.
s << "unknown keycode: 0x" << std::hex << kc << ". Add conversion to " << XSTR(generate_identifier);
}
return std::string(s.str());
}
std::string get_keycode_identifier_or_default(uint16_t keycode) {
auto identifier = KEYCODE_ID_TABLE.find(keycode);
if (identifier != KEYCODE_ID_TABLE.end()) {
return identifier->second;
}
KEYCODE_ID_TABLE[keycode] = generate_identifier(keycode);
return KEYCODE_ID_TABLE[keycode];
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
std::string get_keycode_identifier_or_default(uint16_t keycode);

View File

@ -41,11 +41,15 @@ void matrix_init_kb(void) {}
void matrix_scan_kb(void) {} void matrix_scan_kb(void) {}
void press_key(uint8_t col, uint8_t row) { void press_key(uint8_t col, uint8_t row) {
matrix[row] |= 1 << col; matrix[row] |= (matrix_row_t)1 << col;
} }
void release_key(uint8_t col, uint8_t row) { void release_key(uint8_t col, uint8_t row) {
matrix[row] &= ~(1 << col); matrix[row] &= ~((matrix_row_t)1 << col);
}
bool matrix_is_on(uint8_t row, uint8_t col) {
return (matrix[row] & ((matrix_row_t)1 << col));
} }
void clear_all_keys(void) { void clear_all_keys(void) {

View File

@ -22,5 +22,6 @@ extern "C" {
} }
#include "test_driver.hpp" #include "test_driver.hpp"
#include "test_matrix.h" #include "test_matrix.h"
#include "test_keymap_key.hpp"
#include "keyboard_report_util.hpp" #include "keyboard_report_util.hpp"
#include "test_fixture.hpp" #include "test_fixture.hpp"

View File

@ -12,6 +12,7 @@
#include "test_logger.hpp" #include "test_logger.hpp"
#include "test_matrix.h" #include "test_matrix.h"
#include "test_keymap_key.hpp" #include "test_keymap_key.hpp"
#include "timer.h"
extern "C" { extern "C" {
#include "action.h" #include "action.h"
@ -41,7 +42,7 @@ extern "C" uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t position) {
} }
void TestFixture::SetUpTestCase() { void TestFixture::SetUpTestCase() {
test_logger.info() << "TestFixture setup-up start." << std::endl; test_logger.info() << "test fixture setup-up start." << std::endl;
// The following is enough to bootstrap the values set in main // The following is enough to bootstrap the values set in main
eeconfig_init_quantum(); eeconfig_init_quantum();
@ -50,17 +51,19 @@ void TestFixture::SetUpTestCase() {
TestDriver driver; TestDriver driver;
keyboard_init(); keyboard_init();
test_logger.info() << "TestFixture setup-up end." << std::endl; test_logger.info() << "test fixture setup-up end." << std::endl;
} }
void TestFixture::TearDownTestCase() {} void TestFixture::TearDownTestCase() {}
TestFixture::TestFixture() { TestFixture::TestFixture() {
m_this = this; m_this = this;
timer_clear();
test_logger.info() << "tapping term is " << +GET_TAPPING_TERM(KC_TRANSPARENT, &(keyrecord_t){}) << "ms" << std::endl;
} }
TestFixture::~TestFixture() { TestFixture::~TestFixture() {
test_logger.info() << "TestFixture clean-up start." << std::endl; test_logger.info() << "test fixture clean-up start." << std::endl;
TestDriver driver; TestDriver driver;
/* Reset keyboard state. */ /* Reset keyboard state. */
@ -85,17 +88,15 @@ TestFixture::~TestFixture() {
EXPECT_NO_REPORT(driver); EXPECT_NO_REPORT(driver);
idle_for(TAPPING_TERM * 10); idle_for(TAPPING_TERM * 10);
testing::Mock::VerifyAndClearExpectations(&driver); testing::Mock::VerifyAndClearExpectations(&driver);
m_this = nullptr; m_this = nullptr;
test_logger.info() << "TestFixture clean-up end." << std::endl; test_logger.info() << "test fixture clean-up end." << std::endl;
print_test_log(); print_test_log();
} }
void TestFixture::add_key(KeymapKey key) { void TestFixture::add_key(KeymapKey key) {
if (this->find_key(key.layer, key.position)) { if (this->find_key(key.layer, key.position)) {
FAIL() << "Key is already mapped for layer " << +key.layer << " and (column,row) (" << +key.position.col << "," << +key.position.row << ")"; FAIL() << "key is already mapped for layer " << +key.layer << " and (column,row) (" << +key.position.col << "," << +key.position.row << ")";
} }
this->keymap.push_back(key); this->keymap.push_back(key);
@ -149,7 +150,7 @@ void TestFixture::get_keycode(const layer_t layer, const keypos_t position, uint
/* See if this is done in hardware as well, because this is 100% out of bounds reads on all QMK keebs out there. */ /* See if this is done in hardware as well, because this is 100% out of bounds reads on all QMK keebs out there. */
auto msg = [&]() { auto msg = [&]() {
std::stringstream msg; std::stringstream msg;
msg << "Keycode for position (" << +position.col << "," << +position.row << ") requested! This is out of bounds." << std::endl; msg << "keycode for position (" << +position.col << "," << +position.row << ") requested! This is out of bounds." << std::endl;
return msg.str(); return msg.str();
}(); }();
@ -164,17 +165,18 @@ void TestFixture::get_keycode(const layer_t layer, const keypos_t position, uint
return; return;
} }
FAIL() << "No key is mapped for layer " << +layer << " and (column,row) " << +position.col << "," << +position.row << ")"; FAIL() << "no key is mapped for layer " << +layer << " and (column,row) " << +position.col << "," << +position.row << ")";
} }
void TestFixture::run_one_scan_loop() { void TestFixture::run_one_scan_loop() {
keyboard_task(); this->idle_for(1);
advance_time(1);
} }
void TestFixture::idle_for(unsigned time) { void TestFixture::idle_for(unsigned time) {
test_logger.trace() << +time << " keyboard task " << (time > 1 ? "loops" : "loop") << std::endl;
for (unsigned i = 0; i < time; i++) { for (unsigned i = 0; i < time; i++) {
run_one_scan_loop(); keyboard_task();
advance_time(1);
} }
} }
@ -182,12 +184,13 @@ void TestFixture::print_test_log() const {
const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info();
if (HasFailure()) { if (HasFailure()) {
std::cerr << test_info->test_case_name() << "." << test_info->name() << " failed!" << std::endl; std::cerr << test_info->test_case_name() << "." << test_info->name() << " failed!" << std::endl;
test_logger.print_header();
test_logger.print_log(); test_logger.print_log();
} }
test_logger.reset(); test_logger.reset();
} }
void TestFixture::expect_layer_state(layer_t layer_state) const { void TestFixture::expect_layer_state(layer_t layer_state) const {
test_logger.trace() << "Layer state: (" << +layer_state << ") Highest layer bit: (" << +get_highest_layer(layer_state) << ")" << std::endl; test_logger.trace() << "layer state: (" << +layer_state << ") highest layer bit: (" << +get_highest_layer(layer_state) << ")" << std::endl;
EXPECT_TRUE(layer_state_is(layer_state)); EXPECT_TRUE(layer_state_is(layer_state));
} }

View File

@ -15,16 +15,26 @@
*/ */
#include "test_keymap_key.hpp" #include "test_keymap_key.hpp"
#include <cstdint>
#include <ios>
#include "matrix.h"
#include "test_logger.hpp" #include "test_logger.hpp"
#include "gtest/gtest-message.h" #include "gtest/gtest-message.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "timer.h"
void KeymapKey::press() { void KeymapKey::press() {
test_logger.trace() << "Key pressed: (" << +this->position.col << "," << +this->position.row << ")" << std::endl; EXPECT_FALSE(matrix_is_on(position.row, position.col)) << "tried to press key " << this->name << " that was already pressed! Check the test code." << std::endl;
press_key(this->position.col, this->position.row); press_key(this->position.col, this->position.row);
this->timestamp_pressed = timer_read32();
test_logger.trace() << std::setw(10) << std::left << "pressed: " << this->name << std::endl;
} }
void KeymapKey::release() { void KeymapKey::release() {
test_logger.trace() << "Key released: (" << +this->position.col << "," << +this->position.row << ")" << std::endl; EXPECT_TRUE(matrix_is_on(this->position.row, this->position.col)) << "tried to release key " << this->name << " that wasn't pressed before! Check the test code." << std::endl;
release_key(this->position.col, this->position.row); release_key(this->position.col, this->position.row);
uint32_t now = timer_read32();
test_logger.trace() << std::setw(10) << std::left << "released: " << this->name << " was pressed for " << now - this->timestamp_pressed << "ms" << std::endl;
} }

View File

@ -16,6 +16,9 @@
#pragma once #pragma once
#include <cstddef>
#include <string>
#include "keycode_util.hpp"
extern "C" { extern "C" {
#include "keyboard.h" #include "keyboard.h"
#include "test_matrix.h" #include "test_matrix.h"
@ -26,8 +29,13 @@ extern "C" {
typedef uint8_t layer_t; typedef uint8_t layer_t;
struct KeymapKey { struct KeymapKey {
KeymapKey(layer_t layer, uint8_t col, uint8_t row, uint16_t keycode) : layer(layer), position({.col = col, .row = row}), code(keycode), report_code(keycode) { validate(); } KeymapKey(layer_t layer, uint8_t col, uint8_t row, uint16_t keycode) : layer(layer), position({.col = col, .row = row}), code(keycode), report_code(keycode), name(get_keycode_identifier_or_default(keycode)) {
KeymapKey(layer_t layer, uint8_t col, uint8_t row, uint16_t keycode, uint16_t report_code) : layer(layer), position({.col = col, .row = row}), code(keycode), report_code(report_code) { validate(); } validate();
}
KeymapKey(layer_t layer, uint8_t col, uint8_t row, uint16_t keycode, uint16_t report_code) : layer(layer), position({.col = col, .row = row}), code(keycode), report_code(report_code), name{get_keycode_identifier_or_default(keycode)} {
validate();
}
void press(); void press();
void release(); void release();
@ -35,6 +43,7 @@ struct KeymapKey {
const layer_t layer; const layer_t layer;
const keypos_t position; const keypos_t position;
const uint16_t code; const uint16_t code;
std::string name;
/* Sometimes the keycode does not match the code that is send in the usb report, so we provide it here. */ /* Sometimes the keycode does not match the code that is send in the usb report, so we provide it here. */
const uint16_t report_code; const uint16_t report_code;
@ -43,4 +52,5 @@ struct KeymapKey {
assert(position.col <= MATRIX_COLS); assert(position.col <= MATRIX_COLS);
assert(position.row <= MATRIX_ROWS); assert(position.row <= MATRIX_ROWS);
} }
uint32_t timestamp_pressed;
}; };

View File

@ -14,30 +14,40 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <iomanip>
#include <iostream> #include <iostream>
#include "test_logger.hpp" #include "test_logger.hpp"
#include "timer.h"
TestLogger test_logger; TestLogger test_logger;
TestLogger& TestLogger::info() { TestLogger& TestLogger::info() {
*this << "[ INFO ] "; *this << "[ INFO ] ";
return *this; return this->timestamp();
} }
TestLogger& TestLogger::trace() { TestLogger& TestLogger::trace() {
*this << "[ TRACE ] "; *this << "[ TRACE ] ";
return *this; return this->timestamp();
} }
TestLogger& TestLogger::error() { TestLogger& TestLogger::error() {
*this << "[ ERROR ] "; *this << "[ ERROR ] ";
return *this; return this->timestamp();
} }
TestLogger& TestLogger::timestamp() {
*this << std::setw(6) << timer_read32() << " ";
return *this;
}
void TestLogger::reset() { void TestLogger::reset() {
this->m_log.str(""); this->m_log.str("");
}; };
void TestLogger::print_header() {
std::cerr << "[ LEVEL ] [TIME] [EVENT]" << std::endl;
}
void TestLogger::print_log() { void TestLogger::print_log() {
std::cerr << this->m_log.str(); std::cerr << this->m_log.str();
} }

View File

@ -25,10 +25,12 @@ class TestLogger : public std::ostream {
TestLogger& info(); TestLogger& info();
TestLogger& trace(); TestLogger& trace();
TestLogger& error(); TestLogger& error();
void print_log(); void print_log();
void reset(); void print_header();
void reset();
private: private:
TestLogger& timestamp();
std::stringbuf m_log; std::stringbuf m_log;
}; };