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<