123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- package remdeshid
- import (
- "encoding/json"
- "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
- var upgrader = websocket.Upgrader{
- ReadBufferSize: 1024,
- WriteBufferSize: 1024,
- CheckOrigin: func(r *http.Request) bool {
- return true
- },
- }
- 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)
- }
- }
- func (c *Controller) HIDWebSocketHandler(w http.ResponseWriter, r *http.Request) {
- conn, err := upgrader.Upgrade(w, r, nil)
- if err != nil {
- log.Println("Failed to upgrade to websocket:", err)
- return
- }
- defer conn.Close()
- for {
- _, message, err := conn.ReadMessage()
- if err != nil {
- log.Println("Error reading message:", err)
- break
- }
- log.Printf("Received: %s", message)
- //Try parsing the message as a HIDCommand
- var hidCmd HIDCommand
- if err := json.Unmarshal(message, &hidCmd); err != nil {
- log.Println("Error parsing message:", err)
- continue
- }
- bytes, err := c.GenerateUARTCmd(&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)
- continue
- }
- if len(bytes) == 0 {
- if err := conn.WriteMessage(websocket.TextMessage, []byte("ok")); err != nil {
- log.Println("Error writing message:", err)
- }
- continue
- }
- 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 {
- log.Println("Error writing message:", err)
- continue
- }
- }
- }
|