]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/common/action_util.c
Add double arrow Unicode characters to FMU layer
[qmk_firmware.git] / tmk_core / common / action_util.c
1 /*
2 Copyright 2013 Jun Wako <wakojun@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "host.h"
18 #include "report.h"
19 #include "debug.h"
20 #include "action_util.h"
21 #include "action_layer.h"
22 #include "timer.h"
23
24 static inline void add_key_byte(uint8_t code);
25 static inline void del_key_byte(uint8_t code);
26 #ifdef NKRO_ENABLE
27 static inline void add_key_bit(uint8_t code);
28 static inline void del_key_bit(uint8_t code);
29 #endif
30
31 static uint8_t real_mods = 0;
32 static uint8_t weak_mods = 0;
33 static uint8_t macro_mods = 0;
34
35 #ifdef USB_6KRO_ENABLE
36 #define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS)
37 #define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS)
38 #define RO_INC(a) RO_ADD(a, 1)
39 #define RO_DEC(a) RO_SUB(a, 1)
40 static int8_t cb_head = 0;
41 static int8_t cb_tail = 0;
42 static int8_t cb_count = 0;
43 #endif
44
45 // TODO: pointer variable is not needed
46 //report_keyboard_t keyboard_report = {};
47 report_keyboard_t *keyboard_report = &(report_keyboard_t){};
48
49 #ifndef NO_ACTION_ONESHOT
50 static int8_t oneshot_mods = 0;
51 static int8_t oneshot_locked_mods = 0;
52 int8_t get_oneshot_locked_mods(void) { return oneshot_locked_mods; }
53 void set_oneshot_locked_mods(int8_t mods) { oneshot_locked_mods = mods; }
54 void clear_oneshot_locked_mods(void) { oneshot_locked_mods = 0; }
55 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
56 static int16_t oneshot_time = 0;
57 inline bool has_oneshot_mods_timed_out() {
58   return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT;
59 }
60 #endif
61 #endif
62
63 /* oneshot layer */
64 #ifndef NO_ACTION_ONESHOT
65 /* oneshot_layer_data bits
66 * LLLL LSSS
67 * where:
68 *   L => are layer bits
69 *   S => oneshot state bits
70 */
71 static int8_t oneshot_layer_data = 0;
72
73 inline uint8_t get_oneshot_layer(void) { return oneshot_layer_data >> 3; }
74 inline uint8_t get_oneshot_layer_state(void) { return oneshot_layer_data & 0b111; }
75
76 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
77 static int16_t oneshot_layer_time = 0;
78 inline bool has_oneshot_layer_timed_out() {
79     return TIMER_DIFF_16(timer_read(), oneshot_layer_time) >= ONESHOT_TIMEOUT &&
80         !(get_oneshot_layer_state() & ONESHOT_TOGGLED);
81 }
82 #endif
83
84 /* Oneshot layer */
85 void set_oneshot_layer(uint8_t layer, uint8_t state)
86 {
87     oneshot_layer_data = layer << 3 | state;
88     layer_on(layer);
89 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
90     oneshot_layer_time = timer_read();
91 #endif
92 }
93 void reset_oneshot_layer(void) {
94     oneshot_layer_data = 0;
95 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
96     oneshot_layer_time = 0;
97 #endif
98 }
99 void clear_oneshot_layer_state(oneshot_fullfillment_t state)
100 {
101     uint8_t start_state = oneshot_layer_data;
102     oneshot_layer_data &= ~state;
103     if (!get_oneshot_layer_state() && start_state != oneshot_layer_data) {
104         layer_off(get_oneshot_layer());
105 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
106     oneshot_layer_time = 0;
107 #endif
108     }
109 }
110 bool is_oneshot_layer_active(void)
111 {
112     return get_oneshot_layer_state();
113 }
114 #endif
115
116 void send_keyboard_report(void) {
117     keyboard_report->mods  = real_mods;
118     keyboard_report->mods |= weak_mods;
119     keyboard_report->mods |= macro_mods;
120 #ifndef NO_ACTION_ONESHOT
121     if (oneshot_mods) {
122 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
123         if (has_oneshot_mods_timed_out()) {
124             dprintf("Oneshot: timeout\n");
125             clear_oneshot_mods();
126         }
127 #endif
128         keyboard_report->mods |= oneshot_mods;
129         if (has_anykey()) {
130             clear_oneshot_mods();
131         }
132     }
133
134 #endif
135     host_keyboard_send(keyboard_report);
136 }
137
138 /* key */
139 void add_key(uint8_t key)
140 {
141 #ifdef NKRO_ENABLE
142     if (keyboard_protocol && keyboard_nkro) {
143         add_key_bit(key);
144         return;
145     }
146 #endif
147     add_key_byte(key);
148 }
149
150 void del_key(uint8_t key)
151 {
152 #ifdef NKRO_ENABLE
153     if (keyboard_protocol && keyboard_nkro) {
154         del_key_bit(key);
155         return;
156     }
157 #endif
158     del_key_byte(key);
159 }
160
161 void clear_keys(void)
162 {
163     // not clear mods
164     for (int8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) {
165         keyboard_report->raw[i] = 0;
166     }
167 }
168
169
170 /* modifier */
171 uint8_t get_mods(void) { return real_mods; }
172 void add_mods(uint8_t mods) { real_mods |= mods; }
173 void del_mods(uint8_t mods) { real_mods &= ~mods; }
174 void set_mods(uint8_t mods) { real_mods = mods; }
175 void clear_mods(void) { real_mods = 0; }
176
177 /* weak modifier */
178 uint8_t get_weak_mods(void) { return weak_mods; }
179 void add_weak_mods(uint8_t mods) { weak_mods |= mods; }
180 void del_weak_mods(uint8_t mods) { weak_mods &= ~mods; }
181 void set_weak_mods(uint8_t mods) { weak_mods = mods; }
182 void clear_weak_mods(void) { weak_mods = 0; }
183
184 /* macro modifier */
185 uint8_t get_macro_mods(void) { return macro_mods; }
186 void add_macro_mods(uint8_t mods) { macro_mods |= mods; }
187 void del_macro_mods(uint8_t mods) { macro_mods &= ~mods; }
188 void set_macro_mods(uint8_t mods) { macro_mods = mods; }
189 void clear_macro_mods(void) { macro_mods = 0; }
190
191 /* Oneshot modifier */
192 #ifndef NO_ACTION_ONESHOT
193 void set_oneshot_mods(uint8_t mods)
194 {
195     oneshot_mods = mods;
196 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
197     oneshot_time = timer_read();
198 #endif
199 }
200 void clear_oneshot_mods(void)
201 {
202     oneshot_mods = 0;
203 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
204     oneshot_time = 0;
205 #endif
206 }
207 uint8_t get_oneshot_mods(void)
208 {
209     return oneshot_mods;
210 }
211 #endif
212
213 /*
214  * inspect keyboard state
215  */
216 uint8_t has_anykey(void)
217 {
218     uint8_t cnt = 0;
219     for (uint8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) {
220         if (keyboard_report->raw[i])
221             cnt++;
222     }
223     return cnt;
224 }
225
226 uint8_t has_anymod(void)
227 {
228     return bitpop(real_mods);
229 }
230
231 uint8_t get_first_key(void)
232 {
233 #ifdef NKRO_ENABLE
234     if (keyboard_protocol && keyboard_nkro) {
235         uint8_t i = 0;
236         for (; i < KEYBOARD_REPORT_BITS && !keyboard_report->nkro.bits[i]; i++)
237             ;
238         return i<<3 | biton(keyboard_report->nkro.bits[i]);
239     }
240 #endif
241 #ifdef USB_6KRO_ENABLE
242     uint8_t i = cb_head;
243     do {
244         if (keyboard_report->keys[i] != 0) {
245             break;
246         }
247         i = RO_INC(i);
248     } while (i != cb_tail);
249     return keyboard_report->keys[i];
250 #else
251     return keyboard_report->keys[0];
252 #endif
253 }
254
255
256
257 /* local functions */
258 static inline void add_key_byte(uint8_t code)
259 {
260 #ifdef USB_6KRO_ENABLE
261     int8_t i = cb_head;
262     int8_t empty = -1;
263     if (cb_count) {
264         do {
265             if (keyboard_report->keys[i] == code) {
266                 return;
267             }
268             if (empty == -1 && keyboard_report->keys[i] == 0) {
269                 empty = i;
270             }
271             i = RO_INC(i);
272         } while (i != cb_tail);
273         if (i == cb_tail) {
274             if (cb_tail == cb_head) {
275                 // buffer is full
276                 if (empty == -1) {
277                     // pop head when has no empty space
278                     cb_head = RO_INC(cb_head);
279                     cb_count--;
280                 }
281                 else {
282                     // left shift when has empty space
283                     uint8_t offset = 1;
284                     i = RO_INC(empty);
285                     do {
286                         if (keyboard_report->keys[i] != 0) {
287                             keyboard_report->keys[empty] = keyboard_report->keys[i];
288                             keyboard_report->keys[i] = 0;
289                             empty = RO_INC(empty);
290                         }
291                         else {
292                             offset++;
293                         }
294                         i = RO_INC(i);
295                     } while (i != cb_tail);
296                     cb_tail = RO_SUB(cb_tail, offset);
297                 }
298             }
299         }
300     }
301     // add to tail
302     keyboard_report->keys[cb_tail] = code;
303     cb_tail = RO_INC(cb_tail);
304     cb_count++;
305 #else
306     int8_t i = 0;
307     int8_t empty = -1;
308     for (; i < KEYBOARD_REPORT_KEYS; i++) {
309         if (keyboard_report->keys[i] == code) {
310             break;
311         }
312         if (empty == -1 && keyboard_report->keys[i] == 0) {
313             empty = i;
314         }
315     }
316     if (i == KEYBOARD_REPORT_KEYS) {
317         if (empty != -1) {
318             keyboard_report->keys[empty] = code;
319         }
320     }
321 #endif
322 }
323
324 static inline void del_key_byte(uint8_t code)
325 {
326 #ifdef USB_6KRO_ENABLE
327     uint8_t i = cb_head;
328     if (cb_count) {
329         do {
330             if (keyboard_report->keys[i] == code) {
331                 keyboard_report->keys[i] = 0;
332                 cb_count--;
333                 if (cb_count == 0) {
334                     // reset head and tail
335                     cb_tail = cb_head = 0;
336                 }
337                 if (i == RO_DEC(cb_tail)) {
338                     // left shift when next to tail
339                     do {
340                         cb_tail = RO_DEC(cb_tail);
341                         if (keyboard_report->keys[RO_DEC(cb_tail)] != 0) {
342                             break;
343                         }
344                     } while (cb_tail != cb_head);
345                 }
346                 break;
347             }
348             i = RO_INC(i);
349         } while (i != cb_tail);
350     }
351 #else
352     for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
353         if (keyboard_report->keys[i] == code) {
354             keyboard_report->keys[i] = 0;
355         }
356     }
357 #endif
358 }
359
360 #ifdef NKRO_ENABLE
361 static inline void add_key_bit(uint8_t code)
362 {
363     if ((code>>3) < KEYBOARD_REPORT_BITS) {
364         keyboard_report->nkro.bits[code>>3] |= 1<<(code&7);
365     } else {
366         dprintf("add_key_bit: can't add: %02X\n", code);
367     }
368 }
369
370 static inline void del_key_bit(uint8_t code)
371 {
372     if ((code>>3) < KEYBOARD_REPORT_BITS) {
373         keyboard_report->nkro.bits[code>>3] &= ~(1<<(code&7));
374     } else {
375         dprintf("del_key_bit: can't del: %02X\n", code);
376     }
377 }
378 #endif