Files
NanoKVM-MIRROR/server/service/mcp/mouse.go
SiYue-ZO 64ce12cc0d feat(mcp): add authenticated remote control backend
Add an MCP Streamable HTTP server with token authentication, screenshot capture, keyboard, and mouse tools.

Introduce shared control-mode and input-control coordination so MCP, PicoClaw, and local HID paths serialize ownership safely.

Integrate PicoClaw gateway/runtime control handoff with PID-managed startup and focused unit coverage.
2026-07-29 15:16:06 +08:00

94 lines
2.0 KiB
Go

package mcpservice
import (
"fmt"
"math"
)
const (
maxRelativeMouseReports = 1024
maxRelativeMouseDelta = 127 * maxRelativeMouseReports
)
func absoluteCoordinate(value float64) uint16 {
value = math.Max(0, math.Min(1, value))
return uint16(math.Floor(0x7fff*value)) + 1
}
func buildAbsolutePointerReport(x uint16, y uint16, buttons byte, wheel int) []byte {
return []byte{
buttons,
byte(x), byte(x >> 8),
byte(y), byte(y >> 8),
byte(int8(clampInt(wheel, -127, 127))),
}
}
func buildRelativeMouseReport(deltaX int, deltaY int, buttons byte, wheel int) []byte {
return []byte{
buttons,
byte(int8(clampInt(deltaX, -127, 127))),
byte(int8(clampInt(deltaY, -127, 127))),
byte(int8(clampInt(wheel, -127, 127))),
}
}
func buildRelativeMoveReports(deltaX int, deltaY int) ([][]byte, error) {
if relativeReportCount(deltaX, deltaY) > maxRelativeMouseReports {
return nil, fmt.Errorf("relative movement exceeds %d reports", maxRelativeMouseReports)
}
reports := make([][]byte, 0)
for deltaX != 0 || deltaY != 0 {
x := clampInt(deltaX, -127, 127)
y := clampInt(deltaY, -127, 127)
reports = append(reports, buildRelativeMouseReport(x, y, 0, 0))
deltaX -= x
deltaY -= y
}
return reports, nil
}
func mouseButtonBit(button string) (byte, error) {
switch button {
case "left":
return 1 << 0, nil
case "right":
return 1 << 1, nil
case "middle":
return 1 << 2, nil
default:
return 0, fmt.Errorf("unknown mouse button: %s", button)
}
}
func clampInt(value int, minValue int, maxValue int) int {
if value < minValue {
return minValue
}
if value > maxValue {
return maxValue
}
return value
}
func relativeReportCount(deltaX int, deltaY int) int {
xReports := reportsForDelta(deltaX)
yReports := reportsForDelta(deltaY)
if xReports > yReports {
return xReports
}
return yReports
}
func reportsForDelta(delta int) int {
value := int64(delta)
if value == 0 {
return 0
}
if value < 0 {
return int((-(value + 1))/127 + 1)
}
return int((value-1)/127 + 1)
}