Add One Shot Key callbacks (#4697)
[jackhill/qmk/firmware.git] / tmk_core / common / report.c
1 /* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include "report.h"
18 #include "host.h"
19 #include "keycode_config.h"
20 #include "debug.h"
21 #include "util.h"
22 #include <string.h>
23
24 /** \brief has_anykey
25 *
26 * FIXME: Needs doc
27 */
28 uint8_t has_anykey(report_keyboard_t* keyboard_report)
29 {
30 uint8_t cnt = 0;
31 uint8_t *p = keyboard_report->keys;
32 uint8_t lp = sizeof(keyboard_report->keys);
33 #ifdef NKRO_ENABLE
34 if (keyboard_protocol && keymap_config.nkro) {
35 p = keyboard_report->nkro.bits;
36 lp = sizeof(keyboard_report->nkro.bits);
37 }
38 #endif
39 while (lp--) {
40 if (*p++)
41 cnt++;
42 }
43 return cnt;
44 }
45
46 /** \brief get_first_key
47 *
48 * FIXME: Needs doc
49 */
50 uint8_t get_first_key(report_keyboard_t* keyboard_report)
51 {
52 #ifdef NKRO_ENABLE
53 if (keyboard_protocol && keymap_config.nkro) {
54 uint8_t i = 0;
55 for (; i < KEYBOARD_REPORT_BITS && !keyboard_report->nkro.bits[i]; i++)
56 ;
57 return i<<3 | biton(keyboard_report->nkro.bits[i]);
58 }
59 #endif
60 #ifdef USB_6KRO_ENABLE
61 uint8_t i = cb_head;
62 do {
63 if (keyboard_report->keys[i] != 0) {
64 break;
65 }
66 i = RO_INC(i);
67 } while (i != cb_tail);
68 return keyboard_report->keys[i];
69 #else
70 return keyboard_report->keys[0];
71 #endif
72 }
73
74 /** \brief add key byte
75 *
76 * FIXME: Needs doc
77 */
78 void add_key_byte(report_keyboard_t* keyboard_report, uint8_t code)
79 {
80 #ifdef USB_6KRO_ENABLE
81 int8_t i = cb_head;
82 int8_t empty = -1;
83 if (cb_count) {
84 do {
85 if (keyboard_report->keys[i] == code) {
86 return;
87 }
88 if (empty == -1 && keyboard_report->keys[i] == 0) {
89 empty = i;
90 }
91 i = RO_INC(i);
92 } while (i != cb_tail);
93 if (i == cb_tail) {
94 if (cb_tail == cb_head) {
95 // buffer is full
96 if (empty == -1) {
97 // pop head when has no empty space
98 cb_head = RO_INC(cb_head);
99 cb_count--;
100 }
101 else {
102 // left shift when has empty space
103 uint8_t offset = 1;
104 i = RO_INC(empty);
105 do {
106 if (keyboard_report->keys[i] != 0) {
107 keyboard_report->keys[empty] = keyboard_report->keys[i];
108 keyboard_report->keys[i] = 0;
109 empty = RO_INC(empty);
110 }
111 else {
112 offset++;
113 }
114 i = RO_INC(i);
115 } while (i != cb_tail);
116 cb_tail = RO_SUB(cb_tail, offset);
117 }
118 }
119 }
120 }
121 // add to tail
122 keyboard_report->keys[cb_tail] = code;
123 cb_tail = RO_INC(cb_tail);
124 cb_count++;
125 #else
126 int8_t i = 0;
127 int8_t empty = -1;
128 for (; i < KEYBOARD_REPORT_KEYS; i++) {
129 if (keyboard_report->keys[i] == code) {
130 break;
131 }
132 if (empty == -1 && keyboard_report->keys[i] == 0) {
133 empty = i;
134 }
135 }
136 if (i == KEYBOARD_REPORT_KEYS) {
137 if (empty != -1) {
138 keyboard_report->keys[empty] = code;
139 }
140 }
141 #endif
142 }
143
144 /** \brief del key byte
145 *
146 * FIXME: Needs doc
147 */
148 void del_key_byte(report_keyboard_t* keyboard_report, uint8_t code)
149 {
150 #ifdef USB_6KRO_ENABLE
151 uint8_t i = cb_head;
152 if (cb_count) {
153 do {
154 if (keyboard_report->keys[i] == code) {
155 keyboard_report->keys[i] = 0;
156 cb_count--;
157 if (cb_count == 0) {
158 // reset head and tail
159 cb_tail = cb_head = 0;
160 }
161 if (i == RO_DEC(cb_tail)) {
162 // left shift when next to tail
163 do {
164 cb_tail = RO_DEC(cb_tail);
165 if (keyboard_report->keys[RO_DEC(cb_tail)] != 0) {
166 break;
167 }
168 } while (cb_tail != cb_head);
169 }
170 break;
171 }
172 i = RO_INC(i);
173 } while (i != cb_tail);
174 }
175 #else
176 for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
177 if (keyboard_report->keys[i] == code) {
178 keyboard_report->keys[i] = 0;
179 }
180 }
181 #endif
182 }
183
184 #ifdef NKRO_ENABLE
185 /** \brief add key bit
186 *
187 * FIXME: Needs doc
188 */
189 void add_key_bit(report_keyboard_t* keyboard_report, uint8_t code)
190 {
191 if ((code>>3) < KEYBOARD_REPORT_BITS) {
192 keyboard_report->nkro.bits[code>>3] |= 1<<(code&7);
193 } else {
194 dprintf("add_key_bit: can't add: %02X\n", code);
195 }
196 }
197
198 /** \brief del key bit
199 *
200 * FIXME: Needs doc
201 */
202 void del_key_bit(report_keyboard_t* keyboard_report, uint8_t code)
203 {
204 if ((code>>3) < KEYBOARD_REPORT_BITS) {
205 keyboard_report->nkro.bits[code>>3] &= ~(1<<(code&7));
206 } else {
207 dprintf("del_key_bit: can't del: %02X\n", code);
208 }
209 }
210 #endif
211
212 /** \brief add key to report
213 *
214 * FIXME: Needs doc
215 */
216 void add_key_to_report(report_keyboard_t* keyboard_report, uint8_t key)
217 {
218 #ifdef NKRO_ENABLE
219 if (keyboard_protocol && keymap_config.nkro) {
220 add_key_bit(keyboard_report, key);
221 return;
222 }
223 #endif
224 add_key_byte(keyboard_report, key);
225 }
226
227 /** \brief del key from report
228 *
229 * FIXME: Needs doc
230 */
231 void del_key_from_report(report_keyboard_t* keyboard_report, uint8_t key)
232 {
233 #ifdef NKRO_ENABLE
234 if (keyboard_protocol && keymap_config.nkro) {
235 del_key_bit(keyboard_report, key);
236 return;
237 }
238 #endif
239 del_key_byte(keyboard_report, key);
240 }
241
242 /** \brief clear key from report
243 *
244 * FIXME: Needs doc
245 */
246 void clear_keys_from_report(report_keyboard_t* keyboard_report)
247 {
248 // not clear mods
249 #ifdef NKRO_ENABLE
250 if (keyboard_protocol && keymap_config.nkro) {
251 memset(keyboard_report->nkro.bits, 0, sizeof(keyboard_report->nkro.bits));
252 return;
253 }
254 #endif
255 memset(keyboard_report->keys, 0, sizeof(keyboard_report->keys));
256 }