You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
8.5 KiB

Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
  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