hidcomm.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. package remdeshid
  2. /*
  3. hidcomm.go
  4. This file contains functions to convert HID commands to bytes
  5. that can be sent over the USBKVM device
  6. */
  7. import (
  8. "errors"
  9. "fmt"
  10. )
  11. // Append the keyboard event subtypes to the data
  12. func appendKeyboardEventSubtypes(data []byte, cmd HIDCommand) ([]byte, error) {
  13. /* Keyboard Subtypes */
  14. if len(cmd.Data) == 1 && cmd.Data[0] >= 32 && cmd.Data[0] <= 127 {
  15. //Valid ASCII character
  16. if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_DOWN {
  17. data = append(data, SUBTYPE_KEYBOARD_ASCII_PRESS)
  18. } else if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_UP {
  19. data = append(data, SUBTYPE_KEYBOARD_ASCII_RELEASE)
  20. } else {
  21. //Key Click
  22. data = append(data, SUBTYPE_KEYBOARD_ASCII_WRITE)
  23. }
  24. data = append(data, cmd.Data[0])
  25. return data, nil
  26. } else if isFuncKey(cmd.Data) {
  27. //Function Key
  28. if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_DOWN {
  29. data = append(data, SUBTYPE_KEYBOARD_FUNCTKEY_PRESS)
  30. } else {
  31. data = append(data, SUBTYPE_KEYBOARD_FUNCTKEY_RELEASE)
  32. }
  33. data = append(data, funcKeyToByte(cmd.Data))
  34. if data[0] == 0xFF {
  35. return nil, fmt.Errorf("invalid function key: %v", cmd.Data)
  36. }
  37. return data, nil
  38. } else if isModifierKey(cmd.Data) {
  39. //Modifier Key
  40. if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_DOWN {
  41. data = append(data, SUBTYPE_KEYBOARD_MODIFIER_PRESS)
  42. } else {
  43. data = append(data, SUBTYPE_KEYBOARD_MODIFIER_RELEASE)
  44. }
  45. data = append(data, modifierKeyToByte(cmd.Data))
  46. if data[0] == 0xFF {
  47. return nil, fmt.Errorf("invalid modifier key: %v", cmd.Data)
  48. }
  49. return data, nil
  50. } else if isOtherKeys(cmd.Data) {
  51. //Other Keys
  52. if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_DOWN {
  53. data = append(data, SUBTYPE_KEYBOARD_OTHERKEY_PRESS)
  54. } else if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_UP {
  55. data = append(data, SUBTYPE_KEYBOARD_OTHERKEY_RELEASE)
  56. } else {
  57. return nil, fmt.Errorf("invalid HID command subtype: %v", cmd.Data)
  58. }
  59. data = append(data, nonAsciiKeysToBytes(cmd.Data)...)
  60. return data, nil
  61. } else if isNumpadKey(cmd.Data) {
  62. //Numpad Keys
  63. if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_DOWN {
  64. data = append(data, SUBTYPE_KEYBOARD_NUMPAD_PRESS)
  65. } else if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_UP {
  66. data = append(data, SUBTYPE_KEYBOARD_NUMPAD_RELEASE)
  67. } else {
  68. return nil, fmt.Errorf("invalid HID command subtype: %v", cmd.Data)
  69. }
  70. data = append(data, numpadKeyToByte(string(cmd.Data)))
  71. return data, nil
  72. } else if cmd.Data == "NumLock" {
  73. if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_DOWN {
  74. data = append(data, SUBTYPE_KEYBOARD_SPECIAL_NUMLOCK)
  75. data = append(data, 0x00)
  76. return data, nil
  77. }
  78. return nil, fmt.Errorf("numLock do not support key up")
  79. } else if cmd.Data == "Pause" {
  80. if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_DOWN {
  81. data = append(data, SUBTYPE_KEYBOARD_SPECIAL_PAUSE)
  82. data = append(data, 0x00)
  83. return data, nil
  84. }
  85. return nil, fmt.Errorf("pause do not support key up")
  86. } else if cmd.Data == "PrintScreen" {
  87. if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_UP {
  88. data = append(data, SUBTYPE_KEYBOARD_SPECIAL_PRINT_SCREEN)
  89. data = append(data, 0x00)
  90. return data, nil
  91. }
  92. return nil, fmt.Errorf("printScreen do not support key down")
  93. } else if cmd.Data == "ScrollLock" {
  94. if cmd.EventSubType == FRONTEND_SUBTYPE_KEYBOARD_KEY_DOWN {
  95. data = append(data, SUBTYPE_KEYBOARD_SPECIAL_SCROLL_LOCK)
  96. data = append(data, 0x00)
  97. return data, nil
  98. }
  99. return nil, fmt.Errorf("scrollLock do not support key up")
  100. } else if cmd.Data == "ContextMenu" {
  101. //Special Key: ContextMenu
  102. //TODO: Implement ContextMenu
  103. return nil, fmt.Errorf("ContextMenu not implemented")
  104. } else if cmd.Data == "Ctrl+Alt+Del" {
  105. //Special Key: Ctrl+Alt+Del
  106. data = append(data, SUBTYPE_KEYBOARD_SPECIAL_CTRLALTDEL)
  107. data = append(data, 0x00)
  108. return data, nil
  109. } else {
  110. return nil, fmt.Errorf("invalid HID command subtype: %v", cmd.Data)
  111. }
  112. }
  113. // Append the mouse click event subtypes to the data
  114. func appendMouseClickEventSubtypes(data []byte, cmd HIDCommand) ([]byte, error) {
  115. /* Mouse Click Subtypes */
  116. isPress := cmd.EventSubType == FRONTEND_MOUSE_PRESS
  117. if isPress {
  118. //Mouse Button Press
  119. data = append(data, 0x02)
  120. } else {
  121. //Mouse Button Release
  122. data = append(data, 0x03)
  123. }
  124. if cmd.Data == FRONTEND_MOUSE_BTN_LEFT {
  125. data = append(data, PAYLOAD_MOUSE_BTN_LEFT)
  126. } else if cmd.Data == FRONTEND_MOUSE_BTN_MIDDLE {
  127. data = append(data, PAYLOAD_MOUSE_BTN_MID)
  128. } else if cmd.Data == FRONTEND_MOUSE_BTN_RIGHT {
  129. data = append(data, PAYLOAD_MOUSE_BTN_RIGHT)
  130. } else {
  131. return nil, fmt.Errorf("invalid HID command subtype: %v", cmd.Data)
  132. }
  133. return data, nil
  134. }
  135. // Append the mouse move event subtypes to the data
  136. func appendMouseMoveEventSubtypes(data []byte, cmd HIDCommand) ([]byte, error) {
  137. //The mouse move command requires x_pos, y_pos, x_sign, y_sign
  138. x_pos := cmd.PosX
  139. y_pos := cmd.PosY
  140. xIsNegative := x_pos < 0
  141. yIsNegative := y_pos < 0
  142. x_sign := 0
  143. y_sign := 0
  144. if xIsNegative {
  145. x_pos = -x_pos
  146. x_sign = 1
  147. }
  148. if yIsNegative {
  149. y_pos = -y_pos
  150. y_sign = 1
  151. }
  152. //The max value for x_pos and y_pos are 0xFE, make sure they are within the range
  153. if x_pos > 0xFE {
  154. x_pos = 0xFE
  155. }
  156. if y_pos > 0xFE {
  157. y_pos = 0xFE
  158. }
  159. data = append(data, byte(x_pos), byte(y_pos), byte(x_sign), byte(y_sign))
  160. return data, nil
  161. }
  162. // Append the mouse scroll event subtypes to the data
  163. func appendMouseScrollEventSubtypes(data []byte, cmd HIDCommand) ([]byte, error) {
  164. //The mouse scroll command PosY contains the scroll value
  165. //The scroll command require a direction byte and a scroll value byte
  166. scrollValue := cmd.PosY
  167. var sensitivity byte = 0x02
  168. if scrollValue < 0 {
  169. //Scroll up
  170. data = append(data, 0x00) //Up
  171. data = append(data, sensitivity) //Sensitive
  172. } else {
  173. //Scroll down
  174. data = append(data, 0x01) //Down
  175. data = append(data, sensitivity) //Sensitive
  176. }
  177. return data, nil
  178. }
  179. // Append the switch subtypes to the data
  180. func appendSwitchOperationsEventSubtypes(data []byte, cmd HIDCommand) ([]byte, error) {
  181. if cmd.EventSubType == "hid" {
  182. data = append(data, SUBTYPE_SWITCH_USB_HID)
  183. if cmd.Data == "connect" {
  184. //Set switch state to 0x00
  185. data = append(data, 0x00)
  186. return data, nil
  187. } else if cmd.Data == "disconnect" {
  188. //Set switch state to 0x01
  189. data = append(data, 0x01)
  190. return data, nil
  191. } else if cmd.Data == "reset" {
  192. data = append(data, 0x02)
  193. return data, nil
  194. }
  195. return []byte{}, errors.New("unknown value: only support 'connect' and 'disconnect'")
  196. } else if cmd.EventSubType == "mass-storage" {
  197. data = append(data, SUBTYPE_SWITCH_USB_MASS)
  198. if cmd.Data == "host" {
  199. //Set switch state to 0x00
  200. data = append(data, 0x00)
  201. return data, nil
  202. } else if cmd.Data == "slave" {
  203. //Set switch state to 0x01
  204. data = append(data, 0x01)
  205. return data, nil
  206. }
  207. return []byte{}, errors.New("unknown value: only support 'host' and 'slave'")
  208. }
  209. //Unknown operatuins
  210. return []byte{}, errors.New("unknown switch subtypes")
  211. }
  212. // Entry function for converting a HIDCommand to bytes that can be sent over the USBKVM device
  213. func ConvHIDCommandToBytes(cmd HIDCommand) ([]byte, error) {
  214. // Convert the HID command to bytes
  215. var data []byte
  216. if cmd.EventType == FRONTEND_OPR_TYPE_KEYBOARD_WRITE {
  217. /* Keyboard Write Event */
  218. data = []byte{OPR_TYPE_KEYBOARD_WRITE}
  219. return appendKeyboardEventSubtypes(data, cmd)
  220. } else if cmd.EventType == FRONTEND_OPR_TYPE_MOUSE_WRITE {
  221. /* Mouse Write Event */
  222. data = []byte{OPR_TYPE_MOUSE_WRITE}
  223. return appendMouseClickEventSubtypes(data, cmd)
  224. } else if cmd.EventType == FRONTEND_OPR_TYPE_MOUSE_MOVE {
  225. /* Mouse Move Event */
  226. data = []byte{OPR_TYPE_MOUSE_MOVE}
  227. return appendMouseMoveEventSubtypes(data, cmd)
  228. } else if cmd.EventType == FRONTEND_OPR_TYPE_MOUSE_SCROLL {
  229. /* Mouse Scroll Event */
  230. data = []byte{OPR_TYPE_MOUSE_SCROLL}
  231. return appendMouseScrollEventSubtypes(data, cmd)
  232. } else if cmd.EventType == FRONTEND_OPR_TYPE_SWITCH {
  233. data = []byte{OPR_TYPE_SWITCH_SET}
  234. return appendSwitchOperationsEventSubtypes(data, cmd)
  235. } else if cmd.EventType == FRONT_END_OPR_RESET {
  236. /* Reset Event */
  237. data = []byte{OPR_TYPE_DATA_RESET, //Reset the data queue
  238. OPR_TYPE_KEYBOARD_WRITE, SUBTYPE_KEYBOARD_SPECIAL_RESET, 0x00, //Reset the keyboard press state
  239. OPR_TYPE_MOUSE_WRITE, SUBTYPE_MOUSE_RESET, 0x00} //Reset the mouse press state
  240. return data, nil
  241. }
  242. return nil, fmt.Errorf("invalid HID command type: %s", cmd.EventType)
  243. }