Commit | Line | Data |
---|---|---|
a074364c | 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" | |
74e97eef | 21 | #include "action_layer.h" |
a074364c | 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; | |
b7a81f04 | 33 | static uint8_t macro_mods = 0; |
a074364c | 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; | |
74e97eef TA |
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; } | |
a074364c | 55 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) |
56 | static int16_t oneshot_time = 0; | |
74e97eef TA |
57 | inline bool has_oneshot_mods_timed_out() { |
58 | return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT; | |
59 | } | |
a074364c | 60 | #endif |
61 | #endif | |
62 | ||
74e97eef TA |
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 | |
a074364c | 115 | |
116 | void send_keyboard_report(void) { | |
117 | keyboard_report->mods = real_mods; | |
118 | keyboard_report->mods |= weak_mods; | |
b7a81f04 | 119 | keyboard_report->mods |= macro_mods; |
a074364c | 120 | #ifndef NO_ACTION_ONESHOT |
121 | if (oneshot_mods) { | |
122 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) | |
74e97eef | 123 | if (has_oneshot_mods_timed_out()) { |
a074364c | 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 | } | |
74e97eef | 133 | |
a074364c | 134 | #endif |
135 | host_keyboard_send(keyboard_report); | |
136 | } | |
137 | ||
138 | /* key */ | |
139 | void add_key(uint8_t key) | |
140 | { | |
141 | #ifdef NKRO_ENABLE | |
ed9766a7 | 142 | if (keyboard_protocol && keyboard_nkro) { |
a074364c | 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 | |
ed9766a7 | 153 | if (keyboard_protocol && keyboard_nkro) { |
a074364c | 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 | ||
b7a81f04 DL |
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 | ||
a074364c | 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 | } | |
74e97eef TA |
207 | uint8_t get_oneshot_mods(void) |
208 | { | |
209 | return oneshot_mods; | |
210 | } | |
a074364c | 211 | #endif |
212 | ||
a074364c | 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 | |
ed9766a7 | 234 | if (keyboard_protocol && keyboard_nkro) { |
a074364c | 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 |