123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- package remdeshid
- import "errors"
- const (
- MOD_LCTRL = 0x01
- MOD_LSHIFT = 0x02
- MOD_LALT = 0x04
- MOD_LGUI = 0x08
- MOD_RCTRL = 0x10
- MOD_RSHIFT = 0x20
- MOD_RALT = 0x40
- MOD_RGUI = 0x80
- MOD_RENTER = 0x58
- )
- // IsModifierKey checks if the given JavaScript keycode corresponds to a modifier key
- func IsModifierKey(keycode uint8) bool {
- switch keycode {
- case 16: // Shift
- return true
- case 17: // Control
- return true
- case 18: // Alt
- return true
- case 91: // Meta (Windows/Command key)
- return true
- default:
- return false
- }
- }
- func (c *Controller) SetModifierKey(keycode uint8, isRight bool) ([]byte, error) {
- // Determine the modifier bit based on HID keycode
- var modifierBit uint8
- switch keycode {
- case 17:
- if isRight {
- modifierBit = MOD_RCTRL
- } else {
- modifierBit = MOD_LCTRL
- }
- case 16:
- if isRight {
- modifierBit = MOD_RSHIFT
- } else {
- modifierBit = MOD_LSHIFT
- }
- case 18:
- if isRight {
- modifierBit = MOD_RALT
- } else {
- modifierBit = MOD_LALT
- }
- case 91:
- if isRight {
- modifierBit = MOD_RGUI
- } else {
- modifierBit = MOD_LGUI
- }
- default:
- // Not a modifier key
- return nil, errors.ErrUnsupported
- }
- c.hidState.Modkey |= modifierBit
- return keyboardSendKeyCombinations(c)
- }
- func (c *Controller) UnsetModifierKey(keycode uint8, isRight bool) ([]byte, error) {
- // Determine the modifier bit based on HID keycode
- var modifierBit uint8
- switch keycode {
- case 17:
- if isRight {
- modifierBit = MOD_RCTRL
- } else {
- modifierBit = MOD_LCTRL
- }
- case 16:
- if isRight {
- modifierBit = MOD_RSHIFT
- } else {
- modifierBit = MOD_LSHIFT
- }
- case 18:
- if isRight {
- modifierBit = MOD_RALT
- } else {
- modifierBit = MOD_LALT
- }
- case 91:
- if isRight {
- modifierBit = MOD_RGUI
- } else {
- modifierBit = MOD_LGUI
- }
- default:
- // Not a modifier key
- return nil, errors.ErrUnsupported
- }
- c.hidState.Modkey &^= modifierBit
- return keyboardSendKeyCombinations(c)
- }
- // SendKeyboardPress sends a keyboard press by JavaScript keycode
- func (c *Controller) SendKeyboardPress(keycode uint8) ([]byte, error) {
- // Convert JavaScript keycode to HID
- keycode = javaScriptKeycodeToHIDOpcode(keycode)
- if keycode == 0x00 {
- // Not supported
- return nil, errors.New("Unsupported keycode: " + string(keycode))
- }
- // Already pressed? Skip
- for i := 0; i < 6; i++ {
- if c.hidState.KeyboardButtons[i] == keycode {
- return nil, nil
- }
- }
- // Get the empty slot in the current HID list
- for i := 0; i < 6; i++ {
- if c.hidState.KeyboardButtons[i] == 0x00 {
- c.hidState.KeyboardButtons[i] = keycode
- return keyboardSendKeyCombinations(c)
- }
- }
- // No space left
- return nil, errors.New("No space left in keyboard state to press key: " + string(keycode))
- }
- // SendKeyboardRelease sends a keyboard release by JavaScript keycode
- func (c *Controller) SendKeyboardRelease(keycode uint8) ([]byte, error) {
- // Convert JavaScript keycode to HID
- keycode = javaScriptKeycodeToHIDOpcode(keycode)
- if keycode == 0x00 {
- // Not supported
- return nil, errors.New("Unsupported keycode: " + string(keycode))
- }
- // Find the position where the key is pressed
- for i := 0; i < 6; i++ {
- if c.hidState.KeyboardButtons[i] == keycode {
- c.hidState.KeyboardButtons[i] = 0x00
- return keyboardSendKeyCombinations(c)
- }
- }
- // That key is not pressed
- return nil, nil
- }
- // keyboardSendKeyCombinations simulates sending the current key combinations
- func keyboardSendKeyCombinations(c *Controller) ([]byte, error) {
- // Prepare the packet
- packet := []uint8{
- 0x57, 0xAB, 0x00, 0x02, 0x08,
- c.hidState.Modkey, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00,
- }
- // Populate the HID keycodes
- for i := 0; i < len(c.hidState.KeyboardButtons); i++ {
- packet[7+i] = c.hidState.KeyboardButtons[i]
- }
- // Calculate checksum
- packet[13] = calcChecksum(packet[:13])
- err := c.Send(packet)
- if err != nil {
- return nil, errors.New("failed to send mouse move command: " + err.Error())
- }
- // Wait for a reply from the device
- return c.WaitForReply(0x02)
- }
- // JavaScriptKeycodeToHIDOpcode converts JavaScript keycode into HID keycode
- func javaScriptKeycodeToHIDOpcode(keycode uint8) uint8 {
- // 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 - 49) + 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 19:
- return 0x48 // Pause
- 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)
- case 59:
- return 0x33 // ';'
- case 61:
- return 0x2E // '='
- case 91:
- return 0xE3 // Left GUI (Windows)
- case 92:
- return 0xE7 // Right GUI
- case 93:
- return 0x65 // Menu key
- case 96:
- return 0x62 // 0 (Numpads)
- 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)
- case 144:
- return 0x53 // Num Lock
- case 145:
- return 0x47 // Scroll Lock
- case 146:
- return 0x58 // Numpad enter
- case 173:
- return 0x2D // -
- 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
- }
- }
|