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) } }