From 10d97ee82ad6b53391c16fbe415ec3a79d45cc17 Mon Sep 17 00:00:00 2001 From: flamingcow Date: Mon, 31 Aug 2026 14:58:51 -0700 Subject: [PATCH] Relay browser touches through the harness into the real touchscreen --- harness/stream.go | 34 +++++++++- harness/touch.go | 163 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 harness/touch.go diff --git a/harness/stream.go b/harness/stream.go index 9e16266..a82cb70 100644 --- a/harness/stream.go +++ b/harness/stream.go @@ -22,7 +22,7 @@ const page = ` cabletest - + ` @@ -87,6 +115,9 @@ func serveStream() error { if err != nil { return err } + if touchscreen, err = openTouchscreen(); err != nil { + return err + } ln, err := net.Listen("tcp", streamAddr) if err != nil { return err @@ -104,6 +135,7 @@ func serveStream() error { }) mux.HandleFunc("/frames", frames) mux.HandleFunc("/keys", keys) + mux.HandleFunc("/touch", touch) go http.Serve(ln, mux) return nil } diff --git a/harness/touch.go b/harness/touch.go new file mode 100644 index 0000000..572b100 --- /dev/null +++ b/harness/touch.go @@ -0,0 +1,163 @@ +package main + +import ( + "encoding/binary" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" + "unsafe" + + "golang.org/x/sys/unix" +) + +const ( + evSyn = 0x00 + evKey = 0x01 + evAbs = 0x03 + 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 +} + +type touchDev struct { + f *os.File + minX, maxX, minY, maxY int32 +} + +var touchscreen *touchDev + +// Picks the direct-input device that reports absolute X and Y — the same +// probe cabletest runs, so both ends name the same hardware. Events written +// to the node are fed into the input core as if the hardware produced them, +// so cabletest sees a finger without carrying any injection code. +func openTouchscreen() (*touchDev, 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_RDWR, 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<