summaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
authorStefan Kerkmann <karlk90@pm.me>2022-08-06 12:51:13 +0200
committerGitHub <noreply@github.com>2022-08-06 20:51:13 +1000
commitf27b617f36d55ac5469247016a1b79304f892366 (patch)
tree3334b3b4cf653fa131eef0729529c06450e12168 /quantum
parente9f9f99a3374ad46e9a2baf2fe35c3f1d0715d4b (diff)
downloadqmk_firmware-f27b617f36d55ac5469247016a1b79304f892366.tar.gz
qmk_firmware-f27b617f36d55ac5469247016a1b79304f892366.zip
[Core] Process all changed keys in one scan loop, deprecate `QMK_KEYS_PER_SCAN` (#15292)
Diffstat (limited to 'quantum')
-rw-r--r--quantum/keyboard.c138
-rw-r--r--quantum/keyboard.h8
2 files changed, 81 insertions, 65 deletions
diff --git a/quantum/keyboard.c b/quantum/keyboard.c
index 2364e3167b..1c62a43d9d 100644
--- a/quantum/keyboard.c
+++ b/quantum/keyboard.c
@@ -212,6 +212,12 @@ static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata) {
return false;
}
+#else
+
+static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata) {
+ return false;
+}
+
#endif
/** \brief matrix_setup
@@ -426,64 +432,74 @@ void switch_events(uint8_t row, uint8_t col, bool pressed) {
#endif
}
-/** \brief Perform scan of keyboard matrix
+/**
+ * @brief Generates a tick event at a maximum rate of 1KHz that drives the
+ * internal QMK state machine.
+ */
+static inline void generate_tick_event(void) {
+ static uint16_t last_tick = 0;
+ const uint16_t now = timer_read();
+ if (TIMER_DIFF_16(now, last_tick) != 0) {
+ action_exec(TICK_EVENT);
+ last_tick = now;
+ }
+}
+
+/**
+ * @brief This task scans the keyboards matrix and processes any key presses
+ * that occur.
*
- * Any detected changes in state are sent out as part of the processing
+ * @return true Matrix did change
+ * @return false Matrix didn't change
*/
-bool matrix_scan_task(void) {
- static matrix_row_t matrix_prev[MATRIX_ROWS];
- matrix_row_t matrix_row = 0;
- matrix_row_t matrix_change = 0;
-#ifdef QMK_KEYS_PER_SCAN
- uint8_t keys_processed = 0;
-#endif
+static bool matrix_task(void) {
+ static matrix_row_t matrix_previous[MATRIX_ROWS];
- uint8_t matrix_changed = matrix_scan();
- if (matrix_changed) last_matrix_activity_trigger();
+ matrix_scan();
- for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
- matrix_row = matrix_get_row(r);
- matrix_change = matrix_row ^ matrix_prev[r];
- if (matrix_change) {
-#ifdef MATRIX_HAS_GHOST
- if (has_ghost_in_row(r, matrix_row)) {
- continue;
- }
-#endif
- if (debug_matrix) matrix_print();
- matrix_row_t col_mask = 1;
- for (uint8_t c = 0; c < MATRIX_COLS; c++, col_mask <<= 1) {
- if (matrix_change & col_mask) {
- if (should_process_keypress()) {
- action_exec((keyevent_t){
- .key = (keypos_t){.row = r, .col = c}, .pressed = (matrix_row & col_mask), .time = (timer_read() | 1) /* time should not be 0 */
- });
- }
- // record a processed key
- matrix_prev[r] ^= col_mask;
-
- switch_events(r, c, (matrix_row & col_mask));
-
-#ifdef QMK_KEYS_PER_SCAN
- // only jump out if we have processed "enough" keys.
- if (++keys_processed >= QMK_KEYS_PER_SCAN)
-#endif
- // process a key per task call
- goto MATRIX_LOOP_END;
+ bool matrix_changed = false;
+ for (uint8_t row = 0; row < MATRIX_ROWS && !matrix_changed; row++) {
+ matrix_changed |= matrix_previous[row] ^ matrix_get_row(row);
+ }
+
+ matrix_scan_perf_task();
+
+ // Short-circuit the complete matrix processing if it is not necessary
+ if (!matrix_changed) {
+ generate_tick_event();
+ return matrix_changed;
+ }
+
+ if (debug_config.matrix) {
+ matrix_print();
+ }
+
+ const bool process_keypress = should_process_keypress();
+
+ for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+ const matrix_row_t current_row = matrix_get_row(row);
+ const matrix_row_t row_changes = current_row ^ matrix_previous[row];
+
+ if (!row_changes || has_ghost_in_row(row, current_row)) {
+ continue;
+ }
+
+ matrix_row_t col_mask = 1;
+ for (uint8_t col = 0; col < MATRIX_COLS; col++, col_mask <<= 1) {
+ if (row_changes & col_mask) {
+ const bool key_pressed = current_row & col_mask;
+
+ if (process_keypress) {
+ action_exec(MAKE_KEYEVENT(row, col, key_pressed));
}
+
+ switch_events(row, col, key_pressed);
}
}
- }
- // call with pseudo tick event when no real key event.
-#ifdef QMK_KEYS_PER_SCAN
- // we can get here with some keys processed now.
- if (!keys_processed)
-#endif
- action_exec(TICK_EVENT);
-MATRIX_LOOP_END:
+ matrix_previous[row] = current_row;
+ }
- matrix_scan_perf_task();
return matrix_changed;
}
@@ -562,20 +578,12 @@ void quantum_task(void) {
#endif
}
-/** \brief Keyboard task: Do keyboard routine jobs
- *
- * Do routine keyboard jobs:
- *
- * * scan matrix
- * * handle mouse movements
- * * handle midi commands
- * * light LEDs
- *
- * This is repeatedly called as fast as possible.
- */
+/** \brief Main task that is repeatedly called as fast as possible. */
void keyboard_task(void) {
- bool matrix_changed = matrix_scan_task();
- (void)matrix_changed;
+ const bool matrix_changed = matrix_task();
+ if (matrix_changed) {
+ last_matrix_activity_trigger();
+ }
quantum_task();
@@ -597,8 +605,10 @@ void keyboard_task(void) {
#endif
#ifdef ENCODER_ENABLE
- bool encoders_changed = encoder_read();
- if (encoders_changed) last_encoder_activity_trigger();
+ const bool encoders_changed = encoder_read();
+ if (encoders_changed) {
+ last_encoder_activity_trigger();
+ }
#endif
#ifdef OLED_ENABLE
diff --git a/quantum/keyboard.h b/quantum/keyboard.h
index fe0736a515..86ce65aac1 100644
--- a/quantum/keyboard.h
+++ b/quantum/keyboard.h
@@ -71,9 +71,15 @@ static inline bool IS_RELEASED(keyevent_t event) {
/* Common keyevent object factory */
#define MAKE_KEYPOS(row_num, col_num) ((keypos_t){.row = (row_num), .col = (col_num)})
+
+/**
+ * @brief Constructs a key event for a pressed or released key.
+ */
#define MAKE_KEYEVENT(row_num, col_num, press) ((keyevent_t){.key = MAKE_KEYPOS((row_num), (col_num)), .pressed = (press), .time = (timer_read() | 1)})
-/* Tick event */
+/**
+ * @brief Constructs a internal tick event that is used to drive the internal QMK state machine.
+ */
#define TICK_EVENT MAKE_KEYEVENT(KEYLOC_TICK, KEYLOC_TICK, false)
#ifdef ENCODER_MAP_ENABLE