package usbgadget import ( "fmt" "os" ) var absoluteMouseConfig = gadgetConfigItem{ order: 1001, device: "hid.usb1", path: []string{"functions", "hid.usb1"}, configPath: []string{"hid.usb1"}, attrs: gadgetAttributes{ "protocol": "2", "subclass": "1", "report_length": "6", }, reportDesc: absoluteMouseCombinedReportDesc, } var absoluteMouseCombinedReportDesc = []byte{ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x02, // Usage (Mouse) 0xA1, 0x01, // Collection (Application) // Report ID 1: Absolute Mouse Movement 0x85, 0x01, // Report ID (1) 0x09, 0x01, // Usage (Pointer) 0xA1, 0x00, // Collection (Physical) 0x05, 0x09, // Usage Page (Button) 0x19, 0x01, // Usage Minimum (0x01) 0x29, 0x03, // Usage Maximum (0x03) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x03, // Report Count (3) 0x81, 0x02, // Input (Data, Var, Abs) 0x95, 0x01, // Report Count (1) 0x75, 0x05, // Report Size (5) 0x81, 0x03, // Input (Cnst, Var, Abs) 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) 0x16, 0x00, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x7F, // Logical Maximum (32767) 0x36, 0x00, 0x00, // Physical Minimum (0) 0x46, 0xFF, 0x7F, // Physical Maximum (32767) 0x75, 0x10, // Report Size (16) 0x95, 0x02, // Report Count (2) 0x81, 0x02, // Input (Data, Var, Abs) 0xC0, // End Collection // Report ID 2: Relative Wheel Movement 0x85, 0x02, // Report ID (2) 0x09, 0x38, // Usage (Wheel) 0x15, 0x81, // Logical Minimum (-127) 0x25, 0x7F, // Logical Maximum (127) 0x75, 0x08, // Report Size (8) 0x95, 0x01, // Report Count (1) 0x81, 0x06, // Input (Data, Var, Rel) 0xC0, // End Collection } func (u *UsbGadget) absMouseWriteHidFile(data []byte) error { if u.absMouseHidFile == nil { var err error u.absMouseHidFile, err = os.OpenFile("/dev/hidg1", os.O_RDWR, 0666) if err != nil { return fmt.Errorf("failed to open hidg1: %w", err) } } _, err := u.absMouseHidFile.Write(data) if err != nil { u.log.Error().Err(err).Msg("failed to write to hidg1") u.absMouseHidFile.Close() u.absMouseHidFile = nil return err } return nil } func (u *UsbGadget) AbsMouseReport(x, y int, buttons uint8) error { u.absMouseLock.Lock() defer u.absMouseLock.Unlock() err := u.absMouseWriteHidFile([]byte{ 1, // Report ID 1 buttons, // Buttons uint8(x), // X Low Byte uint8(x >> 8), // X High Byte uint8(y), // Y Low Byte uint8(y >> 8), // Y High Byte }) if err != nil { return err } u.resetUserInputTime() return nil } func (u *UsbGadget) AbsMouseWheelReport(wheelY int8) error { u.absMouseLock.Lock() defer u.absMouseLock.Unlock() // Accumulate the wheelY value u.absMouseAccumulatedWheelY += float64(wheelY) / 8.0 // Only send a report if the accumulated value is significant if abs(u.absMouseAccumulatedWheelY) < 1.0 { return nil } scaledWheelY := int8(u.absMouseAccumulatedWheelY) err := u.absMouseWriteHidFile([]byte{ 2, // Report ID 2 byte(scaledWheelY), // Scaled Wheel Y (signed) }) // Reset the accumulator, keeping any remainder u.absMouseAccumulatedWheelY -= float64(scaledWheelY) u.resetUserInputTime() return err }