package main import ( "fmt" "os" "path/filepath" "sync" "unsafe" "golang.org/x/sys/unix" ) const ( evSyn = 0x00 evKey = 0x01 evAbs = 0x03 synReport = 0x00 btnTouch = 0x14a absX = 0x00 absY = 0x01 inputPropDirect = 0x01 sizeofInputEvent = 24 ) func evIoc(nr, size uintptr) uintptr { const iocRead = 2 return iocRead<<30 | size<<16 | 'E'<<8 | nr } // Current finger position and whether it is down. Held as state rather than // delivered as events, so a dropped release can never leave a hold armed. type touchState struct { mu sync.Mutex x, y int down bool } func (t *touchState) set(x, y int, down bool) { t.mu.Lock() t.x, t.y, t.down = x, y, down t.mu.Unlock() } func (t *touchState) get() (x, y int, down bool) { t.mu.Lock() defer t.mu.Unlock() return t.x, t.y, t.down } // Picks the direct-input device that reports absolute X and Y, which is the // touchscreen; a mouse is relative and a keyboard has no absolute axes. func findTouchscreen() (*os.File, error) { paths, err := filepath.Glob("/dev/input/event*") if err != nil { return nil, err } for _, p := range paths { f, err := os.OpenFile(p, os.O_RDONLY, 0) if err != nil { continue } var props, absBits uint64 if _, _, errno := unix.Syscall(unix.SYS_IOCTL, f.Fd(), evIoc(0x09, 8), uintptr(unsafe.Pointer(&props))); errno != 0 { f.Close() continue } if _, _, errno := unix.Syscall(unix.SYS_IOCTL, f.Fd(), evIoc(0x20+evAbs, 8), uintptr(unsafe.Pointer(&absBits))); errno != 0 { f.Close() continue } if props&(1<