/* keyboard_emu.ino Author: tobychui This code file handle keyboard emulation related functionality When opr_type is set to 0x01, the sub-handler will process the request here. -- Keyboard Opcode -- 0x00 = Reserved 0x01 = keyboard write 0x02 = keyboard press 0x03 = keyboard release (ASCII bytes in range of 32 to 127) 0x04 = Modifier key combination set (bit flags in payload) Bit 0 (0x01) = KEY_LEFT_CTRL Bit 1 (0x02) = KEY_LEFT_SHIFT Bit 2 (0x04) = KEY_LEFT_ALT Bit 3 (0x08) = KEY_LEFT_GUI Bit 4 (0x10) = KEY_RIGHT_CTRL Bit 5 (0x20) = KEY_RIGHT_SHIFT Bit 6 (0x40) = KEY_RIGHT_ALT Bit 7 (0x80) = KEY_RIGHT_GUI 0x05 = Modifier key combination reset 0x07 = Function key combinartion write 0xC2 = KEY_F1 0xC3 = KEY_F2 0xC4 = KEY_F3 ... 0xCC = KEY_F11 0xCD = KEY_F12 0xF0 = KEY_F13 ... 0xFB = KEY_F24 0x08 = Other keys press 0x09 = Other keys release 0xDA = KEY_UP_ARROW 0xD9 = KEY_DOWN_ARROW 0xD8 = KEY_LEFT_ARROW 0xD7 = KEY_RIGHT_ARROW 0xB2 = KEY_BACKSPACE 0xB3 = KEY_TAB 0xB0 = KEY_RETURN 0xB1 = KEY_ESC 0xD1 = KEY_INSERT 0xD4 = KEY_DELETE 0xD3 = KEY_PAGE_UP 0xD6 = KEY_PAGE_DOWN 0xD2 = KEY_HOME 0xD5 = KEY_END 0xC1 = KEY_CAPS_LOCK -- Special Opcode -- 0xFE = Ctrl + Alt + Delete 0xFF = Reset all keys state */ #include "usbkvm_fw.h" //Check if the value is a supported ascii code bool is_ascii(uint8_t value) { return value >= 32 && value <= 127; } //Check if the value is a valid function key value bool is_funckey(uint8_t value) { return ((value >= 0xC2 && value <= 0xCD) || (value >= 0xF0 && value <= 0xFB)); } //Check if the key is valid key that do not belongs in ASCII or function key bool is_validkeys(uint8_t key) { if (key >= 0xD7 && key <= 0xDA) { //Arrow keys return true; } if (key >= 0xB0 && key <= 0xB3) { //ESC, tabs and other left-most keys return true; } if (key >= 0xD1 && key <= 0xD6) { //Keys above arrow keys like pageup and down return true; } //CAP_LOCK return key == 0xC1; } //Check if the nth bit is set in the value bool isBitSet(uint8_t value, uint8_t n) { if (n > 7) return false; // Ensure n is within 0-7 return (value & (1 << n)) != 0; } //Handle modifying key set or unset void keyboard_modifying_key_set(uint8_t key) { if (key & 0x01) { // Bit 0 = KEY_LEFT_CTRL Keyboard_press(KEY_LEFT_CTRL); } else { Keyboard_release(KEY_LEFT_CTRL); } if (key & 0x02) { // Bit 1 = KEY_LEFT_SHIFT Keyboard_press(KEY_LEFT_SHIFT); } else { Keyboard_release(KEY_LEFT_SHIFT); } if (key & 0x04) { // Bit 2 = KEY_LEFT_ALT Keyboard_press(KEY_LEFT_ALT); } else { Keyboard_release(KEY_LEFT_ALT); } if (key & 0x08) { // Bit 3 = KEY_LEFT_GUI Keyboard_press(KEY_LEFT_GUI); } else { Keyboard_release(KEY_LEFT_GUI); } if (key & 0x10) { // Bit 4 = KEY_RIGHT_CTRL Keyboard_press(KEY_RIGHT_CTRL); } else { Keyboard_release(KEY_RIGHT_CTRL); } if (key & 0x20) { // Bit 5 = KEY_RIGHT_SHIFT Keyboard_press(KEY_RIGHT_SHIFT); } else { Keyboard_release(KEY_RIGHT_SHIFT); } if (key & 0x40) { // Bit 6 = KEY_RIGHT_ALT Keyboard_press(KEY_RIGHT_ALT); } else { Keyboard_release(KEY_RIGHT_ALT); } if (key & 0x80) { // Bit 7 = KEY_RIGHT_GUI Keyboard_press(KEY_RIGHT_GUI); } else { Keyboard_release(KEY_RIGHT_GUI); } } //Entry point for keyboard emulation uint8_t keyboard_emulation(uint8_t subtype, uint8_t value) { //Check if the input is a supported ascii value switch (subtype) { case SUBTYPE_KEYBOARD_ASCII_WRITE: if (!is_ascii(value)) return resp_invalid_key_value; Keyboard_write(value); return resp_ok; case SUBTYPE_KEYBOARD_ASCII_PRESS: if (!is_ascii(value)) return resp_invalid_key_value; Keyboard_press(value); return resp_ok; case SUBTYPE_KEYBOARD_ASCII_RELEASE: if (!is_ascii(value)) return resp_invalid_key_value; Keyboard_release(value); return resp_ok; case SUBTYPE_KEYBOARD_MODIFIER_SET: keyboard_modifying_key_set(value); return resp_ok; case SUBTYPE_KEYBOARD_MODIFIER_CLEAR: keyboard_modifying_key_set(0x00); return resp_ok; case SUBTYPE_KEYBOARD_FUNCTKEY_WRITE: if (!is_funckey(value)) return resp_invalid_key_value; Keyboard_write(value); return resp_ok; case SUBTYPE_KEYBOARD_OTHERKEY_PRESS: if (!is_validkeys(value)) return resp_invalid_key_value; Keyboard_press(value); return resp_ok; case SUBTYPE_KEYBOARD_OTHERKEY_RELEASE: if (!is_validkeys(value)) return resp_invalid_key_value; Keyboard_release(value); return resp_ok; case SUBTYPE_KEYBOARD_SPECIAL_CTRLALTDEL: // Press Ctrl + Alt + Del Keyboard_press(KEY_LEFT_CTRL); Keyboard_press(KEY_LEFT_ALT); Keyboard_press(KEY_DELETE); delay(100); // Give a little longer time for all keys to be registered together // Release Ctrl + Alt + Del in reverse order Keyboard_release(KEY_DELETE); delay(MIN_KEY_EVENTS_DELAY); Keyboard_release(KEY_LEFT_ALT); delay(MIN_KEY_EVENTS_DELAY); Keyboard_release(KEY_LEFT_CTRL); delay(MIN_KEY_EVENTS_DELAY); return resp_ok; case SUBTYPE_KEYBOARD_SPECIAL_RESET: //Release all pressed keys Keyboard_releaseAll(); return resp_ok; default: return resp_invalid_opr_type; } }