encoder.c (4913B)
1 // Copyright 2022-2023 Nick Brassel (@tzarc) 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 4 #include <string.h> 5 #include "action.h" 6 #include "encoder.h" 7 #include "wait.h" 8 9 #ifndef ENCODER_MAP_KEY_DELAY 10 # define ENCODER_MAP_KEY_DELAY TAP_CODE_DELAY 11 #endif 12 13 __attribute__((weak)) bool should_process_encoder(void) { 14 return is_keyboard_master(); 15 } 16 17 static encoder_events_t encoder_events; 18 static bool signal_queue_drain = false; 19 20 void encoder_init(void) { 21 memset(&encoder_events, 0, sizeof(encoder_events)); 22 encoder_driver_init(); 23 } 24 25 static void encoder_queue_drain(void) { 26 encoder_events.tail = encoder_events.head; 27 encoder_events.dequeued = encoder_events.enqueued; 28 } 29 30 static bool encoder_handle_queue(void) { 31 bool changed = false; 32 uint8_t index; 33 bool clockwise; 34 while (encoder_dequeue_event(&index, &clockwise)) { 35 #ifdef ENCODER_MAP_ENABLE 36 37 // The delays below cater for Windows and its wonderful requirements. 38 action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, true) : MAKE_ENCODER_CCW_EVENT(index, true)); 39 # if ENCODER_MAP_KEY_DELAY > 0 40 wait_ms(ENCODER_MAP_KEY_DELAY); 41 # endif // ENCODER_MAP_KEY_DELAY > 0 42 43 action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, false) : MAKE_ENCODER_CCW_EVENT(index, false)); 44 # if ENCODER_MAP_KEY_DELAY > 0 45 wait_ms(ENCODER_MAP_KEY_DELAY); 46 # endif // ENCODER_MAP_KEY_DELAY > 0 47 48 #else // ENCODER_MAP_ENABLE 49 50 encoder_update_kb(index, clockwise); 51 52 #endif // ENCODER_MAP_ENABLE 53 54 changed = true; 55 } 56 return changed; 57 } 58 59 bool encoder_task(void) { 60 bool changed = false; 61 62 #ifdef SPLIT_KEYBOARD 63 // Attempt to process existing encoder events in case split handling has already enqueued events 64 if (should_process_encoder()) { 65 changed |= encoder_handle_queue(); 66 } 67 #endif // SPLIT_KEYBOARD 68 69 if (signal_queue_drain) { 70 signal_queue_drain = false; 71 encoder_queue_drain(); 72 } 73 74 // Let the encoder driver produce events 75 encoder_driver_task(); 76 77 // Process any events that were enqueued 78 if (should_process_encoder()) { 79 changed |= encoder_handle_queue(); 80 } 81 82 return changed; 83 } 84 85 bool encoder_queue_full_advanced(encoder_events_t *events) { 86 return events->tail == (events->head + 1) % MAX_QUEUED_ENCODER_EVENTS; 87 } 88 89 bool encoder_queue_full(void) { 90 return encoder_queue_full_advanced(&encoder_events); 91 } 92 93 bool encoder_queue_empty_advanced(encoder_events_t *events) { 94 return events->head == events->tail; 95 } 96 97 bool encoder_queue_empty(void) { 98 return encoder_queue_empty_advanced(&encoder_events); 99 } 100 101 bool encoder_queue_event_advanced(encoder_events_t *events, uint8_t index, bool clockwise) { 102 // Drop out if we're full 103 if (encoder_queue_full_advanced(events)) { 104 return false; 105 } 106 107 // Append the event 108 encoder_event_t new_event = {.index = index, .clockwise = clockwise ? 1 : 0}; 109 events->queue[events->head] = new_event; 110 111 // Increment the head index 112 events->head = (events->head + 1) % MAX_QUEUED_ENCODER_EVENTS; 113 events->enqueued++; 114 115 return true; 116 } 117 118 bool encoder_dequeue_event_advanced(encoder_events_t *events, uint8_t *index, bool *clockwise) { 119 if (encoder_queue_empty_advanced(events)) { 120 return false; 121 } 122 123 // Retrieve the event 124 encoder_event_t event = events->queue[events->tail]; 125 *index = event.index; 126 *clockwise = event.clockwise; 127 128 // Increment the tail index 129 events->tail = (events->tail + 1) % MAX_QUEUED_ENCODER_EVENTS; 130 events->dequeued++; 131 132 return true; 133 } 134 135 bool encoder_queue_event(uint8_t index, bool clockwise) { 136 return encoder_queue_event_advanced(&encoder_events, index, clockwise); 137 } 138 139 bool encoder_dequeue_event(uint8_t *index, bool *clockwise) { 140 return encoder_dequeue_event_advanced(&encoder_events, index, clockwise); 141 } 142 143 void encoder_retrieve_events(encoder_events_t *events) { 144 memcpy(events, &encoder_events, sizeof(encoder_events)); 145 } 146 147 void encoder_signal_queue_drain(void) { 148 signal_queue_drain = true; 149 } 150 151 __attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) { 152 return true; 153 } 154 155 __attribute__((weak)) bool encoder_update_kb(uint8_t index, bool clockwise) { 156 bool res = encoder_update_user(index, clockwise); 157 #if !defined(ENCODER_TESTS) 158 if (res) { 159 if (clockwise) { 160 # if defined(EXTRAKEY_ENABLE) 161 tap_code_delay(KC_VOLU, 10); 162 # elif defined(MOUSEKEY_ENABLE) 163 tap_code_delay(QK_MOUSE_WHEEL_UP, 10); 164 # else 165 tap_code_delay(KC_PGDN, 10); 166 # endif 167 } else { 168 # if defined(EXTRAKEY_ENABLE) 169 tap_code_delay(KC_VOLD, 10); 170 # elif defined(MOUSEKEY_ENABLE) 171 tap_code_delay(QK_MOUSE_WHEEL_DOWN, 10); 172 # else 173 tap_code_delay(KC_PGUP, 10); 174 # endif 175 } 176 } 177 #endif // ENCODER_TESTS 178 return res; 179 }