keyboard.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. package remdeshid
  2. import "errors"
  3. const (
  4. MOD_LCTRL = 0x01
  5. MOD_LSHIFT = 0x02
  6. MOD_LALT = 0x04
  7. MOD_LGUI = 0x08
  8. MOD_RCTRL = 0x10
  9. MOD_RSHIFT = 0x20
  10. MOD_RALT = 0x40
  11. MOD_RGUI = 0x80
  12. MOD_RENTER = 0x58
  13. )
  14. // IsModifierKey checks if the given JavaScript keycode corresponds to a modifier key
  15. func IsModifierKey(keycode uint8) bool {
  16. switch keycode {
  17. case 16: // Shift
  18. return true
  19. case 17: // Control
  20. return true
  21. case 18: // Alt
  22. return true
  23. case 91: // Meta (Windows/Command key)
  24. return true
  25. default:
  26. return false
  27. }
  28. }
  29. func (c *Controller) SetModifierKey(keycode uint8, isRight bool) ([]byte, error) {
  30. // Determine the modifier bit based on HID keycode
  31. var modifierBit uint8
  32. switch keycode {
  33. case 17:
  34. if isRight {
  35. modifierBit = MOD_RCTRL
  36. } else {
  37. modifierBit = MOD_LCTRL
  38. }
  39. case 16:
  40. if isRight {
  41. modifierBit = MOD_RSHIFT
  42. } else {
  43. modifierBit = MOD_LSHIFT
  44. }
  45. case 18:
  46. if isRight {
  47. modifierBit = MOD_RALT
  48. } else {
  49. modifierBit = MOD_LALT
  50. }
  51. case 91:
  52. if isRight {
  53. modifierBit = MOD_RGUI
  54. } else {
  55. modifierBit = MOD_LGUI
  56. }
  57. default:
  58. // Not a modifier key
  59. return nil, errors.ErrUnsupported
  60. }
  61. c.hidState.Modkey |= modifierBit
  62. return keyboardSendKeyCombinations(c)
  63. }
  64. func (c *Controller) UnsetModifierKey(keycode uint8, isRight bool) ([]byte, error) {
  65. // Determine the modifier bit based on HID keycode
  66. var modifierBit uint8
  67. switch keycode {
  68. case 17:
  69. if isRight {
  70. modifierBit = MOD_RCTRL
  71. } else {
  72. modifierBit = MOD_LCTRL
  73. }
  74. case 16:
  75. if isRight {
  76. modifierBit = MOD_RSHIFT
  77. } else {
  78. modifierBit = MOD_LSHIFT
  79. }
  80. case 18:
  81. if isRight {
  82. modifierBit = MOD_RALT
  83. } else {
  84. modifierBit = MOD_LALT
  85. }
  86. case 91:
  87. if isRight {
  88. modifierBit = MOD_RGUI
  89. } else {
  90. modifierBit = MOD_LGUI
  91. }
  92. default:
  93. // Not a modifier key
  94. return nil, errors.ErrUnsupported
  95. }
  96. c.hidState.Modkey &^= modifierBit
  97. return keyboardSendKeyCombinations(c)
  98. }
  99. // SendKeyboardPress sends a keyboard press by JavaScript keycode
  100. func (c *Controller) SendKeyboardPress(keycode uint8) ([]byte, error) {
  101. // Convert JavaScript keycode to HID
  102. keycode = javaScriptKeycodeToHIDOpcode(keycode)
  103. if keycode == 0x00 {
  104. // Not supported
  105. return nil, errors.New("Unsupported keycode: " + string(keycode))
  106. }
  107. // Already pressed? Skip
  108. for i := 0; i < 6; i++ {
  109. if c.hidState.KeyboardButtons[i] == keycode {
  110. return nil, nil
  111. }
  112. }
  113. // Get the empty slot in the current HID list
  114. for i := 0; i < 6; i++ {
  115. if c.hidState.KeyboardButtons[i] == 0x00 {
  116. c.hidState.KeyboardButtons[i] = keycode
  117. return keyboardSendKeyCombinations(c)
  118. }
  119. }
  120. // No space left
  121. return nil, errors.New("No space left in keyboard state to press key: " + string(keycode))
  122. }
  123. // SendKeyboardRelease sends a keyboard release by JavaScript keycode
  124. func (c *Controller) SendKeyboardRelease(keycode uint8) ([]byte, error) {
  125. // Convert JavaScript keycode to HID
  126. keycode = javaScriptKeycodeToHIDOpcode(keycode)
  127. if keycode == 0x00 {
  128. // Not supported
  129. return nil, errors.New("Unsupported keycode: " + string(keycode))
  130. }
  131. // Find the position where the key is pressed
  132. for i := 0; i < 6; i++ {
  133. if c.hidState.KeyboardButtons[i] == keycode {
  134. c.hidState.KeyboardButtons[i] = 0x00
  135. return keyboardSendKeyCombinations(c)
  136. }
  137. }
  138. // That key is not pressed
  139. return nil, nil
  140. }
  141. // keyboardSendKeyCombinations simulates sending the current key combinations
  142. func keyboardSendKeyCombinations(c *Controller) ([]byte, error) {
  143. // Prepare the packet
  144. packet := []uint8{
  145. 0x57, 0xAB, 0x00, 0x02, 0x08,
  146. c.hidState.Modkey, 0x00,
  147. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  148. 0x00,
  149. }
  150. // Populate the HID keycodes
  151. for i := 0; i < len(c.hidState.KeyboardButtons); i++ {
  152. packet[7+i] = c.hidState.KeyboardButtons[i]
  153. }
  154. // Calculate checksum
  155. packet[13] = calcChecksum(packet[:13])
  156. err := c.Send(packet)
  157. if err != nil {
  158. return nil, errors.New("failed to send mouse move command: " + err.Error())
  159. }
  160. // Wait for a reply from the device
  161. return c.WaitForReply(0x02)
  162. }
  163. // JavaScriptKeycodeToHIDOpcode converts JavaScript keycode into HID keycode
  164. func javaScriptKeycodeToHIDOpcode(keycode uint8) uint8 {
  165. // Letters A-Z
  166. if keycode >= 65 && keycode <= 90 {
  167. return (keycode - 65) + 0x04 // 'A' is 0x04
  168. }
  169. // Numbers 1-9 (top row, not numpad)
  170. if keycode >= 49 && keycode <= 57 {
  171. return (keycode - 49) + 0x1E // '1' is 0x1E
  172. }
  173. // Numpad 1-9
  174. if keycode >= 97 && keycode <= 105 {
  175. return (keycode - 97) + 0x59 // '1' (numpad) is 0x59
  176. }
  177. // F1 to F12
  178. if keycode >= 112 && keycode <= 123 {
  179. return (keycode - 112) + 0x3A // 'F1' is 0x3A
  180. }
  181. switch keycode {
  182. case 8:
  183. return 0x2A // Backspace
  184. case 9:
  185. return 0x2B // Tab
  186. case 13:
  187. return 0x28 // Enter
  188. case 16:
  189. return 0xE1 // Left shift
  190. case 17:
  191. return 0xE0 // Left Ctrl
  192. case 18:
  193. return 0xE6 // Left Alt
  194. case 19:
  195. return 0x48 // Pause
  196. case 20:
  197. return 0x39 // Caps Lock
  198. case 27:
  199. return 0x29 // Escape
  200. case 32:
  201. return 0x2C // Spacebar
  202. case 33:
  203. return 0x4B // Page Up
  204. case 34:
  205. return 0x4E // Page Down
  206. case 35:
  207. return 0x4D // End
  208. case 36:
  209. return 0x4A // Home
  210. case 37:
  211. return 0x50 // Left Arrow
  212. case 38:
  213. return 0x52 // Up Arrow
  214. case 39:
  215. return 0x4F // Right Arrow
  216. case 40:
  217. return 0x51 // Down Arrow
  218. case 44:
  219. return 0x46 // Print Screen or F13 (Firefox)
  220. case 45:
  221. return 0x49 // Insert
  222. case 46:
  223. return 0x4C // Delete
  224. case 48:
  225. return 0x27 // 0 (not Numpads)
  226. case 59:
  227. return 0x33 // ';'
  228. case 61:
  229. return 0x2E // '='
  230. case 91:
  231. return 0xE3 // Left GUI (Windows)
  232. case 92:
  233. return 0xE7 // Right GUI
  234. case 93:
  235. return 0x65 // Menu key
  236. case 96:
  237. return 0x62 // 0 (Numpads)
  238. case 106:
  239. return 0x55 // * (Numpads)
  240. case 107:
  241. return 0x57 // + (Numpads)
  242. case 109:
  243. return 0x56 // - (Numpads)
  244. case 110:
  245. return 0x63 // dot (Numpads)
  246. case 111:
  247. return 0x54 // divide (Numpads)
  248. case 144:
  249. return 0x53 // Num Lock
  250. case 145:
  251. return 0x47 // Scroll Lock
  252. case 146:
  253. return 0x58 // Numpad enter
  254. case 173:
  255. return 0x2D // -
  256. case 186:
  257. return 0x33 // ';'
  258. case 187:
  259. return 0x2E // '='
  260. case 188:
  261. return 0x36 // ','
  262. case 189:
  263. return 0x2D // '-'
  264. case 190:
  265. return 0x37 // '.'
  266. case 191:
  267. return 0x38 // '/'
  268. case 192:
  269. return 0x35 // '`'
  270. case 219:
  271. return 0x2F // '['
  272. case 220:
  273. return 0x31 // backslash
  274. case 221:
  275. return 0x30 // ']'
  276. case 222:
  277. return 0x34 // '\''
  278. default:
  279. return 0x00 // Unknown / unsupported
  280. }
  281. }