92 lines
2.1 KiB
Go
92 lines
2.1 KiB
Go
// Package evdev is the kernel input-event ABI.
|
|
package evdev
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const (
|
|
Syn = 0x00
|
|
Key = 0x01
|
|
Abs = 0x03
|
|
SynReport = 0x00
|
|
BtnTouch = 0x14a
|
|
AbsX = 0x00
|
|
AbsY = 0x01
|
|
|
|
propDirect = 0x01
|
|
|
|
EventSize = 24
|
|
)
|
|
|
|
func ioc(nr, size uintptr) uintptr {
|
|
const iocRead = 2
|
|
return iocRead<<30 | size<<16 | 'E'<<8 | nr
|
|
}
|
|
|
|
type Touchscreen struct {
|
|
F *os.File
|
|
MinX, MaxX, MinY, MaxY int32
|
|
}
|
|
|
|
// 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(flag int) (*Touchscreen, error) {
|
|
paths, err := filepath.Glob("/dev/input/event*")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, p := range paths {
|
|
f, err := os.OpenFile(p, flag, 0)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
var props, absBits uint64
|
|
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, f.Fd(),
|
|
ioc(0x09, 8), uintptr(unsafe.Pointer(&props))); errno != 0 {
|
|
f.Close()
|
|
continue
|
|
}
|
|
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, f.Fd(),
|
|
ioc(0x20+Abs, 8), uintptr(unsafe.Pointer(&absBits))); errno != 0 {
|
|
f.Close()
|
|
continue
|
|
}
|
|
if props&(1<<propDirect) == 0 ||
|
|
absBits&(1<<AbsX) == 0 || absBits&(1<<AbsY) == 0 {
|
|
f.Close()
|
|
continue
|
|
}
|
|
t := &Touchscreen{F: f}
|
|
if t.MinX, t.MaxX, err = axisRange(f, AbsX); err != nil {
|
|
f.Close()
|
|
return nil, fmt.Errorf("%s x range: %w", p, err)
|
|
}
|
|
if t.MinY, t.MaxY, err = axisRange(f, AbsY); err != nil {
|
|
f.Close()
|
|
return nil, fmt.Errorf("%s y range: %w", p, err)
|
|
}
|
|
if t.MaxX <= t.MinX || t.MaxY <= t.MinY {
|
|
f.Close()
|
|
return nil, fmt.Errorf("%s: degenerate axes x %d..%d y %d..%d",
|
|
p, t.MinX, t.MaxX, t.MinY, t.MaxY)
|
|
}
|
|
return t, nil
|
|
}
|
|
return nil, fmt.Errorf("no touchscreen found among /dev/input/event*")
|
|
}
|
|
|
|
func axisRange(f *os.File, axis uintptr) (min, max int32, err error) {
|
|
var info [6]int32
|
|
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, f.Fd(),
|
|
ioc(0x40+axis, 24), uintptr(unsafe.Pointer(&info[0]))); errno != 0 {
|
|
return 0, 0, errno
|
|
}
|
|
return info[1], info[2], nil
|
|
}
|