summaryrefslogtreecommitdiff
path: root/quantum/encoder.c
blob: 0a48ac9a07b50fa3a6d84a9215c03b6f8d4499ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2022-2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later

#include <string.h>
#include "action.h"
#include "encoder.h"
#include "wait.h"

#ifndef ENCODER_MAP_KEY_DELAY
#    define ENCODER_MAP_KEY_DELAY TAP_CODE_DELAY
#endif

__attribute__((weak)) bool should_process_encoder(void) {
    return is_keyboard_master();
}

static encoder_events_t encoder_events;
static bool             signal_queue_drain = false;

void encoder_init(void) {
    memset(&encoder_events, 0, sizeof(encoder_events));
    encoder_driver_init();
}

static void encoder_queue_drain(void) {
    encoder_events.tail     = encoder_events.head;
    encoder_events.dequeued = encoder_events.enqueued;
}

static bool encoder_handle_queue(void) {
    bool    changed = false;
    uint8_t index;
    bool    clockwise;
    while (encoder_dequeue_event(&index, &clockwise)) {
#ifdef ENCODER_MAP_ENABLE

        // The delays below cater for Windows and its wonderful requirements.
        action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, true) : MAKE_ENCODER_CCW_EVENT(index, true));
#    if ENCODER_MAP_KEY_DELAY > 0
        wait_ms(ENCODER_MAP_KEY_DELAY);
#    endif // ENCODER_MAP_KEY_DELAY > 0

        action_exec(clockwise ? MAKE_ENCODER_CW_EVENT(index, false) : MAKE_ENCODER_CCW_EVENT(index, false));
#    if ENCODER_MAP_KEY_DELAY > 0
        wait_ms(ENCODER_MAP_KEY_DELAY);
#    endif // ENCODER_MAP_KEY_DELAY > 0

#else // ENCODER_MAP_ENABLE

        encoder_update_kb(index, clockwise);

#endif // ENCODER_MAP_ENABLE

        changed = true;
    }
    return changed;
}

bool encoder_task(void) {
    bool changed = false;

#ifdef SPLIT_KEYBOARD
    // Attempt to process existing encoder events in case split handling has already enqueued events
    if (should_process_encoder()) {
        changed |= encoder_handle_queue();
    }
#endif // SPLIT_KEYBOARD

    if (signal_queue_drain) {
        signal_queue_drain = false;
        encoder_queue_drain();
    }

    // Let the encoder driver produce events
    encoder_driver_task();

    // Process any events that were enqueued
    if (should_process_encoder()) {
        changed |= encoder_handle_queue();
    }

    return changed;
}

bool encoder_queue_full_advanced(encoder_events_t *events) {
    return events->head == (events->tail - 1) % MAX_QUEUED_ENCODER_EVENTS;
}

bool encoder_queue_full(void) {
    return encoder_queue_full_advanced(&encoder_events);
}

bool encoder_queue_empty_advanced(encoder_events_t *events) {
    return events->head == events->tail;
}

bool encoder_queue_empty(void) {
    return encoder_queue_empty_advanced(&encoder_events);
}

bool encoder_queue_event_advanced(encoder_events_t *events, uint8_t index, bool clockwise) {
    // Drop out if we're full
    if (encoder_queue_full_advanced(events)) {
        return false;
    }

    // Append the event
    encoder_event_t new_event   = {.index = index, .clockwise = clockwise ? 1 : 0};
    events->queue[events->head] = new_event;

    // Increment the head index
    events->head = (events->head + 1) % MAX_QUEUED_ENCODER_EVENTS;
    events->enqueued++;

    return true;
}

bool encoder_dequeue_event_advanced(encoder_events_t *events, uint8_t *index, bool *clockwise) {
    if (encoder_queue_empty_advanced(events)) {
        return false;
    }

    // Retrieve the event
    encoder_event_t event = events->queue[events->tail];
    *index                = event.index;
    *clockwise            = event.clockwise;

    // Increment the tail index
    events->tail = (events->tail + 1) % MAX_QUEUED_ENCODER_EVENTS;
    events->dequeued++;

    return true;
}

bool encoder_queue_event(uint8_t index, bool clockwise) {
    return encoder_queue_event_advanced(&encoder_events, index, clockwise);
}

bool encoder_dequeue_event(uint8_t *index, bool *clockwise) {
    return encoder_dequeue_event_advanced(&encoder_events, index, clockwise);
}

void encoder_retrieve_events(encoder_events_t *events) {
    memcpy(events, &encoder_events, sizeof(encoder_events));
}

void encoder_signal_queue_drain(void) {
    signal_queue_drain = true;
}

__attribute__((weak)) bool encoder_update_user(uint8_t index, bool clockwise) {
    return true;
}

__attribute__((weak)) bool encoder_update_kb(uint8_t index, bool clockwise) {
    bool res = encoder_update_user(index, clockwise);
#if !defined(ENCODER_TESTS)
    if (res) {
        if (clockwise) {
#    if defined(EXTRAKEY_ENABLE)
            tap_code_delay(KC_VOLU, 10);
#    elif defined(MOUSEKEY_ENABLE)
            tap_code_delay(KC_MS_WH_UP, 10);
#    else
            tap_code_delay(KC_PGDN, 10);
#    endif
        } else {
#    if defined(EXTRAKEY_ENABLE)
            tap_code_delay(KC_VOLD, 10);
#    elif defined(MOUSEKEY_ENABLE)
            tap_code_delay(KC_MS_WH_DOWN, 10);
#    else
            tap_code_delay(KC_PGUP, 10);
#    endif
        }
    }
#endif // ENCODER_TESTS
    return res;
}