|
@@ -5,38 +5,11 @@ import (
|
|
|
"fmt"
|
|
|
"log"
|
|
|
"net/http"
|
|
|
- "time"
|
|
|
|
|
|
"github.com/gorilla/websocket"
|
|
|
)
|
|
|
|
|
|
-type EventType int
|
|
|
-
|
|
|
-const (
|
|
|
- EventTypeKeyPress EventType = iota
|
|
|
- EventTypeKeyRelease
|
|
|
- EventTypeMouseMove
|
|
|
- EventTypeMousePress
|
|
|
- EventTypeMouseRelease
|
|
|
- EventTypeMouseScroll
|
|
|
- EventTypeHIDCommand
|
|
|
-)
|
|
|
-
|
|
|
-const MinCusrorEventInterval = 1 //ms
|
|
|
-
|
|
|
-type HIDCommand struct {
|
|
|
- Event EventType `json:"event"`
|
|
|
- Keycode int `json:"keycode,omitempty"`
|
|
|
- IsRightModKey bool `json:"is_right_modifier_key,omitempty"` // true if the key is a right modifier key (Ctrl, Shift, Alt, GUI)
|
|
|
- MouseAbsX int `json:"mouse_x,omitempty"` // Absolute mouse position in X direction
|
|
|
- MouseAbsY int `json:"mouse_y,omitempty"` // Absolute mouse position in Y direction
|
|
|
- MouseRelX int `json:"mouse_rel_x,omitempty"` // Relative mouse movement in X direction
|
|
|
- MouseRelY int `json:"mouse_rel_y,omitempty"` // Relative mouse movement in Y direction
|
|
|
- MouseButton int `json:"mouse_button,omitempty"` //0x01 for left click, 0x02 for right click, 0x03 for middle clicks
|
|
|
- MouseScroll int `json:"mouse_scroll,omitempty"` // Positive for scroll up, negative for scroll down, max 127
|
|
|
-}
|
|
|
-
|
|
|
-// HIDWebSocketHandler is a handler for the HID WebSocket connection
|
|
|
+// upgrader is used to upgrade HTTP connections to WebSocket connections
|
|
|
var upgrader = websocket.Upgrader{
|
|
|
ReadBufferSize: 1024,
|
|
|
WriteBufferSize: 1024,
|
|
@@ -45,127 +18,7 @@ var upgrader = websocket.Upgrader{
|
|
|
},
|
|
|
}
|
|
|
|
|
|
-func (c *Controller) IsModifierKeys(keycode int) bool {
|
|
|
- // Modifier keycodes for JavaScript
|
|
|
- modifierKeys := []int{16, 17, 18, 91} // Shift, Ctrl, Alt, Meta (Windows/Command key)
|
|
|
- for _, key := range modifierKeys {
|
|
|
- if keycode == key {
|
|
|
- return true
|
|
|
- }
|
|
|
- }
|
|
|
- return false
|
|
|
-}
|
|
|
-
|
|
|
-// Convert a keycode to the corresponding HID opcode for modifier keys
|
|
|
-func (c *Controller) GetModkeyOpcode(keycode int, isRight bool) int {
|
|
|
- switch keycode {
|
|
|
- case 17: // Ctrl
|
|
|
- if isRight {
|
|
|
- return 0x05 // Right Ctrl
|
|
|
- }
|
|
|
- return 0x01 // Left Ctrl
|
|
|
- case 16: // Shift
|
|
|
- if isRight {
|
|
|
- return 0x06 // Right Shift
|
|
|
- }
|
|
|
- return 0x02 // Left Shift
|
|
|
- case 18: // Alt
|
|
|
- if isRight {
|
|
|
- return 0x07 // Right Alt
|
|
|
- }
|
|
|
- return 0x03 // Left Alt
|
|
|
- case 91: // Meta (Windows/Command key)
|
|
|
- if isRight {
|
|
|
- return 0x08 // Right GUI (Windows)
|
|
|
- }
|
|
|
- return 0x04 // Left GUI (Windows)
|
|
|
- default:
|
|
|
- return 0x00 // Unknown or unmapped key
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// Generate the required LTV (length, type, value) bytes for the HID command
|
|
|
-func (c *Controller) GenerateUARTCmd(HIDCommand *HIDCommand) ([]byte, error) {
|
|
|
- switch HIDCommand.Event {
|
|
|
- case EventTypeKeyPress:
|
|
|
- if c.IsModifierKeys(HIDCommand.Keycode) {
|
|
|
- // If it's a modifier key, we need to return the appropriate opcode
|
|
|
- opcode := c.GetModkeyOpcode(HIDCommand.Keycode, HIDCommand.IsRightModKey)
|
|
|
- if opcode == 0x00 {
|
|
|
- return nil, fmt.Errorf("unsupported modifier key: %d", HIDCommand.Keycode)
|
|
|
- }
|
|
|
- return []byte{0x02, 0x03, byte(opcode)}, nil
|
|
|
- } else if HIDCommand.Keycode == 13 && HIDCommand.IsRightModKey {
|
|
|
- //Special case for right Enter key
|
|
|
- return []byte{0x02, 0x01, 0x92}, nil
|
|
|
- }
|
|
|
- return []byte{0x02, 0x01, byte(HIDCommand.Keycode)}, nil
|
|
|
- case EventTypeKeyRelease:
|
|
|
- if c.IsModifierKeys(HIDCommand.Keycode) {
|
|
|
- // If it's a modifier key, we need to return the appropriate opcode
|
|
|
- opcode := c.GetModkeyOpcode(HIDCommand.Keycode, HIDCommand.IsRightModKey)
|
|
|
- if opcode == 0x00 {
|
|
|
- return nil, fmt.Errorf("unsupported modifier key: %d", HIDCommand.Keycode)
|
|
|
- }
|
|
|
- return []byte{0x02, 0x04, byte(opcode)}, nil
|
|
|
- } else if HIDCommand.Keycode == 13 && HIDCommand.IsRightModKey {
|
|
|
- //Special case for right Enter key
|
|
|
- return []byte{0x02, 0x02, 0x92}, nil
|
|
|
- }
|
|
|
- return []byte{0x02, 0x02, byte(HIDCommand.Keycode)}, nil
|
|
|
- case EventTypeMouseMove:
|
|
|
- if (time.Now().UnixMilli() - c.lastCursorEventTime) < MinCusrorEventInterval {
|
|
|
- // If the last cursor event was too recent, we skip sending this one
|
|
|
- return []byte{}, nil
|
|
|
- }
|
|
|
- c.lastCursorEventTime = time.Now().UnixMilli()
|
|
|
- if HIDCommand.MouseAbsX != 0 || HIDCommand.MouseAbsY != 0 {
|
|
|
- // If absolute mouse movement is specified, we send it as a single command
|
|
|
- xLSB := byte(HIDCommand.MouseAbsX & 0xFF)
|
|
|
- xMSB := byte((HIDCommand.MouseAbsX >> 8) & 0xFF)
|
|
|
- yLSB := byte(HIDCommand.MouseAbsY & 0xFF)
|
|
|
- yMSB := byte((HIDCommand.MouseAbsY >> 8) & 0xFF)
|
|
|
- return []byte{0x05, 0x09, xLSB, xMSB, yLSB, yMSB}, nil
|
|
|
- } else if HIDCommand.MouseRelX != 0 || HIDCommand.MouseRelY != 0 {
|
|
|
- // If relative mouse movement is specified, we send it as a single command
|
|
|
- //TODO
|
|
|
- return []byte{0x03, 0x0A, byte(HIDCommand.MouseRelX), byte(HIDCommand.MouseRelY)}, nil
|
|
|
- }
|
|
|
- return nil, fmt.Errorf("no mouse movement specified")
|
|
|
- case EventTypeMousePress:
|
|
|
- if HIDCommand.MouseButton < 1 || HIDCommand.MouseButton > 3 {
|
|
|
- return nil, fmt.Errorf("invalid mouse button: %d", HIDCommand.MouseButton)
|
|
|
- }
|
|
|
- // Mouse button click event
|
|
|
- return []byte{0x02, 0x05, byte(HIDCommand.MouseButton)}, nil
|
|
|
- case EventTypeMouseRelease:
|
|
|
- if HIDCommand.MouseButton < 1 || HIDCommand.MouseButton > 3 {
|
|
|
- return nil, fmt.Errorf("invalid mouse button: %d", HIDCommand.MouseButton)
|
|
|
- }
|
|
|
- // Mouse button release event
|
|
|
- return []byte{0x02, 0x06, byte(HIDCommand.MouseButton)}, nil
|
|
|
- case EventTypeMouseScroll:
|
|
|
- if (time.Now().UnixMilli() - c.lastCursorEventTime) < MinCusrorEventInterval {
|
|
|
- // If the last cursor event was too recent, we skip sending this one
|
|
|
- return []byte{}, nil
|
|
|
- }
|
|
|
- c.lastCursorEventTime = time.Now().UnixMilli()
|
|
|
-
|
|
|
- if HIDCommand.MouseScroll < -127 || HIDCommand.MouseScroll > 127 {
|
|
|
- return nil, fmt.Errorf("invalid mouse scroll value: %d", HIDCommand.MouseScroll)
|
|
|
- }
|
|
|
- // Mouse scroll event
|
|
|
- if HIDCommand.MouseScroll < 0 {
|
|
|
- return []byte{0x02, 0x07, byte(HIDCommand.MouseScroll * -1)}, nil
|
|
|
- } else {
|
|
|
- return []byte{0x02, 0x08, byte(HIDCommand.MouseScroll)}, nil
|
|
|
- }
|
|
|
-
|
|
|
- default:
|
|
|
- return nil, fmt.Errorf("unsupported HID command event type: %d", HIDCommand.Event)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
+// HIDWebSocketHandler handles incoming WebSocket connections for HID commands
|
|
|
func (c *Controller) HIDWebSocketHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
conn, err := upgrader.Upgrade(w, r, nil)
|
|
|
if err != nil {
|
|
@@ -189,38 +42,25 @@ func (c *Controller) HIDWebSocketHandler(w http.ResponseWriter, r *http.Request)
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- bytes, err := c.GenerateUARTCmd(&hidCmd)
|
|
|
+ bytes, err := c.ConstructAndSendCmd(&hidCmd)
|
|
|
if err != nil {
|
|
|
errmsg := map[string]string{"error": err.Error()}
|
|
|
if err := conn.WriteJSON(errmsg); err != nil {
|
|
|
log.Println("Error writing message:", err)
|
|
|
continue
|
|
|
}
|
|
|
- log.Println("Error generating UART command:", err)
|
|
|
+ log.Println("Error sending command:", err)
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- if len(bytes) == 0 {
|
|
|
- if err := conn.WriteMessage(websocket.TextMessage, []byte("ok")); err != nil {
|
|
|
- log.Println("Error writing message:", err)
|
|
|
- }
|
|
|
- continue
|
|
|
+ prettyBytes := ""
|
|
|
+ for _, b := range bytes {
|
|
|
+ prettyBytes += fmt.Sprintf("0x%02X ", b)
|
|
|
}
|
|
|
-
|
|
|
- fmt.Println("Sending bytes:", bytes)
|
|
|
-
|
|
|
- //Write the bytes to the serial port
|
|
|
- if err := c.Send(bytes); err != nil {
|
|
|
- errmsg := map[string]string{"error": err.Error()}
|
|
|
- if err := conn.WriteJSON(errmsg); err != nil {
|
|
|
- log.Println("Error writing message:", err)
|
|
|
- }
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- if err := conn.WriteMessage(websocket.TextMessage, []byte("ok")); err != nil {
|
|
|
+ if err := conn.WriteMessage(websocket.TextMessage, []byte(prettyBytes)); err != nil {
|
|
|
log.Println("Error writing message:", err)
|
|
|
continue
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
}
|