/* ketboard_emu.ino This file handle keyboard emulation and key writes */ #define MAX_KEYBOARD_HID_KEYCODE_NO 6 #define ENABLE_KEYBOARD_DEBUG_PRINTOUT /* Modifier keycode for CH9329 */ #define MOD_LCTRL 0x01 #define MOD_LSHIFT 0x02 #define MOD_LALT 0x04 #define MOD_LGUI 0x08 #define MOD_RCTRL 0x10 #define MOD_RSHIFT 0x20 #define MOD_RALT 0x40 #define MOD_RGUI 0x80 /* Runtime variables */ uint8_t keyboard_state[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //byte 0: Computer connected //byte 1: // bit 0: NUM LOCK // bit 1: CAPS LOCK // bit 2: SCROLL LOCK uint8_t keyboard_leds[2] = { 0x00, 0x00 }; extern uint8_t kbCmdBuf[MAX_CMD_LEN]; extern uint8_t kbCmdIndex; extern uint8_t kbCmdCounter; /* Function Prototypes */ void send_cmd(uint8_t cmd, uint8_t* data, uint8_t length); /* Request CH9329 response with current keyboard status */ void keyboard_get_info() { send_cmd(0x01, NULL, 0x00); } /* Callback handler for setting keyboard status */ void handle_keyboard_get_info_reply() { keyboard_leds[0] = kbCmdBuf[6]; keyboard_leds[1] = kbCmdBuf[7]; #ifdef ENABLE_KEYBOARD_DEBUG_PRINTOUT for (int i = 0; i < kbCmdIndex; i++) { uint8_t b = kbCmdBuf[i]; USBSerial_print("0x"); if (b < 0x10) USBSerial_print("0"); USBSerial_print(b, HEX); USBSerial_print(" "); } USBSerial_println(keyboard_leds[0] ? "Connected" : "Not Connected"); USBSerial_println((keyboard_leds[1] & 0x01) ? "NUMLOCK ON" : "NUMLOCK OFF"); USBSerial_println((keyboard_leds[1] & 0x02) ? "CAPSLOCK ON" : "CAPSLOCK OFF"); USBSerial_println((keyboard_leds[1] & 0x04) ? "SCROLLLOCK ON" : "SCROLLLOCK OFF"); #endif } /* helper to write an array of uint8_t to CH9329 */ void Serial0_writeBuf(const uint8_t* data, uint8_t len) { for (uint8_t i = 0; i < len; i++) { Serial0_write(data[i]); } } /* Send key combinations, keycode must be an array with length 6 */ int keyboard_send_key_combinations(uint8_t modifiers, uint8_t* keycode, uint8_t length) { if (length != MAX_KEYBOARD_HID_KEYCODE_NO) { //This function must take in an array of 6 keycodes return -1; } uint8_t packet[14] = { 0x57, 0xAB, 0x00, 0x02, 0x08, modifiers, 0x00, keycode[0], keycode[1], keycode[2], keycode[3], keycode[4], keycode[5], 0x00 }; packet[13] = calcChecksum(packet, 13); Serial0_writeBuf(packet, 14); return 0; } /* Release all keypress on the current emulated keyboard */ void keyboard_release_all_keys() { uint8_t packet[] = { 0x57, 0xAB, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // checksum placeholder }; packet[13] = calcChecksum(packet, 13); Serial0_writeBuf(packet, 14); } /* Convert JavaScrpt Keycode into HID keycode */ uint8_t javascript_keycode_to_hid_opcode(uint8_t keycode) { // Letters A-Z if (keycode >= 65 && keycode <= 90) { return (keycode - 65) + 0x04; // 'A' is 0x04 } // Numbers 1-9 (top row, not numpad) if (keycode >= 49 && keycode <= 57) { return (keycode - 48) + 0x1E; // '1' is 0x1E } //Numpad 1-9 if (keycode >= 97 && keycode <= 105) { return (keycode - 97) + 0x59; // '1' (numpad) is 0x59 } //F1 to F12 if (keycode >= 112 && keycode <= 123) { return (keycode - 112) + 0x3A; // 'F1' is 0x3A } switch (keycode) { case 8: return 0x2A; // Backspace case 9: return 0x2B; // Tab case 13: return 0x28; // Enter case 16: return 0xE1; //Left shift case 17: return 0xE0; //Left Ctrl case 18: return 0xE6; //Left Alt case 20: return 0x39; // Caps Lock case 27: return 0x29; // Escape case 32: return 0x2C; // Spacebar case 33: return 0x4B; // Page Up case 34: return 0x4E; // Page Down case 35: return 0x4D; // End case 36: return 0x4A; // Home case 37: return 0x50; // Left Arrow case 38: return 0x52; // Up Arrow case 39: return 0x4F; // Right Arrow case 40: return 0x51; // Down Arrow case 44: return 0x46; //Print Screen or F13 (Firefox) case 45: return 0x49; // Insert case 46: return 0x4C; // Delete case 48: return 0x27; // 0 (not Numpads) // 49 - 57 Number row 1 - 9 handled above // 58 not supported case 59: return 0x33; // ';' // 60 not supported case 61: return 0x2E; // '=' //62 - 90 not supported case 91: return 0xE3; // Left GUI (Windows) case 92: return 0xE7; // Right GUI case 93: return 0x65; // Menu key // 64 - 65 not supported case 96: return 0x62; //0 (Numpads) //Numpad 1 to 9 handled above case 106: return 0x55; //* (Numpads) case 107: return 0x57; //+ (Numpads) case 109: return 0x56; //- (Numpads) case 110: return 0x63; // dot (Numpads) case 111: return 0x54; // divide (Numpads) // 112 - 123 F1 to F12 handled above // 124 - 143 F13 to F32 not supported case 144: return 0x53; // Num Lock case 145: return 0x47; // Scroll Lock // 146 - 185 not supported or not exists case 186: return 0x33; // ; case 187: return 0x2E; // = case 188: return 0x36; // , case 189: return 0x2D; // - case 190: return 0x37; // . case 191: return 0x38; // / case 192: return 0x35; // ` case 219: return 0x2F; // [ case 220: return 0x31; // backslash case 221: return 0x30; // ] case 222: return 0x34; // ' default: return 0x00; // Unknown / unsupported } }