report.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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. #include "report.h"
  17. #include "action_util.h"
  18. #include "host.h"
  19. #include "keycode_config.h"
  20. #include "debug.h"
  21. #include "util.h"
  22. #include <string.h>
  23. #ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
  24. # define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS)
  25. # define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS)
  26. # define RO_INC(a) RO_ADD(a, 1)
  27. # define RO_DEC(a) RO_SUB(a, 1)
  28. static int8_t cb_head = 0;
  29. static int8_t cb_tail = 0;
  30. static int8_t cb_count = 0;
  31. #endif
  32. /** \brief has_anykey
  33. *
  34. * FIXME: Needs doc
  35. */
  36. uint8_t has_anykey(void) {
  37. uint8_t cnt = 0;
  38. uint8_t* p = keyboard_report->keys;
  39. uint8_t lp = sizeof(keyboard_report->keys);
  40. #ifdef NKRO_ENABLE
  41. if (keyboard_protocol && keymap_config.nkro) {
  42. p = nkro_report->bits;
  43. lp = sizeof(nkro_report->bits);
  44. }
  45. #endif
  46. while (lp--) {
  47. if (*p++) cnt++;
  48. }
  49. return cnt;
  50. }
  51. /** \brief get_first_key
  52. *
  53. * FIXME: Needs doc
  54. */
  55. uint8_t get_first_key(void) {
  56. #ifdef NKRO_ENABLE
  57. if (keyboard_protocol && keymap_config.nkro) {
  58. uint8_t i = 0;
  59. for (; i < NKRO_REPORT_BITS && !nkro_report->bits[i]; i++)
  60. ;
  61. return i << 3 | biton(nkro_report->bits[i]);
  62. }
  63. #endif
  64. #ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
  65. uint8_t i = cb_head;
  66. do {
  67. if (keyboard_report->keys[i] != 0) {
  68. break;
  69. }
  70. i = RO_INC(i);
  71. } while (i != cb_tail);
  72. return keyboard_report->keys[i];
  73. #else
  74. return keyboard_report->keys[0];
  75. #endif
  76. }
  77. /** \brief Checks if a key is pressed in the report
  78. *
  79. * Returns true if the keyboard_report reports that the key is pressed, otherwise false
  80. * Note: The function doesn't support modifers currently, and it returns false for KC_NO
  81. */
  82. bool is_key_pressed(uint8_t key) {
  83. if (key == KC_NO) {
  84. return false;
  85. }
  86. #ifdef NKRO_ENABLE
  87. if (keyboard_protocol && keymap_config.nkro) {
  88. if ((key >> 3) < NKRO_REPORT_BITS) {
  89. return nkro_report->bits[key >> 3] & 1 << (key & 7);
  90. } else {
  91. return false;
  92. }
  93. }
  94. #endif
  95. for (int i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
  96. if (keyboard_report->keys[i] == key) {
  97. return true;
  98. }
  99. }
  100. return false;
  101. }
  102. /** \brief add key byte
  103. *
  104. * FIXME: Needs doc
  105. */
  106. void add_key_byte(report_keyboard_t* keyboard_report, uint8_t code) {
  107. #ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
  108. int8_t i = cb_head;
  109. int8_t empty = -1;
  110. if (cb_count) {
  111. do {
  112. if (keyboard_report->keys[i] == code) {
  113. return;
  114. }
  115. if (empty == -1 && keyboard_report->keys[i] == 0) {
  116. empty = i;
  117. }
  118. i = RO_INC(i);
  119. } while (i != cb_tail);
  120. if (i == cb_tail) {
  121. if (cb_tail == cb_head) {
  122. // buffer is full
  123. if (empty == -1) {
  124. // pop head when has no empty space
  125. cb_head = RO_INC(cb_head);
  126. cb_count--;
  127. } else {
  128. // left shift when has empty space
  129. uint8_t offset = 1;
  130. i = RO_INC(empty);
  131. do {
  132. if (keyboard_report->keys[i] != 0) {
  133. keyboard_report->keys[empty] = keyboard_report->keys[i];
  134. keyboard_report->keys[i] = 0;
  135. empty = RO_INC(empty);
  136. } else {
  137. offset++;
  138. }
  139. i = RO_INC(i);
  140. } while (i != cb_tail);
  141. cb_tail = RO_SUB(cb_tail, offset);
  142. }
  143. }
  144. }
  145. }
  146. // add to tail
  147. keyboard_report->keys[cb_tail] = code;
  148. cb_tail = RO_INC(cb_tail);
  149. cb_count++;
  150. #else
  151. int8_t i = 0;
  152. int8_t empty = -1;
  153. for (; i < KEYBOARD_REPORT_KEYS; i++) {
  154. if (keyboard_report->keys[i] == code) {
  155. break;
  156. }
  157. if (empty == -1 && keyboard_report->keys[i] == 0) {
  158. empty = i;
  159. }
  160. }
  161. if (i == KEYBOARD_REPORT_KEYS) {
  162. if (empty != -1) {
  163. keyboard_report->keys[empty] = code;
  164. }
  165. }
  166. #endif
  167. }
  168. /** \brief del key byte
  169. *
  170. * FIXME: Needs doc
  171. */
  172. void del_key_byte(report_keyboard_t* keyboard_report, uint8_t code) {
  173. #ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
  174. uint8_t i = cb_head;
  175. if (cb_count) {
  176. do {
  177. if (keyboard_report->keys[i] == code) {
  178. keyboard_report->keys[i] = 0;
  179. cb_count--;
  180. if (cb_count == 0) {
  181. // reset head and tail
  182. cb_tail = cb_head = 0;
  183. }
  184. if (i == RO_DEC(cb_tail)) {
  185. // left shift when next to tail
  186. do {
  187. cb_tail = RO_DEC(cb_tail);
  188. if (keyboard_report->keys[RO_DEC(cb_tail)] != 0) {
  189. break;
  190. }
  191. } while (cb_tail != cb_head);
  192. }
  193. break;
  194. }
  195. i = RO_INC(i);
  196. } while (i != cb_tail);
  197. }
  198. #else
  199. for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
  200. if (keyboard_report->keys[i] == code) {
  201. keyboard_report->keys[i] = 0;
  202. }
  203. }
  204. #endif
  205. }
  206. #ifdef NKRO_ENABLE
  207. /** \brief add key bit
  208. *
  209. * FIXME: Needs doc
  210. */
  211. void add_key_bit(report_nkro_t* nkro_report, uint8_t code) {
  212. if ((code >> 3) < NKRO_REPORT_BITS) {
  213. nkro_report->bits[code >> 3] |= 1 << (code & 7);
  214. } else {
  215. dprintf("add_key_bit: can't add: %02X\n", code);
  216. }
  217. }
  218. /** \brief del key bit
  219. *
  220. * FIXME: Needs doc
  221. */
  222. void del_key_bit(report_nkro_t* nkro_report, uint8_t code) {
  223. if ((code >> 3) < NKRO_REPORT_BITS) {
  224. nkro_report->bits[code >> 3] &= ~(1 << (code & 7));
  225. } else {
  226. dprintf("del_key_bit: can't del: %02X\n", code);
  227. }
  228. }
  229. #endif
  230. /** \brief add key to report
  231. *
  232. * FIXME: Needs doc
  233. */
  234. void add_key_to_report(uint8_t key) {
  235. #ifdef NKRO_ENABLE
  236. if (keyboard_protocol && keymap_config.nkro) {
  237. add_key_bit(nkro_report, key);
  238. return;
  239. }
  240. #endif
  241. add_key_byte(keyboard_report, key);
  242. }
  243. /** \brief del key from report
  244. *
  245. * FIXME: Needs doc
  246. */
  247. void del_key_from_report(uint8_t key) {
  248. #ifdef NKRO_ENABLE
  249. if (keyboard_protocol && keymap_config.nkro) {
  250. del_key_bit(nkro_report, key);
  251. return;
  252. }
  253. #endif
  254. del_key_byte(keyboard_report, key);
  255. }
  256. /** \brief clear key from report
  257. *
  258. * FIXME: Needs doc
  259. */
  260. void clear_keys_from_report(void) {
  261. // not clear mods
  262. #ifdef NKRO_ENABLE
  263. if (keyboard_protocol && keymap_config.nkro) {
  264. memset(nkro_report->bits, 0, sizeof(nkro_report->bits));
  265. return;
  266. }
  267. #endif
  268. memset(keyboard_report->keys, 0, sizeof(keyboard_report->keys));
  269. }
  270. #ifdef MOUSE_ENABLE
  271. /**
  272. * @brief Compares 2 mouse reports for difference and returns result. Empty
  273. * reports always evaluate as unchanged.
  274. *
  275. * @param[in] new_report report_mouse_t
  276. * @param[in] old_report report_mouse_t
  277. * @return bool result
  278. */
  279. __attribute__((weak)) bool has_mouse_report_changed(report_mouse_t* new_report, report_mouse_t* old_report) {
  280. // memcmp doesn't work here because of the `report_id` field when using
  281. // shared mouse endpoint
  282. bool changed = ((new_report->buttons != old_report->buttons) ||
  283. # ifdef MOUSE_EXTENDED_REPORT
  284. (new_report->boot_x != 0 && new_report->boot_x != old_report->boot_x) || (new_report->boot_y != 0 && new_report->boot_y != old_report->boot_y) ||
  285. # endif
  286. (new_report->x != 0 && new_report->x != old_report->x) || (new_report->y != 0 && new_report->y != old_report->y) || (new_report->h != 0 && new_report->h != old_report->h) || (new_report->v != 0 && new_report->v != old_report->v));
  287. return changed;
  288. }
  289. #endif