#include #include #include #include "unity.h" #include "asdf.h" #include "asdf_arch.h" #include "asdf_ascii.h" #include "asdf_modifiers.h" #include "asdf_keymaps.h" #include "asdf_keymap_defs.h" #include "asdf_buffer.h" #include "asdf_repeat.h" #define A 'a' #define B 'b' #define TEST_STRING "abcdefghijklmnop" #define NUM_REPEATS (ASDF_KEYCODE_BUFFER_SIZE - 2) #define TESTMAP(row, col, mapname, mapname2) \ do { \ asdf_keycode_t expected = mapname##_matrix[(row)][(col)]; \ asdf_keycode_t result = asdf_keymaps_get_code((row), (col), MOD_##mapname2##_MAP); \ TEST_ASSERT_EQUAL_INT(expected, result); \ } while (0); #define TESTPLAIN(row, col, n) TESTMAP((row), (col), PLAIN, n) #define TESTSHIFT(row, col, n) TESTMAP((row), (col), SHIFT, n) #define TESTCAPS(row, col, n) TESTMAP((row), (col), CAPS, n) #define TESTCTRL(row, col, n) TESTMAP((row), (col), CTRL, n) const char test_string[] = TEST_STRING; const asdf_keycode_t key_a = A; const asdf_keycode_t key_b = B; typedef struct { int32_t row; int32_t col; } coord_t; ASDF_TEST_DECLARATIONS; static uint32_t key_matrix[ASDF_NUM_ROWS]; void setUp(void) { asdf_buffer_init(); asdf_init(); // initialize simulated key matrix for (uint32_t i = 0; i < ASDF_NUM_ROWS; i++) { key_matrix[i] = 0; } } void tearDown(void) {} coord_t *find_code(asdf_keycode_t code) { uint32_t done = 0; static coord_t location = { .row = -1, .col = -1 }; for (uint32_t row = 0; !done && (row < ASDF_NUM_ROWS); row++) { for (uint32_t col = 0; !done && (col < ASDF_NUM_COLS); col++) { if (test_PLAIN_matrix[row][col] == code) { done = 1; location.row = row; location.col = col; } } } return &location; } asdf_keycode_t shifted(asdf_keycode_t code) <{ coord_t *location = find_code(code); return test_SHIFT_matrix[location->row][location->col]; } asdf_keycode_t caps(asdf_keycode_t code) { coord_t *xy = find_code(code); return test_CAPS_matrix[xy->row][xy->col]; } asdf_keycode_t ctrl(asdf_keycode_t code) { coord_t *xy = find_code(code); return test_CTRL_matrix[xy->row][xy->col]; } void keyscan_delay(int32_t ticks) { for (; ticks; ticks--) { asdf_keyscan(); } } void press_no_debounce(asdf_keycode_t code) { coord_t *location = find_code(code); key_matrix[location->row] |= (1 << location->col); } void release_no_debounce(asdf_keycode_t code) { coord_t *location = find_code(code); key_matrix[location->row] &= ~(1 << location->col); } void press(asdf_keycode_t code) { press_no_debounce(code); keyscan_delay(ASDF_DEBOUNCE_TIME_MS); } void release(asdf_keycode_t code) { release_no_debounce(code); keyscan_delay(ASDF_DEBOUNCE_TIME_MS); } asdf_cols_t asdf_arch_read_row(uint8_t row) { return key_matrix[row]; } // No repsonse to a keypress before it is debounced. void pressing_a_gives_nothing_before_debounce(void) { press_no_debounce(key_a); // no keypress after only ASDF_DEBOUNCE_TIME_MS -1 ticks (not yet debounced): keyscan_delay(ASDF_DEBOUNCE_TIME_MS - 1); TEST_ASSERT_EQUAL_INT32(ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing 'A' gives 'a' void pressing_a_gives_a(void) { press_no_debounce(key_a); // no keypress after only ASDF_DEBOUNCE_TIME_MS -1 ticks (not yet debounced): keyscan_delay(ASDF_DEBOUNCE_TIME_MS - 1); TEST_ASSERT_EQUAL_INT32(ASDF_INVALID_CODE, (int32_t) asdf_next_code()); // allow the key to finish debounce keyscan_delay(1); TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (int32_t) asdf_next_code()); // no more codes in the buffer. TEST_ASSERT_EQUAL_INT32(ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing SHIFT+A gives 'A' void pressing_shift_a_gives_shifted_a(void) { press(ACTION_SHIFT); press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) shifted(key_a), (int32_t) asdf_next_code()); } // pressing CAPS+A gives 'A' void pressing_caps_a_gives_caps_a(void) { press(ACTION_CAPS); release(ACTION_CAPS); press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) caps(key_a), (int32_t) asdf_next_code()); } // pressing CTRL+A gives 0x01 (Ctrl-A) void pressing_ctrl_a_gives_ctrl_a(void) { press(ACTION_CTRL); press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) ctrl(key_a), (int32_t) asdf_next_code()); } // pressing REPT+A repeats 'a' void pressing_rept_a_repeats_a(void) { press(ACTION_REPEAT); press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); for (int i = 0; i < NUM_REPEATS; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); } // and verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing REPT+SHIFT+A repeats 'A' void pressing_shift_rept_a_repeats_shifted_a(void) { press(ACTION_REPEAT); press(ACTION_SHIFT); press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) shifted(key_a), (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); for (int i = 0; i < NUM_REPEATS; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) shifted(key_a), (uint32_t) asdf_next_code()); } // and verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing REPT+CAPS+A repeats 'A' void pressing_caps_rept_a_repeats_caps_a(void) { press(ACTION_REPEAT); press(ACTION_CAPS); press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) caps(key_a), (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); for (int i = 0; i < NUM_REPEATS; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) caps(key_a), (uint32_t) asdf_next_code()); } // and verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing REPT+CTRL+A repeats CTRL-A void pressing_ctrl_rept_a_repeats_ctrl_a(void) { press(ACTION_REPEAT); press(ACTION_CTRL); press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) ctrl(key_a), (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); for (int i = 0; i < NUM_REPEATS + 1; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) ctrl(key_a), (uint32_t) asdf_next_code()); } // and verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing and holding 'A' autorepeats 'A' void holding_a_autorepeats_a(void) { press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(ASDF_AUTOREPEAT_TIME_MS); TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); // and verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing and holding 'A' autorepeats 'A' void holding_a_autorepeats_slow_then_fast(void) { press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(ASDF_AUTOREPEAT_TIME_MS); TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); for (int i = 0; i < NUM_REPEATS; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); } // and verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing and holding 'A' and 'B' within less than debounce interval // eventually returns 'A' then 'B' void pressing_a_then_b_before_debounce_gives_a_then_b(void) { press_no_debounce(key_a); // press B very quickly after a keyscan_delay(1); press(key_b); // first get back A TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); // next get back B TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code()); // and then verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing and holding a series of keys (up to buffer size) in rapid // succession, allowing each key to debounce, before sending the next, sends all // the keys in order. (n-key rollover) void test_key_sequence_nkro(void) { for (int i = 0; i < (int32_t) strlen(test_string); i++) { press((asdf_keycode_t) test_string[i]); } for (int i = 0; i < (int32_t) strlen(test_string); i++) { TEST_ASSERT_EQUAL_INT32((int32_t) test_string[i], (int32_t) asdf_next_code()); } // and then verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // pressing and holding a series of keys (up to buffer size) in rapid succession // without waiting for prior keys to debounce, eventually debounces and sends // all the keys in order. (n-key rollover) void test_key_sequence_nkro_simultaneous_debounce(void) { for (int i = 0; i < (int32_t) strlen(test_string); i++) { press_no_debounce((asdf_keycode_t) test_string[i]); keyscan_delay(1); } // several keys are already debounced, but now make sure they all are: keyscan_delay(ASDF_DEBOUNCE_TIME_MS); for (int i = 0; i < (int32_t) strlen(test_string); i++) { TEST_ASSERT_EQUAL_INT32((int32_t) test_string[i], (int32_t) asdf_next_code()); } // and then verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // holding 'A' then pressing 'B' before autorepeat interval and holding 'B' gives 'A', then repeats // 'B' void holding_a_briefly_then_holding_b_gives_a_and_repeats_b(void) { press(key_a); keyscan_delay(ASDF_AUTOREPEAT_TIME_MS / 2); press(key_b); // hold "a" and "b" for autorepeat delay: keyscan_delay(ASDF_AUTOREPEAT_TIME_MS); // hold "a" and "b" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); // should get "a" back, then "b" TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code()); // now get back NUM_REEPEATS repetitions of "b" for (int i = 0; i < NUM_REPEATS; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code()); } // and then verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // holding 'B' while repeating 'A' starts autorepeat delay, then starts repeating 'B' void holding_a_then_holding_b_autorepeats_a_then_autorepeats_b(void) { press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); // hold "a" for AUTOREPEAT delay keyscan_delay(ASDF_AUTOREPEAT_TIME_MS); TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); // empty the buffer to make room for 'B' for (int i = 0; i < NUM_REPEATS; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); } // now press "b" while "a" is autorepeating: press(key_b); TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code()); // hold "a" for autorepeat delay keyscan_delay(ASDF_AUTOREPEAT_TIME_MS); TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); // empty the buffer to make room for 'B' for (int i = 0; i < NUM_REPEATS; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code()); } // and verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } // Pressing and holding 'A' then holding 'B' with repeat key held repeats 'A' then 'B' void repeating_with_a_then_adding_b_repeats_a_then_repeats_b(void) { press(ACTION_REPEAT); press(key_a); TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); // empty the buffer to make room for 'B' for (int i = 0; i < NUM_REPEATS; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) key_a, (uint32_t) asdf_next_code()); } // now press "b" while "a" is autorepeating: press(key_b); TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code()); // hold "a" for NUM_REPEATS repeat cycles: keyscan_delay(NUM_REPEATS * ASDF_REPEAT_TIME_MS); // empty the buffer to make room for 'B' for (int i = 0; i < NUM_REPEATS; i++) { TEST_ASSERT_EQUAL_INT32((int32_t) key_b, (uint32_t) asdf_next_code()); } // and verify there are no more codes in buffer: TEST_ASSERT_EQUAL_INT32((int32_t) ASDF_INVALID_CODE, (int32_t) asdf_next_code()); } int main(void) { UNITY_BEGIN(); RUN_TEST(pressing_a_gives_nothing_before_debounce); RUN_TEST(pressing_a_gives_a); RUN_TEST(pressing_shift_a_gives_shifted_a); RUN_TEST(pressing_caps_a_gives_caps_a); RUN_TEST(pressing_ctrl_a_gives_ctrl_a); RUN_TEST(pressing_rept_a_repeats_a); RUN_TEST(pressing_shift_rept_a_repeats_shifted_a); RUN_TEST(pressing_caps_rept_a_repeats_caps_a); RUN_TEST(holding_a_autorepeats_a); RUN_TEST(holding_a_autorepeats_slow_then_fast); RUN_TEST(pressing_a_then_b_before_debounce_gives_a_then_b); RUN_TEST(test_key_sequence_nkro); RUN_TEST(test_key_sequence_nkro_simultaneous_debounce); RUN_TEST(holding_a_briefly_then_holding_b_gives_a_and_repeats_b); RUN_TEST(holding_a_then_holding_b_autorepeats_a_then_autorepeats_b); RUN_TEST(repeating_with_a_then_adding_b_repeats_a_then_repeats_b); return UNITY_END(); }