diff options
Diffstat (limited to 'tmk_core/common/action_util.c')
-rw-r--r-- | tmk_core/common/action_util.c | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/tmk_core/common/action_util.c b/tmk_core/common/action_util.c new file mode 100644 index 000000000..dbee630d1 --- /dev/null +++ b/tmk_core/common/action_util.c | |||
@@ -0,0 +1,307 @@ | |||
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 "timer.h" | ||
22 | |||
23 | static inline void add_key_byte(uint8_t code); | ||
24 | static inline void del_key_byte(uint8_t code); | ||
25 | #ifdef NKRO_ENABLE | ||
26 | static inline void add_key_bit(uint8_t code); | ||
27 | static inline void del_key_bit(uint8_t code); | ||
28 | #endif | ||
29 | |||
30 | static uint8_t real_mods = 0; | ||
31 | static uint8_t weak_mods = 0; | ||
32 | |||
33 | #ifdef USB_6KRO_ENABLE | ||
34 | #define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS) | ||
35 | #define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS) | ||
36 | #define RO_INC(a) RO_ADD(a, 1) | ||
37 | #define RO_DEC(a) RO_SUB(a, 1) | ||
38 | static int8_t cb_head = 0; | ||
39 | static int8_t cb_tail = 0; | ||
40 | static int8_t cb_count = 0; | ||
41 | #endif | ||
42 | |||
43 | // TODO: pointer variable is not needed | ||
44 | //report_keyboard_t keyboard_report = {}; | ||
45 | report_keyboard_t *keyboard_report = &(report_keyboard_t){}; | ||
46 | |||
47 | #ifndef NO_ACTION_ONESHOT | ||
48 | static int8_t oneshot_mods = 0; | ||
49 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) | ||
50 | static int16_t oneshot_time = 0; | ||
51 | #endif | ||
52 | #endif | ||
53 | |||
54 | |||
55 | void send_keyboard_report(void) { | ||
56 | keyboard_report->mods = real_mods; | ||
57 | keyboard_report->mods |= weak_mods; | ||
58 | #ifndef NO_ACTION_ONESHOT | ||
59 | if (oneshot_mods) { | ||
60 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) | ||
61 | if (TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT) { | ||
62 | dprintf("Oneshot: timeout\n"); | ||
63 | clear_oneshot_mods(); | ||
64 | } | ||
65 | #endif | ||
66 | keyboard_report->mods |= oneshot_mods; | ||
67 | if (has_anykey()) { | ||
68 | clear_oneshot_mods(); | ||
69 | } | ||
70 | } | ||
71 | #endif | ||
72 | host_keyboard_send(keyboard_report); | ||
73 | } | ||
74 | |||
75 | /* key */ | ||
76 | void add_key(uint8_t key) | ||
77 | { | ||
78 | #ifdef NKRO_ENABLE | ||
79 | if (keyboard_nkro) { | ||
80 | add_key_bit(key); | ||
81 | return; | ||
82 | } | ||
83 | #endif | ||
84 | add_key_byte(key); | ||
85 | } | ||
86 | |||
87 | void del_key(uint8_t key) | ||
88 | { | ||
89 | #ifdef NKRO_ENABLE | ||
90 | if (keyboard_nkro) { | ||
91 | del_key_bit(key); | ||
92 | return; | ||
93 | } | ||
94 | #endif | ||
95 | del_key_byte(key); | ||
96 | } | ||
97 | |||
98 | void clear_keys(void) | ||
99 | { | ||
100 | // not clear mods | ||
101 | for (int8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) { | ||
102 | keyboard_report->raw[i] = 0; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | |||
107 | /* modifier */ | ||
108 | uint8_t get_mods(void) { return real_mods; } | ||
109 | void add_mods(uint8_t mods) { real_mods |= mods; } | ||
110 | void del_mods(uint8_t mods) { real_mods &= ~mods; } | ||
111 | void set_mods(uint8_t mods) { real_mods = mods; } | ||
112 | void clear_mods(void) { real_mods = 0; } | ||
113 | |||
114 | /* weak modifier */ | ||
115 | uint8_t get_weak_mods(void) { return weak_mods; } | ||
116 | void add_weak_mods(uint8_t mods) { weak_mods |= mods; } | ||
117 | void del_weak_mods(uint8_t mods) { weak_mods &= ~mods; } | ||
118 | void set_weak_mods(uint8_t mods) { weak_mods = mods; } | ||
119 | void clear_weak_mods(void) { weak_mods = 0; } | ||
120 | |||
121 | /* Oneshot modifier */ | ||
122 | #ifndef NO_ACTION_ONESHOT | ||
123 | void set_oneshot_mods(uint8_t mods) | ||
124 | { | ||
125 | oneshot_mods = mods; | ||
126 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) | ||
127 | oneshot_time = timer_read(); | ||
128 | #endif | ||
129 | } | ||
130 | void clear_oneshot_mods(void) | ||
131 | { | ||
132 | oneshot_mods = 0; | ||
133 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) | ||
134 | oneshot_time = 0; | ||
135 | #endif | ||
136 | } | ||
137 | #endif | ||
138 | |||
139 | |||
140 | |||
141 | |||
142 | /* | ||
143 | * inspect keyboard state | ||
144 | */ | ||
145 | uint8_t has_anykey(void) | ||
146 | { | ||
147 | uint8_t cnt = 0; | ||
148 | for (uint8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) { | ||
149 | if (keyboard_report->raw[i]) | ||
150 | cnt++; | ||
151 | } | ||
152 | return cnt; | ||
153 | } | ||
154 | |||
155 | uint8_t has_anymod(void) | ||
156 | { | ||
157 | return bitpop(real_mods); | ||
158 | } | ||
159 | |||
160 | uint8_t get_first_key(void) | ||
161 | { | ||
162 | #ifdef NKRO_ENABLE | ||
163 | if (keyboard_nkro) { | ||
164 | uint8_t i = 0; | ||
165 | for (; i < KEYBOARD_REPORT_BITS && !keyboard_report->nkro.bits[i]; i++) | ||
166 | ; | ||
167 | return i<<3 | biton(keyboard_report->nkro.bits[i]); | ||
168 | } | ||
169 | #endif | ||
170 | #ifdef USB_6KRO_ENABLE | ||
171 | uint8_t i = cb_head; | ||
172 | do { | ||
173 | if (keyboard_report->keys[i] != 0) { | ||
174 | break; | ||
175 | } | ||
176 | i = RO_INC(i); | ||
177 | } while (i != cb_tail); | ||
178 | return keyboard_report->keys[i]; | ||
179 | #else | ||
180 | return keyboard_report->keys[0]; | ||
181 | #endif | ||
182 | } | ||
183 | |||
184 | |||
185 | |||
186 | /* local functions */ | ||
187 | static inline void add_key_byte(uint8_t code) | ||
188 | { | ||
189 | #ifdef USB_6KRO_ENABLE | ||
190 | int8_t i = cb_head; | ||
191 | int8_t empty = -1; | ||
192 | if (cb_count) { | ||
193 | do { | ||
194 | if (keyboard_report->keys[i] == code) { | ||
195 | return; | ||
196 | } | ||
197 | if (empty == -1 && keyboard_report->keys[i] == 0) { | ||
198 | empty = i; | ||
199 | } | ||
200 | i = RO_INC(i); | ||
201 | } while (i != cb_tail); | ||
202 | if (i == cb_tail) { | ||
203 | if (cb_tail == cb_head) { | ||
204 | // buffer is full | ||
205 | if (empty == -1) { | ||
206 | // pop head when has no empty space | ||
207 | cb_head = RO_INC(cb_head); | ||
208 | cb_count--; | ||
209 | } | ||
210 | else { | ||
211 | // left shift when has empty space | ||
212 | uint8_t offset = 1; | ||
213 | i = RO_INC(empty); | ||
214 | do { | ||
215 | if (keyboard_report->keys[i] != 0) { | ||
216 | keyboard_report->keys[empty] = keyboard_report->keys[i]; | ||
217 | keyboard_report->keys[i] = 0; | ||
218 | empty = RO_INC(empty); | ||
219 | } | ||
220 | else { | ||
221 | offset++; | ||
222 | } | ||
223 | i = RO_INC(i); | ||
224 | } while (i != cb_tail); | ||
225 | cb_tail = RO_SUB(cb_tail, offset); | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | // add to tail | ||
231 | keyboard_report->keys[cb_tail] = code; | ||
232 | cb_tail = RO_INC(cb_tail); | ||
233 | cb_count++; | ||
234 | #else | ||
235 | int8_t i = 0; | ||
236 | int8_t empty = -1; | ||
237 | for (; i < KEYBOARD_REPORT_KEYS; i++) { | ||
238 | if (keyboard_report->keys[i] == code) { | ||
239 | break; | ||
240 | } | ||
241 | if (empty == -1 && keyboard_report->keys[i] == 0) { | ||
242 | empty = i; | ||
243 | } | ||
244 | } | ||
245 | if (i == KEYBOARD_REPORT_KEYS) { | ||
246 | if (empty != -1) { | ||
247 | keyboard_report->keys[empty] = code; | ||
248 | } | ||
249 | } | ||
250 | #endif | ||
251 | } | ||
252 | |||
253 | static inline void del_key_byte(uint8_t code) | ||
254 | { | ||
255 | #ifdef USB_6KRO_ENABLE | ||
256 | uint8_t i = cb_head; | ||
257 | if (cb_count) { | ||
258 | do { | ||
259 | if (keyboard_report->keys[i] == code) { | ||
260 | keyboard_report->keys[i] = 0; | ||
261 | cb_count--; | ||
262 | if (cb_count == 0) { | ||
263 | // reset head and tail | ||
264 | cb_tail = cb_head = 0; | ||
265 | } | ||
266 | if (i == RO_DEC(cb_tail)) { | ||
267 | // left shift when next to tail | ||
268 | do { | ||
269 | cb_tail = RO_DEC(cb_tail); | ||
270 | if (keyboard_report->keys[RO_DEC(cb_tail)] != 0) { | ||
271 | break; | ||
272 | } | ||
273 | } while (cb_tail != cb_head); | ||
274 | } | ||
275 | break; | ||
276 | } | ||
277 | i = RO_INC(i); | ||
278 | } while (i != cb_tail); | ||
279 | } | ||
280 | #else | ||
281 | for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | ||
282 | if (keyboard_report->keys[i] == code) { | ||
283 | keyboard_report->keys[i] = 0; | ||
284 | } | ||
285 | } | ||
286 | #endif | ||
287 | } | ||
288 | |||
289 | #ifdef NKRO_ENABLE | ||
290 | static inline void add_key_bit(uint8_t code) | ||
291 | { | ||
292 | if ((code>>3) < KEYBOARD_REPORT_BITS) { | ||
293 | keyboard_report->nkro.bits[code>>3] |= 1<<(code&7); | ||
294 | } else { | ||
295 | dprintf("add_key_bit: can't add: %02X\n", code); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | static inline void del_key_bit(uint8_t code) | ||
300 | { | ||
301 | if ((code>>3) < KEYBOARD_REPORT_BITS) { | ||
302 | keyboard_report->nkro.bits[code>>3] &= ~(1<<(code&7)); | ||
303 | } else { | ||
304 | dprintf("del_key_bit: can't del: %02X\n", code); | ||
305 | } | ||
306 | } | ||
307 | #endif | ||