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