summaryrefslogtreecommitdiff
path: root/tmk_core/protocol/report.c
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core/protocol/report.c')
-rw-r--r--tmk_core/protocol/report.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/tmk_core/protocol/report.c b/tmk_core/protocol/report.c
new file mode 100644
index 0000000000..854b59ae48
--- /dev/null
+++ b/tmk_core/protocol/report.c
@@ -0,0 +1,280 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "report.h"
+#include "host.h"
+#include "keycode_config.h"
+#include "debug.h"
+#include "util.h"
+#include <string.h>
+
+#ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
+# define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS)
+# define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS)
+# define RO_INC(a) RO_ADD(a, 1)
+# define RO_DEC(a) RO_SUB(a, 1)
+static int8_t cb_head = 0;
+static int8_t cb_tail = 0;
+static int8_t cb_count = 0;
+#endif
+
+/** \brief has_anykey
+ *
+ * FIXME: Needs doc
+ */
+uint8_t has_anykey(report_keyboard_t* keyboard_report) {
+ uint8_t cnt = 0;
+ uint8_t* p = keyboard_report->keys;
+ uint8_t lp = sizeof(keyboard_report->keys);
+#ifdef NKRO_ENABLE
+ if (keyboard_protocol && keymap_config.nkro) {
+ p = keyboard_report->nkro.bits;
+ lp = sizeof(keyboard_report->nkro.bits);
+ }
+#endif
+ while (lp--) {
+ if (*p++) cnt++;
+ }
+ return cnt;
+}
+
+/** \brief get_first_key
+ *
+ * FIXME: Needs doc
+ */
+uint8_t get_first_key(report_keyboard_t* keyboard_report) {
+#ifdef NKRO_ENABLE
+ if (keyboard_protocol && keymap_config.nkro) {
+ uint8_t i = 0;
+ for (; i < KEYBOARD_REPORT_BITS && !keyboard_report->nkro.bits[i]; i++)
+ ;
+ return i << 3 | biton(keyboard_report->nkro.bits[i]);
+ }
+#endif
+#ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
+ uint8_t i = cb_head;
+ do {
+ if (keyboard_report->keys[i] != 0) {
+ break;
+ }
+ i = RO_INC(i);
+ } while (i != cb_tail);
+ return keyboard_report->keys[i];
+#else
+ return keyboard_report->keys[0];
+#endif
+}
+
+/** \brief Checks if a key is pressed in the report
+ *
+ * Returns true if the keyboard_report reports that the key is pressed, otherwise false
+ * Note: The function doesn't support modifers currently, and it returns false for KC_NO
+ */
+bool is_key_pressed(report_keyboard_t* keyboard_report, uint8_t key) {
+ if (key == KC_NO) {
+ return false;
+ }
+#ifdef NKRO_ENABLE
+ if (keyboard_protocol && keymap_config.nkro) {
+ if ((key >> 3) < KEYBOARD_REPORT_BITS) {
+ return keyboard_report->nkro.bits[key >> 3] & 1 << (key & 7);
+ } else {
+ return false;
+ }
+ }
+#endif
+ for (int i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
+ if (keyboard_report->keys[i] == key) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/** \brief add key byte
+ *
+ * FIXME: Needs doc
+ */
+void add_key_byte(report_keyboard_t* keyboard_report, uint8_t code) {
+#ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
+ int8_t i = cb_head;
+ int8_t empty = -1;
+ if (cb_count) {
+ do {
+ if (keyboard_report->keys[i] == code) {
+ return;
+ }
+ if (empty == -1 && keyboard_report->keys[i] == 0) {
+ empty = i;
+ }
+ i = RO_INC(i);
+ } while (i != cb_tail);
+ if (i == cb_tail) {
+ if (cb_tail == cb_head) {
+ // buffer is full
+ if (empty == -1) {
+ // pop head when has no empty space
+ cb_head = RO_INC(cb_head);
+ cb_count--;
+ } else {
+ // left shift when has empty space
+ uint8_t offset = 1;
+ i = RO_INC(empty);
+ do {
+ if (keyboard_report->keys[i] != 0) {
+ keyboard_report->keys[empty] = keyboard_report->keys[i];
+ keyboard_report->keys[i] = 0;
+ empty = RO_INC(empty);
+ } else {
+ offset++;
+ }
+ i = RO_INC(i);
+ } while (i != cb_tail);
+ cb_tail = RO_SUB(cb_tail, offset);
+ }
+ }
+ }
+ }
+ // add to tail
+ keyboard_report->keys[cb_tail] = code;
+ cb_tail = RO_INC(cb_tail);
+ cb_count++;
+#else
+ int8_t i = 0;
+ int8_t empty = -1;
+ for (; i < KEYBOARD_REPORT_KEYS; i++) {
+ if (keyboard_report->keys[i] == code) {
+ break;
+ }
+ if (empty == -1 && keyboard_report->keys[i] == 0) {
+ empty = i;
+ }
+ }
+ if (i == KEYBOARD_REPORT_KEYS) {
+ if (empty != -1) {
+ keyboard_report->keys[empty] = code;
+ }
+ }
+#endif
+}
+
+/** \brief del key byte
+ *
+ * FIXME: Needs doc
+ */
+void del_key_byte(report_keyboard_t* keyboard_report, uint8_t code) {
+#ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
+ uint8_t i = cb_head;
+ if (cb_count) {
+ do {
+ if (keyboard_report->keys[i] == code) {
+ keyboard_report->keys[i] = 0;
+ cb_count--;
+ if (cb_count == 0) {
+ // reset head and tail
+ cb_tail = cb_head = 0;
+ }
+ if (i == RO_DEC(cb_tail)) {
+ // left shift when next to tail
+ do {
+ cb_tail = RO_DEC(cb_tail);
+ if (keyboard_report->keys[RO_DEC(cb_tail)] != 0) {
+ break;
+ }
+ } while (cb_tail != cb_head);
+ }
+ break;
+ }
+ i = RO_INC(i);
+ } while (i != cb_tail);
+ }
+#else
+ for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
+ if (keyboard_report->keys[i] == code) {
+ keyboard_report->keys[i] = 0;
+ }
+ }
+#endif
+}
+
+#ifdef NKRO_ENABLE
+/** \brief add key bit
+ *
+ * FIXME: Needs doc
+ */
+void add_key_bit(report_keyboard_t* keyboard_report, uint8_t code) {
+ if ((code >> 3) < KEYBOARD_REPORT_BITS) {
+ keyboard_report->nkro.bits[code >> 3] |= 1 << (code & 7);
+ } else {
+ dprintf("add_key_bit: can't add: %02X\n", code);
+ }
+}
+
+/** \brief del key bit
+ *
+ * FIXME: Needs doc
+ */
+void del_key_bit(report_keyboard_t* keyboard_report, uint8_t code) {
+ if ((code >> 3) < KEYBOARD_REPORT_BITS) {
+ keyboard_report->nkro.bits[code >> 3] &= ~(1 << (code & 7));
+ } else {
+ dprintf("del_key_bit: can't del: %02X\n", code);
+ }
+}
+#endif
+
+/** \brief add key to report
+ *
+ * FIXME: Needs doc
+ */
+void add_key_to_report(report_keyboard_t* keyboard_report, uint8_t key) {
+#ifdef NKRO_ENABLE
+ if (keyboard_protocol && keymap_config.nkro) {
+ add_key_bit(keyboard_report, key);
+ return;
+ }
+#endif
+ add_key_byte(keyboard_report, key);
+}
+
+/** \brief del key from report
+ *
+ * FIXME: Needs doc
+ */
+void del_key_from_report(report_keyboard_t* keyboard_report, uint8_t key) {
+#ifdef NKRO_ENABLE
+ if (keyboard_protocol && keymap_config.nkro) {
+ del_key_bit(keyboard_report, key);
+ return;
+ }
+#endif
+ del_key_byte(keyboard_report, key);
+}
+
+/** \brief clear key from report
+ *
+ * FIXME: Needs doc
+ */
+void clear_keys_from_report(report_keyboard_t* keyboard_report) {
+ // not clear mods
+#ifdef NKRO_ENABLE
+ if (keyboard_protocol && keymap_config.nkro) {
+ memset(keyboard_report->nkro.bits, 0, sizeof(keyboard_report->nkro.bits));
+ return;
+ }
+#endif
+ memset(keyboard_report->keys, 0, sizeof(keyboard_report->keys));
+}