Improvements: input performance

This commit is contained in:
Alex P 2025-09-09 20:58:34 +00:00
parent 8cff7d600b
commit 2a81497d34
3 changed files with 66 additions and 81 deletions

View File

@ -35,7 +35,7 @@ func handleHidRPCMessage(message hidrpc.Message, session *Session) {
logger.Warn().Err(err).Msg("failed to get pointer report") logger.Warn().Err(err).Msg("failed to get pointer report")
return return
} }
rpcErr = rpcAbsMouseReport(pointerReport.X, pointerReport.Y, pointerReport.Button) rpcErr = rpcAbsMouseReport(uint16(pointerReport.X), uint16(pointerReport.Y), pointerReport.Button)
case hidrpc.TypeMouseReport: case hidrpc.TypeMouseReport:
mouseReport, err := message.MouseReport() mouseReport, err := message.MouseReport()
if err != nil { if err != nil {

View File

@ -35,17 +35,18 @@ type InputRPCRequest struct {
Method string `json:"method"` Method string `json:"method"`
ID any `json:"id,omitempty"` ID any `json:"id,omitempty"`
// Union of all possible input parameters - only relevant fields are populated // Union of all possible input parameters - only relevant fields are populated
// Fields ordered for optimal 32-bit alignment: slice pointers, 2-byte fields, 1-byte fields
Params struct { Params struct {
// Keyboard parameters // Slice pointers (4 bytes on 32-bit ARM)
Modifier *uint8 `json:"modifier,omitempty"`
Keys *[]uint8 `json:"keys,omitempty"` Keys *[]uint8 `json:"keys,omitempty"`
// Mouse parameters // 2-byte fields grouped together
X *int `json:"x,omitempty"` X *uint16 `json:"x,omitempty"`
Y *int `json:"y,omitempty"` Y *uint16 `json:"y,omitempty"`
// 1-byte fields grouped together for optimal packing
Modifier *uint8 `json:"modifier,omitempty"`
Dx *int8 `json:"dx,omitempty"` Dx *int8 `json:"dx,omitempty"`
Dy *int8 `json:"dy,omitempty"` Dy *int8 `json:"dy,omitempty"`
Buttons *uint8 `json:"buttons,omitempty"` Buttons *uint8 `json:"buttons,omitempty"`
// Wheel parameters
WheelY *int8 `json:"wheelY,omitempty"` WheelY *int8 `json:"wheelY,omitempty"`
} `json:"params,omitempty"` } `json:"params,omitempty"`
} }
@ -77,15 +78,7 @@ func validateKeysArray(params map[string]interface{}, methodName string) ([]uint
keys[i] = uint8(intVal) keys[i] = uint8(intVal)
continue continue
} }
// Fallback to float64 for compatibility with existing clients
if floatVal, ok := keyInterface.(float64); ok {
intVal := int(floatVal)
if floatVal != float64(intVal) || intVal < 0 || intVal > 255 {
return nil, fmt.Errorf("%s: key at index %d value %v invalid for uint8 (must be integer 0-255)", methodName, i, floatVal)
}
keys[i] = uint8(intVal)
continue
}
return nil, fmt.Errorf("%s: key at index %d must be a number, got %T", methodName, i, keyInterface) return nil, fmt.Errorf("%s: key at index %d must be a number, got %T", methodName, i, keyInterface)
} }
return keys, nil return keys, nil
@ -103,10 +96,10 @@ type KeyboardReportParams struct {
} }
// AbsMouseReportParams represents parameters for absolute mouse positioning // AbsMouseReportParams represents parameters for absolute mouse positioning
// Matches rpcAbsMouseReport(x, y int, buttons uint8) // Matches rpcAbsMouseReport(x, y uint16, buttons uint8)
type AbsMouseReportParams struct { type AbsMouseReportParams struct {
X int `json:"x"` // Absolute X coordinate (0-32767) X uint16 `json:"x"` // Absolute X coordinate (0-32767)
Y int `json:"y"` // Absolute Y coordinate (0-32767) Y uint16 `json:"y"` // Absolute Y coordinate (0-32767)
Buttons uint8 `json:"buttons"` // Mouse button state bitmask Buttons uint8 `json:"buttons"` // Mouse button state bitmask
} }
@ -150,7 +143,7 @@ func handleInputRPCUltraFast(data []byte) (interface{}, error) {
return nil, fmt.Errorf("absMouseReport: missing required parameters") return nil, fmt.Errorf("absMouseReport: missing required parameters")
} }
x, y, buttons := *request.Params.X, *request.Params.Y, *request.Params.Buttons x, y, buttons := *request.Params.X, *request.Params.Y, *request.Params.Buttons
if x < 0 || x > 32767 || y < 0 || y > 32767 { if x > 32767 || y > 32767 {
return nil, fmt.Errorf("absMouseReport: coordinates out of range") return nil, fmt.Errorf("absMouseReport: coordinates out of range")
} }
return nil, rpcAbsMouseReport(x, y, buttons) return nil, rpcAbsMouseReport(x, y, buttons)
@ -183,11 +176,10 @@ func handleKeyboardReportDirect(params map[string]interface{}) (interface{}, err
} }
modifier = uint8(intVal) modifier = uint8(intVal)
} else if floatVal, ok := params["modifier"].(float64); ok { } else if floatVal, ok := params["modifier"].(float64); ok {
intVal := int(floatVal) if floatVal != float64(int(floatVal)) || floatVal < 0 || floatVal > 255 {
if floatVal != float64(intVal) || intVal < 0 || intVal > 255 {
return nil, fmt.Errorf("keyboardReport: modifier value %v invalid", floatVal) return nil, fmt.Errorf("keyboardReport: modifier value %v invalid", floatVal)
} }
modifier = uint8(intVal) modifier = uint8(floatVal)
} else { } else {
return nil, fmt.Errorf("keyboardReport: modifier must be a number") return nil, fmt.Errorf("keyboardReport: modifier must be a number")
} }
@ -205,36 +197,34 @@ func handleKeyboardReportDirect(params map[string]interface{}) (interface{}, err
// Direct handler for absolute mouse reports // Direct handler for absolute mouse reports
// Ultra-optimized path with inlined validation for maximum performance // Ultra-optimized path with inlined validation for maximum performance
func handleAbsMouseReportDirect(params map[string]interface{}) (interface{}, error) { func handleAbsMouseReportDirect(params map[string]interface{}) (interface{}, error) {
// Inline x coordinate validation // Inline x coordinate validation - check float64 first (most common JSON number type)
var x int var x uint16
if intVal, ok := params["x"].(int); ok { if floatVal, ok := params["x"].(float64); ok {
if floatVal != float64(int(floatVal)) || floatVal < 0 || floatVal > 32767 {
return nil, fmt.Errorf("absMouseReport: x value %v invalid", floatVal)
}
x = uint16(floatVal)
} else if intVal, ok := params["x"].(int); ok {
if intVal < 0 || intVal > 32767 { if intVal < 0 || intVal > 32767 {
return nil, fmt.Errorf("absMouseReport: x value %d out of range [0-32767]", intVal) return nil, fmt.Errorf("absMouseReport: x value %d out of range [0-32767]", intVal)
} }
x = intVal x = uint16(intVal)
} else if floatVal, ok := params["x"].(float64); ok {
intVal := int(floatVal)
if floatVal != float64(intVal) || intVal < 0 || intVal > 32767 {
return nil, fmt.Errorf("absMouseReport: x value %v invalid", floatVal)
}
x = intVal
} else { } else {
return nil, fmt.Errorf("absMouseReport: x must be a number") return nil, fmt.Errorf("absMouseReport: x must be a number")
} }
// Inline y coordinate validation // Inline y coordinate validation - check float64 first (most common JSON number type)
var y int var y uint16
if intVal, ok := params["y"].(int); ok { if floatVal, ok := params["y"].(float64); ok {
if floatVal != float64(int(floatVal)) || floatVal < 0 || floatVal > 32767 {
return nil, fmt.Errorf("absMouseReport: y value %v invalid", floatVal)
}
y = uint16(floatVal)
} else if intVal, ok := params["y"].(int); ok {
if intVal < 0 || intVal > 32767 { if intVal < 0 || intVal > 32767 {
return nil, fmt.Errorf("absMouseReport: y value %d out of range [0-32767]", intVal) return nil, fmt.Errorf("absMouseReport: y value %d out of range [0-32767]", intVal)
} }
y = intVal y = uint16(intVal)
} else if floatVal, ok := params["y"].(float64); ok {
intVal := int(floatVal)
if floatVal != float64(intVal) || intVal < 0 || intVal > 32767 {
return nil, fmt.Errorf("absMouseReport: y value %v invalid", floatVal)
}
y = intVal
} else { } else {
return nil, fmt.Errorf("absMouseReport: y must be a number") return nil, fmt.Errorf("absMouseReport: y must be a number")
} }
@ -247,11 +237,10 @@ func handleAbsMouseReportDirect(params map[string]interface{}) (interface{}, err
} }
buttons = uint8(intVal) buttons = uint8(intVal)
} else if floatVal, ok := params["buttons"].(float64); ok { } else if floatVal, ok := params["buttons"].(float64); ok {
intVal := int(floatVal) if floatVal != float64(int(floatVal)) || floatVal < 0 || floatVal > 255 {
if floatVal != float64(intVal) || intVal < 0 || intVal > 255 {
return nil, fmt.Errorf("absMouseReport: buttons value %v invalid", floatVal) return nil, fmt.Errorf("absMouseReport: buttons value %v invalid", floatVal)
} }
buttons = uint8(intVal) buttons = uint8(floatVal)
} else { } else {
return nil, fmt.Errorf("absMouseReport: buttons must be a number") return nil, fmt.Errorf("absMouseReport: buttons must be a number")
} }
@ -262,53 +251,50 @@ func handleAbsMouseReportDirect(params map[string]interface{}) (interface{}, err
// Direct handler for relative mouse reports // Direct handler for relative mouse reports
// Ultra-optimized path with inlined validation for maximum performance // Ultra-optimized path with inlined validation for maximum performance
func handleRelMouseReportDirect(params map[string]interface{}) (interface{}, error) { func handleRelMouseReportDirect(params map[string]interface{}) (interface{}, error) {
// Inline dx validation // Inline dx validation - check float64 first (most common JSON number type)
var dx int8 var dx int8
if intVal, ok := params["dx"].(int); ok { if floatVal, ok := params["dx"].(float64); ok {
if floatVal != float64(int(floatVal)) || floatVal < -128 || floatVal > 127 {
return nil, fmt.Errorf("relMouseReport: dx value %v invalid", floatVal)
}
dx = int8(floatVal)
} else if intVal, ok := params["dx"].(int); ok {
if intVal < -128 || intVal > 127 { if intVal < -128 || intVal > 127 {
return nil, fmt.Errorf("relMouseReport: dx value %d out of range [-128 to 127]", intVal) return nil, fmt.Errorf("relMouseReport: dx value %d out of range [-128 to 127]", intVal)
} }
dx = int8(intVal) dx = int8(intVal)
} else if floatVal, ok := params["dx"].(float64); ok {
intVal := int(floatVal)
if floatVal != float64(intVal) || intVal < -128 || intVal > 127 {
return nil, fmt.Errorf("relMouseReport: dx value %v invalid", floatVal)
}
dx = int8(intVal)
} else { } else {
return nil, fmt.Errorf("relMouseReport: dx must be a number") return nil, fmt.Errorf("relMouseReport: dx must be a number")
} }
// Inline dy validation // Inline dy validation - check float64 first (most common JSON number type)
var dy int8 var dy int8
if intVal, ok := params["dy"].(int); ok { if floatVal, ok := params["dy"].(float64); ok {
if floatVal != float64(int(floatVal)) || floatVal < -128 || floatVal > 127 {
return nil, fmt.Errorf("relMouseReport: dy value %v invalid", floatVal)
}
dy = int8(floatVal)
} else if intVal, ok := params["dy"].(int); ok {
if intVal < -128 || intVal > 127 { if intVal < -128 || intVal > 127 {
return nil, fmt.Errorf("relMouseReport: dy value %d out of range [-128 to 127]", intVal) return nil, fmt.Errorf("relMouseReport: dy value %d out of range [-128 to 127]", intVal)
} }
dy = int8(intVal) dy = int8(intVal)
} else if floatVal, ok := params["dy"].(float64); ok {
intVal := int(floatVal)
if floatVal != float64(intVal) || intVal < -128 || intVal > 127 {
return nil, fmt.Errorf("relMouseReport: dy value %v invalid", floatVal)
}
dy = int8(intVal)
} else { } else {
return nil, fmt.Errorf("relMouseReport: dy must be a number") return nil, fmt.Errorf("relMouseReport: dy must be a number")
} }
// Inline buttons validation // Inline buttons validation - check float64 first (most common JSON number type)
var buttons uint8 var buttons uint8
if intVal, ok := params["buttons"].(int); ok { if floatVal, ok := params["buttons"].(float64); ok {
if floatVal != float64(int(floatVal)) || floatVal < 0 || floatVal > 255 {
return nil, fmt.Errorf("relMouseReport: buttons value %v invalid", floatVal)
}
buttons = uint8(floatVal)
} else if intVal, ok := params["buttons"].(int); ok {
if intVal < 0 || intVal > 255 { if intVal < 0 || intVal > 255 {
return nil, fmt.Errorf("relMouseReport: buttons value %d out of range [0-255]", intVal) return nil, fmt.Errorf("relMouseReport: buttons value %d out of range [0-255]", intVal)
} }
buttons = uint8(intVal) buttons = uint8(intVal)
} else if floatVal, ok := params["buttons"].(float64); ok {
intVal := int(floatVal)
if floatVal != float64(intVal) || intVal < 0 || intVal > 255 {
return nil, fmt.Errorf("relMouseReport: buttons value %v invalid", floatVal)
}
buttons = uint8(intVal)
} else { } else {
return nil, fmt.Errorf("relMouseReport: buttons must be a number") return nil, fmt.Errorf("relMouseReport: buttons must be a number")
} }
@ -327,11 +313,10 @@ func handleWheelReportDirect(params map[string]interface{}) (interface{}, error)
} }
wheelY = int8(intVal) wheelY = int8(intVal)
} else if floatVal, ok := params["wheelY"].(float64); ok { } else if floatVal, ok := params["wheelY"].(float64); ok {
intVal := int(floatVal) if floatVal != float64(int(floatVal)) || floatVal < -128 || floatVal > 127 {
if floatVal != float64(intVal) || intVal < -128 || intVal > 127 {
return nil, fmt.Errorf("wheelReport: wheelY value %v invalid", floatVal) return nil, fmt.Errorf("wheelReport: wheelY value %v invalid", floatVal)
} }
wheelY = int8(intVal) wheelY = int8(floatVal)
} else { } else {
return nil, fmt.Errorf("wheelReport: wheelY must be a number") return nil, fmt.Errorf("wheelReport: wheelY must be a number")
} }

4
usb.go
View File

@ -51,8 +51,8 @@ func rpcKeypressReport(key byte, press bool) (usbgadget.KeysDownState, error) {
return gadget.KeypressReport(key, press) return gadget.KeypressReport(key, press)
} }
func rpcAbsMouseReport(x int, y int, buttons uint8) error { func rpcAbsMouseReport(x uint16, y uint16, buttons uint8) error {
return gadget.AbsMouseReport(x, y, buttons) return gadget.AbsMouseReport(int(x), int(y), buttons)
} }
func rpcRelMouseReport(dx int8, dy int8, buttons uint8) error { func rpcRelMouseReport(dx int8, dy int8, buttons uint8) error {