Parent directory

encoder.c

4913 bytes
  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
 17static encoder_events_t encoder_events;
 18static bool             signal_queue_drain = false;
 19
 20void encoder_init(void) {
 21    memset(&encoder_events, 0, sizeof(encoder_events));
 22    encoder_driver_init();
 23}
 24
 25static void encoder_queue_drain(void) {
 26    encoder_events.tail     = encoder_events.head;
 27    encoder_events.dequeued = encoder_events.enqueued;
 28}
 29
 30static 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
 59bool 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
 85bool encoder_queue_full_advanced(encoder_events_t *events) {
 86    return events->tail == (events->head + 1) % MAX_QUEUED_ENCODER_EVENTS;
 87}
 88
 89bool encoder_queue_full(void) {
 90    return encoder_queue_full_advanced(&encoder_events);
 91}
 92
 93bool encoder_queue_empty_advanced(encoder_events_t *events) {
 94    return events->head == events->tail;
 95}
 96
 97bool encoder_queue_empty(void) {
 98    return encoder_queue_empty_advanced(&encoder_events);
 99}
100
101bool 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
118bool 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
135bool encoder_queue_event(uint8_t index, bool clockwise) {
136    return encoder_queue_event_advanced(&encoder_events, index, clockwise);
137}
138
139bool encoder_dequeue_event(uint8_t *index, bool *clockwise) {
140    return encoder_dequeue_event_advanced(&encoder_events, index, clockwise);
141}
142
143void encoder_retrieve_events(encoder_events_t *events) {
144    memcpy(events, &encoder_events, sizeof(encoder_events));
145}
146
147void 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}