Files
cabletest/harness/touch.go
T

82 lines
2.4 KiB
Go

package main
import (
"encoding/binary"
"io"
"net/http"
"strconv"
"strings"
"g.fc.run/theater/cabletest/internal/evdev"
)
var touchscreen *evdev.Touchscreen
type inputEvent struct {
typ, code uint16
val int32
}
// 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. Timestamps are left zero: evdev stamps injected events at delivery.
func send(t *evdev.Touchscreen, evs []inputEvent) error {
buf := make([]byte, len(evs)*evdev.EventSize)
for i, e := range evs {
o := i * evdev.EventSize
binary.NativeEndian.PutUint16(buf[o+16:], e.typ)
binary.NativeEndian.PutUint16(buf[o+18:], e.code)
binary.NativeEndian.PutUint32(buf[o+20:], uint32(e.val))
}
_, err := t.F.Write(buf)
return err
}
// The page speaks portrait canvas pixels; the device speaks the panel's
// landscape axes, so the quarter turn cabletest applies on the way in is
// inverted on the way out.
func touch(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
return
}
f := strings.Fields(string(body))
if len(f) == 1 && f[0] == "up" {
if err := send(touchscreen, []inputEvent{{evdev.Key, evdev.BtnTouch, 0}, {evdev.Syn, 0, 0}}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
if len(f) != 3 || (f[0] != "down" && f[0] != "move") {
http.Error(w, "want down x y, move x y, or up", http.StatusBadRequest)
return
}
cx, errX := strconv.Atoi(f[1])
cy, errY := strconv.Atoi(f[2])
if errX != nil || errY != nil {
http.Error(w, "bad coordinates", http.StatusBadRequest)
return
}
latestMu.RLock()
k := latest
latestMu.RUnlock()
if k.buf == nil {
http.Error(w, "no frame to locate the touch on", http.StatusServiceUnavailable)
return
}
cx = min(max(cx, 0), k.ph-1)
cy = min(max(cy, 0), k.pw-1)
xl, yl := cy, k.ph-1-cx
t := touchscreen
rawX := t.MinX + int32(int64(xl)*int64(t.MaxX-t.MinX)/int64(k.pw-1))
rawY := t.MinY + int32(int64(yl)*int64(t.MaxY-t.MinY)/int64(k.ph-1))
evs := []inputEvent{{evdev.Abs, evdev.AbsX, rawX}, {evdev.Abs, evdev.AbsY, rawY}}
if f[0] == "down" {
evs = append(evs, inputEvent{evdev.Key, evdev.BtnTouch, 1})
}
evs = append(evs, inputEvent{evdev.Syn, 0, 0})
if err := send(touchscreen, evs); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}