keyboard_emu.ino 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. ketboard_emu.ino
  3. This file handle keyboard emulation and key writes
  4. */
  5. #define KEYBOARD_HID_KEYCODE_LENGTH 6
  6. /* Modifier keycode for CH9329 */
  7. #define MOD_LCTRL 0x01
  8. #define MOD_LSHIFT 0x02
  9. #define MOD_LALT 0x04
  10. #define MOD_LGUI 0x08
  11. #define MOD_RCTRL 0x10
  12. #define MOD_RSHIFT 0x20
  13. #define MOD_RALT 0x40
  14. #define MOD_RGUI 0x80
  15. #define MOD_RENTER 0x58
  16. /* Runtime variables */
  17. uint8_t keyboard_state[KEYBOARD_HID_KEYCODE_LENGTH] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  18. uint8_t keyboard_pressing_key_count = 0; //No. of key currently pressing, max is 6
  19. uint8_t keyboard_modifiers = 0x00; //Current modifier key state
  20. //byte 0: Computer connected
  21. //byte 1:
  22. // bit 0: NUM LOCK
  23. // bit 1: CAPS LOCK
  24. // bit 2: SCROLL LOCK
  25. uint8_t keyboard_leds[2] = { 0x00, 0x00 };
  26. extern uint8_t kbCmdBuf[MAX_CMD_LEN];
  27. extern uint8_t kbCmdIndex;
  28. extern uint8_t kbCmdCounter;
  29. /* Function Prototypes */
  30. void send_cmd(uint8_t cmd, uint8_t* data, uint8_t length);
  31. /* Request CH9329 response with current keyboard status */
  32. void keyboard_get_info() {
  33. send_cmd(0x01, NULL, 0x00);
  34. }
  35. /* Callback handler for setting keyboard status */
  36. void handle_keyboard_get_info_reply() {
  37. keyboard_leds[0] = kbCmdBuf[6];
  38. keyboard_leds[1] = kbCmdBuf[7];
  39. //Print the result to USBSerial
  40. USBSerial_print(keyboard_leds[0], HEX); //USB connected
  41. USBSerial_print(keyboard_leds[1], HEX); //LED state bits
  42. }
  43. /* Send key combinations to CH9329*/
  44. int keyboard_send_key_combinations() {
  45. uint8_t packet[14] = {
  46. 0x57, 0xAB, 0x00, 0x02, 0x08,
  47. keyboard_modifiers, 0x00,
  48. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  49. 0x00
  50. };
  51. //Populate the HID keycodes
  52. for (uint8_t i = 0; i < KEYBOARD_HID_KEYCODE_LENGTH; i++) {
  53. packet[7 + i] = keyboard_state[i];
  54. }
  55. packet[13] = calcChecksum(packet, 13);
  56. Serial0_writeBuf(packet, 14);
  57. return 0;
  58. }
  59. /* Release all keypress on the current emulated keyboard */
  60. void keyboard_release_all_keys() {
  61. uint8_t packet[] = {
  62. 0x57, 0xAB, 0x00, 0x02, 0x08,
  63. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  64. 0x00 // checksum placeholder
  65. };
  66. packet[13] = calcChecksum(packet, 13);
  67. Serial0_writeBuf(packet, 14);
  68. }
  69. /* Convert JavaScrpt Keycode into HID keycode */
  70. uint8_t javascript_keycode_to_hid_opcode(uint8_t keycode) {
  71. // Letters A-Z
  72. if (keycode >= 65 && keycode <= 90) {
  73. return (keycode - 65) + 0x04; // 'A' is 0x04
  74. }
  75. // Numbers 1-9 (top row, not numpad)
  76. if (keycode >= 49 && keycode <= 57) {
  77. return (keycode - 49) + 0x1E; // '1' is 0x1E
  78. }
  79. //Numpad 1-9
  80. if (keycode >= 97 && keycode <= 105) {
  81. return (keycode - 97) + 0x59; // '1' (numpad) is 0x59
  82. }
  83. //F1 to F12
  84. if (keycode >= 112 && keycode <= 123) {
  85. return (keycode - 112) + 0x3A; // 'F1' is 0x3A
  86. }
  87. switch (keycode) {
  88. case 8:
  89. return 0x2A; // Backspace
  90. case 9:
  91. return 0x2B; // Tab
  92. case 13:
  93. return 0x28; // Enter
  94. case 16:
  95. return 0xE1; //Left shift
  96. case 17:
  97. return 0xE0; //Left Ctrl
  98. case 18:
  99. return 0xE6; //Left Alt
  100. case 19:
  101. return 0x48; //Pause
  102. case 20:
  103. return 0x39; // Caps Lock
  104. case 27:
  105. return 0x29; // Escape
  106. case 32:
  107. return 0x2C; // Spacebar
  108. case 33:
  109. return 0x4B; // Page Up
  110. case 34:
  111. return 0x4E; // Page Down
  112. case 35:
  113. return 0x4D; // End
  114. case 36:
  115. return 0x4A; // Home
  116. case 37:
  117. return 0x50; // Left Arrow
  118. case 38:
  119. return 0x52; // Up Arrow
  120. case 39:
  121. return 0x4F; // Right Arrow
  122. case 40:
  123. return 0x51; // Down Arrow
  124. case 44:
  125. return 0x46; //Print Screen or F13 (Firefox)
  126. case 45:
  127. return 0x49; // Insert
  128. case 46:
  129. return 0x4C; // Delete
  130. case 48:
  131. return 0x27; // 0 (not Numpads)
  132. // 49 - 57 Number row 1 - 9 handled above
  133. // 58 not supported
  134. case 59:
  135. return 0x33; // ';'
  136. // 60 not supported
  137. case 61:
  138. return 0x2E; // '='
  139. //62 - 90 not supported
  140. case 91:
  141. return 0xE3; // Left GUI (Windows)
  142. case 92:
  143. return 0xE7; // Right GUI
  144. case 93:
  145. return 0x65; // Menu key
  146. // 64 - 65 not supported
  147. case 96:
  148. return 0x62; //0 (Numpads)
  149. //Numpad 1 to 9 handled above
  150. case 106:
  151. return 0x55; //* (Numpads)
  152. case 107:
  153. return 0x57; //+ (Numpads)
  154. case 109:
  155. return 0x56; //- (Numpads)
  156. case 110:
  157. return 0x63; // dot (Numpads)
  158. case 111:
  159. return 0x54; // divide (Numpads)
  160. // 112 - 123 F1 to F12 handled above
  161. // 124 - 143 F13 to F32 not supported
  162. case 144:
  163. return 0x53; // Num Lock
  164. case 145:
  165. return 0x47; // Scroll Lock
  166. /*
  167. SPECIAL CASES
  168. We are using a specific range of the JavaScript unused keycode
  169. for special keys that cannot be mapped normally
  170. */
  171. case 146:
  172. return 0x58; //Numpad enter
  173. case 173:
  174. return 0x2D; // -
  175. //End of special cases
  176. case 186:
  177. return 0x33; // ;
  178. case 187:
  179. return 0x2E; // =
  180. case 188:
  181. return 0x36; // ,
  182. case 189:
  183. return 0x2D; // -
  184. case 190:
  185. return 0x37; // .
  186. case 191:
  187. return 0x38; // /
  188. case 192:
  189. return 0x35; // `
  190. case 219:
  191. return 0x2F; // [
  192. case 220:
  193. return 0x31; // backslash
  194. case 221:
  195. return 0x30; // ]
  196. case 222:
  197. return 0x34; // '
  198. default:
  199. return 0x00; // Unknown / unsupported
  200. }
  201. }
  202. //Send a keyboard press by JavaScript keycode
  203. int keyboard_press_key(uint8_t keycode) {
  204. //Convert javascript keycode to HID
  205. keycode = javascript_keycode_to_hid_opcode(keycode);
  206. if (keycode == 0x00) {
  207. //Not supported
  208. return -1;
  209. }
  210. // Already pressed? Skip
  211. for (int i = 0; i < 6; i++) {
  212. if (keyboard_state[i] == keycode) {
  213. return 0; // Already held
  214. }
  215. }
  216. //Get the empty slot in the current HID list
  217. for (int i = 0; i < 6; i++) {
  218. if (keyboard_state[i] == 0x00) {
  219. keyboard_state[i] = keycode;
  220. keyboard_pressing_key_count++;
  221. keyboard_send_key_combinations();
  222. return 0;
  223. }
  224. }
  225. //No space left
  226. return -1;
  227. }
  228. //Send a keyboard release by JavaScript keycode
  229. int keyboard_release_key(uint8_t keycode) {
  230. //Convert javascript keycode to HID
  231. keycode = javascript_keycode_to_hid_opcode(keycode);
  232. if (keycode == 0x00) {
  233. //Not supported
  234. return -1;
  235. }
  236. //Get the position where the key is pressed
  237. for (int i = 0; i < 6; i++) {
  238. if (keyboard_state[i] == keycode) {
  239. keyboard_state[i] = 0x00;
  240. if (keyboard_pressing_key_count > 0) {
  241. keyboard_pressing_key_count--;
  242. }
  243. keyboard_send_key_combinations();
  244. return 0;
  245. }
  246. }
  247. //That key is not pressed
  248. return 0;
  249. }
  250. uint8_t keyboard_get_modifier_bit_from_opcode(uint8_t opcode) {
  251. switch (opcode) {
  252. case 0x01:
  253. return MOD_LCTRL;
  254. case 0x02:
  255. return MOD_LSHIFT;
  256. case 0x03:
  257. return MOD_LALT;
  258. case 0x04:
  259. return MOD_LGUI;
  260. case 0x05:
  261. return MOD_RCTRL;
  262. case 0x06:
  263. return MOD_RSHIFT;
  264. case 0x07:
  265. return MOD_RALT;
  266. case 0x08:
  267. return MOD_RGUI;
  268. case 0x09:
  269. //Ctrl + Alt + Del
  270. return MOD_LCTRL | MOD_LALT;
  271. case 0x0A:
  272. //Win + Shift + S
  273. return MOD_LSHIFT | MOD_LGUI;
  274. break;
  275. //To be added
  276. default:
  277. return 0x00;
  278. }
  279. }
  280. //Set the modifier key bit
  281. int keyboard_press_modkey(uint8_t opcode) {
  282. if (opcode == 0x00) {
  283. //Reset the modkeys
  284. keyboard_modifiers = 0;
  285. keyboard_send_key_combinations();
  286. return 0;
  287. }
  288. uint8_t mask = keyboard_get_modifier_bit_from_opcode(opcode);
  289. if (mask == 0x00) {
  290. return -1;
  291. }
  292. keyboard_modifiers |= mask;
  293. keyboard_send_key_combinations();
  294. return 0;
  295. }
  296. //Unset modifier key bit
  297. int keyboard_release_modkey(uint8_t opcode) {
  298. if (opcode == 0x00) {
  299. //Reset the modkeys
  300. keyboard_modifiers = 0;
  301. keyboard_send_key_combinations();
  302. return 0;
  303. }
  304. uint8_t mask = keyboard_get_modifier_bit_from_opcode(opcode);
  305. if (mask == 0x00) {
  306. return -1;
  307. }
  308. keyboard_modifiers &= ~mask;
  309. keyboard_send_key_combinations();
  310. return 0;
  311. }
  312. //Reset all keypress on keyboard
  313. void keyboard_reset() {
  314. memset(keyboard_state, 0x00, sizeof(keyboard_state));
  315. keyboard_modifiers = 0x00;
  316. keyboard_send_key_combinations();
  317. }