package main import ( "context" "fmt" "log" "math" "os" "os/signal" "syscall" "github.com/linuxdeepin/go-x11-client/util/cursor" "github.com/linuxdeepin/go-x11-client/util/mousebind" x "github.com/linuxdeepin/go-x11-client" ) // Give names to the events we care about const ( Pressed uint8 = 4 Released = 5 ) type dragger struct { Done chan bool events chan x.GenericEvent ctx context.Context pointerDown bool start [2]int16 end [2]int16 } // NewDragger returns a new reference to a dragger. // This dragger can only be used to watch one drag event. func NewDragger(events chan x.GenericEvent, ctx context.Context) *dragger { return &dragger{ Done: make(chan bool, 1), events: events, ctx: ctx, } } // Watch begins the process of dragger watching for drag events func (s *dragger) Watch() { for { select { case generic := <-s.events: s.handleEvent(generic) break case _ = <-s.ctx.Done(): return } } } func (s *dragger) handleEvent(generic x.GenericEvent) { event, err := x.NewButtonPressEvent(generic) if err != nil { log.Fatal(err) } code := generic.GetEventCode() if code == Pressed { s.pointerDown = true s.start = [2]int16{event.EventX, event.EventY} } else { s.end = [2]int16{event.EventX, event.EventY} if s.pointerDown { s.pointerDown = false s.Done <- true } else { s.Done <- false } } } // Distance returns the total distance of the drag event func (s dragger) Distance() int { diffx := int(s.start[0] - s.end[0]) diffy := int(s.start[1] - s.end[1]) distance := math.Sqrt(float64((diffx * diffx) + (diffy * diffy))) return int(distance) } func loadCursor(conn *x.Conn) (x.Cursor, error) { img, err := cursor.LoadImage("default", "crosshair", 2) if err != nil { return x.CursorNone, err } return img.LoadCursor(conn, "") } func main() { stop := make(chan os.Signal) signal.Notify(stop, os.Interrupt, syscall.SIGTERM, syscall.SIGINT) display, err := x.NewConnDisplay("") if err != nil { log.Fatal(err) } defer display.Close() screen := display.GetDefaultScreen() curs, err := loadCursor(display) if err != nil { log.Fatal(err) } mask := uint16(x.EventMaskButtonPress | x.EventMaskButtonRelease) err = mousebind.GrabPointer(display, screen.Root, mask, x.None, curs) if err != nil { log.Fatal(err) } defer mousebind.UngrabPointer(display) eventChan := display.MakeAndAddEventChan(1) ctx, cancel := context.WithCancel(context.Background()) dm := NewDragger(eventChan, ctx) go dm.Watch() for { select { case v := <-dm.Done: if v { fmt.Println(dm.Distance()) os.Exit(0) } break case <-stop: cancel() os.Exit(0) } } }