From 20df328b63f11a3821cf15faea36507a5679a4ba Mon Sep 17 00:00:00 2001 From: The_miro Date: Thu, 30 Jul 2026 12:38:15 +0200 Subject: [PATCH] Add touch-panel mouse-emulated-touchscreen fallback; revise components.md shopping list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hosts/touch-panel/: cheap touch controllers sometimes report as an absolute- position HID mouse instead of a real digitizer, which makes libinput hand sway a type:pointer device instead of type:touch. Add a type:pointer fallback (flat accel profile, no pointer acceleration, cursor hidden on idle) so taps still work as single-touch clicks in that case, plus a udev rule template (configs/udev/99-touchscreen-override.rules) to re-tag a specific known device back to full wl_touch semantics once its USB vendor/ product ID is known. Documented in a new README section and reflected in project-plan.md's hardware/guardrail/open-decision entries for Phase 16. docs/components.md: replace the Lenovo ThinkSmart View pick for Loggia (a locked-down Teams/Zoom appliance, not a general Linux box) with a cheap all-in-one touchscreen PC, then supersede that with the Lenovo all-in-one already on hand for that room — moved from Need to Have throughout. Also adds a Need section: missing components broken into sub-parts (Sound System, Voice Reciever) with real Amazon listings found via search. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01K6CrKjW3yVptUnjG35HjC1 --- docs/components.md | 93 ++++++++++++++++++- docs/project-plan.md | 25 +++-- hosts/touch-panel/README.md | 56 +++++++++-- hosts/touch-panel/configs/sway/config | 33 ++++++- .../udev/99-touchscreen-override.rules | 42 +++++++++ .../scripts/build-touch-panel-iso.sh | 20 +++- 6 files changed, 245 insertions(+), 24 deletions(-) create mode 100644 hosts/touch-panel/configs/udev/99-touchscreen-override.rules diff --git a/docs/components.md b/docs/components.md index 872a982..bb4dfc5 100644 --- a/docs/components.md +++ b/docs/components.md @@ -9,13 +9,13 @@ Components #Living Room -1xMedia Station/TVPC (doesn't technically need to be in the same room) -> 1xThinClient (tiny reicht) +1xMedia Station/TVPC (doesn't technically need to be in the same room) -> 1xThinClient (tiny is sufficient) 1xVoice Reciever - Round screen thingy 1xSound System #Loggia -1xMiniscreen System (Lenovo Thinksmart would be ideal - i will be aquiring one) +1xMiniscreen System (Lenovo all-in-one PC, large built-in touchscreen — already own it, free, see #Have) 1xSound System 1xVoice Reciever - Round screen thingy @@ -28,7 +28,7 @@ Components #Amirs Room 1xBeamer -1xThinClient (tiny reicht) +1xThinClient (tiny is sufficient) 1xHA Voice PE #Kitchen @@ -47,7 +47,7 @@ Components #Endpoints (all rooms combined) 2x ThinClient (tiny) -1x Miniscreen System (Lenovo Thinksmart) +1x Miniscreen System (Lenovo all-in-one, built-in touchscreen — already owned) 1x Beamer 4x Voice Reciever - round screen thingy (Living Room, Loggia, Linus Room, Kitchen) 1x HA Voice PE @@ -57,7 +57,7 @@ Components #By room Living Room: 1x ThinClient, 1x Voice Reciever, 1x Sound System -Loggia: 1x Miniscreen System, 1x Sound System, 1x Voice Reciever +Loggia: 1x Miniscreen System (have), 1x Sound System, 1x Voice Reciever Linus Room: 1x Voice Reciever, 1x Sound System?, +1 unresolved (???) Amirs Room: 1x Beamer, 1x ThinClient, 1x HA Voice PE Kitchen: 1x Tiny PC w/ Touchscreen, 1x Camera, 1x Voice Reciever, 1x Sound System? @@ -66,3 +66,86 @@ Kitchen: 1x Tiny PC w/ Touchscreen, 1x Camera, 1x Voice Reciever, 1x Sound - Linus Room's "???" line is still undecided. - Sound System is unconfirmed ("?") in Linus Room and Kitchen — 2 of the 4 total. +#Have +1xSound System +Near infinite Tiny Pcs +near infinite ATX Pcs +1xHA Voice PE +1xZigbee adapter +1xLenovo all-in-one PC, large built-in touchscreen (Loggia's Miniscreen System — free, already have it) + +##Need + +Need = Summed totals minus Have. "Tiny Pcs"/"ATX Pcs" are covered (near-infinite +supply on hand), so ThinClients and the LLM-host chassis are NOT listed below — +only parts not already owned. Composite items ("Sound System", "Voice Reciever") +are broken into their actual sub-components, since "1x Sound System" isn't a single +SKU. Amazon links are real listings found via search (mostly amazon.com — search +only returned US results; check amazon.de for local pricing/shipping/VAT before +buying). No prices are invented below — where docs/project-plan.md already +documents one it's reused as-is, otherwise it says "see link." + +#GPU (LLM host) — need 1 +- Used RTX 3060 12GB (~€200–250, per docs/project-plan.md §1.2) — condition/model + don't matter much, 12GB VRAM is the requirement (Q4 Qwen2.5-14B). New alternative: + [MSI GeForce RTX 3060 Ventus 2X 12G OC](https://www.amazon.com/MSI-GeForce-Ventus-NVIDIA-Graphics/dp/B08WHJFYM8) + +#Beamer (Amirs Room) — need 1 +- [TMY 1080P Mini Portable Projector, HDMI/USB](https://www.amazon.com/TMY-Projector-Supported-Projection-Compatible/dp/B082F13J55) + (see link for price) — budget pick; if the ThinClient output needs to look good on + a big wall, a brighter/native-1080p unit is worth paying more for than a mini + LED projector like this one +- HDMI cable, length depends on beamer placement vs. ThinClient — not sized yet +- Ceiling/shelf mount — only if not just resting on furniture + +#Voice Reciever - round screen thingy (Living Room, Loggia, Linus Room, Kitchen) — need 4 +This is `firmware/esp32-s3-touch-lcd-1.85c/` from this repo (Phase 14) — each unit +is a kit of: +- [Waveshare ESP32-S3-Touch-LCD-1.85C, round touch display dev board](https://www.amazon.com/waveshare-ESP32-S3-1-85inch-Touch-LCD/dp/B0DK6NH65T) + (~€35–45 each per docs/project-plan.md §1.12) — **must be the V2 revision**, see + `firmware/esp32-s3-touch-lcd-1.85c/README.md`; the listing needs checking for which + hardware revision it actually ships, this repo's firmware assumes V2 (V1 has no AEC + circuit and different audio pins) +- USB-C power adapter, one per unit — [5V/3A USB-C wall adapter](https://www.amazon.com/Security-01-Supply-Adapter-Type-C-MLF-C060503000CU/dp/B09JW4QQJ2) +- USB-C cable, one per unit (often included with the board — check the listing before + buying separately) + +4x board + 4x power adapter (+ cable if not bundled). + +#Sound System (Living Room + Loggia confirmed; Linus Room + Kitchen unconfirmed) — need 1 confirmed, up to 3 total +Have 1 already, need 4 total (2 confirmed, 2 pending the "?"/"???" decisions above) +→ need 1 now, +2 more if Linus Room/Kitchen are confirmed. Each unit is a kit of: +- [Fosi Audio V3 stereo amp (300W x2, TPA3255, w/ 48V PSU)](https://www.amazon.com/Fosi-Audio-V3-Amplifier-48V/dp/B0CGCSM191) + (~€130 per docs/project-plan.md §1.13) — USB DAC/amp for the passive speakers below, + same choice this repo's `hosts/audio-endpoint/` and `hosts/thin-client/` docs already + make for amd64 rooms +- [Micca MB42X G2 passive bookshelf speakers, pair](https://www.amazon.com/Micca-Passive-Bookshelf-Speakers-Surround/dp/B0CGBKWBGM) + (~€100/pair per docs/project-plan.md §1.13) +- [16-gauge speaker wire, 100ft spool](https://www.amazon.com/AmazonBasics-16-Gauge-Speaker-Wire-Feet/dp/B006LW0W5Y) + (one spool easily covers multiple rooms — buy once, not once per Sound System) + +1x spool of wire total; 1–3x (amp + speaker pair) depending on how many of the +"?"/"???" rooms end up wanting one. + +#Kitchen — need 1 touchscreen + 1 camera +`hosts/kitchen-display/` (Phase 17) — the Tiny PC is covered by "Have", these two +are not: +- [10.3" portable USB-C touchscreen monitor](https://www.amazon.com/Touchscreen-Stretched-Portable-Computer-Monitoring/dp/B0DFVZ2Z35) + (see link for price) — needs to expose itself as a native Wayland `wl_touch` + device, not just an emulated-mouse HID surface (unverified either way — see + `hosts/kitchen-display/README.md`) +- [Logitech HD Pro Webcam C920](https://www.amazon.com/Logitech-Widescreen-Calling-Recording-Desktop/dp/B006JH8T3S) + (see link for price) — any UVC webcam works; picked for wide availability/driver + support, not a specific requirement + +#Open items carried over from above +- Whether Linus Room and Kitchen actually get a Sound System (the two "?" marks) + decides whether 1 or 3 more amp+speaker kits are needed. +- Linus Room's "???" line is still a completely open slot — nothing to shop for + until it's decided what it is. +- Loggia's Lenovo all-in-one is already owned, so nothing to buy. `hosts/touch-panel/` + now handles either way its touch panel shows up to Linux (native `wl_touch`, or an + emulated-mouse HID device via the `type:pointer` fallback + a udev override to fix + it properly — see that host's README "Touch input: two tiers"), so this is no + longer a go/no-go check, just worth running once to know which tier it landed in + and whether the override needs filling in for full multi-touch. diff --git a/docs/project-plan.md b/docs/project-plan.md index e5e886f..df704d1 100644 --- a/docs/project-plan.md +++ b/docs/project-plan.md @@ -101,7 +101,7 @@ Already covered — using your existing Haozee CC2652P USB dongle. No coordinato ### 1.14 Touch panel hardware (Phase 16) | Item | Est. Price (EUR) | Notes | |---|---|---| -| Mini PC or SBC with a capacitive touchscreen (e.g. 10–15" USB-touch monitor + small x86 mini PC, or an all-in-one touch panel PC) | €150–300 | **No specific unit has been chosen** — the one hard requirement is that the touchscreen exposes itself as a native Wayland `wl_touch` device under libinput, not merely an emulated-mouse HID interface, since `hosts/touch-panel/` has no gesture/pointer-translation fallback the way the thin client does | +| Mini PC or SBC with a capacitive touchscreen (e.g. 10–15" USB-touch monitor + small x86 mini PC, or an all-in-one touch panel PC) | €150–300 | **No specific unit has been chosen.** A native Wayland `wl_touch` device is preferred but no longer a hard requirement — `hosts/touch-panel/` also ships a `type:pointer` fallback (usable single-touch tap/click-drag) for touchscreens that misreport as an emulated-mouse HID device, plus a udev override template to reclassify a specific known device back to full touch semantics. See that host's "Touch input: two tiers" README section | | Speakers or a wired connection to existing room audio | €0–100 | For local Spotify GUI-client playback — same speaker guidance as the thin-client/audio-endpoint rooms | *(No container-host changes — `touchpanel-agent` talks to the existing Mosquitto/HA @@ -110,7 +110,7 @@ from Phase 1, same as every other MQTT-connected host in this plan.)* ### 1.15 Kitchen/fridge display hardware (Phase 17) | Item | Est. Price (EUR) | Notes | |---|---|---| -| Mini PC or SBC with a touchscreen, mounted near the fridge/pantry | €150–300 | Same "must be a native Wayland `wl_touch` device" requirement as §1.14 — `hosts/kitchen-display/` has no pointer-emulation fallback either | +| Mini PC or SBC with a touchscreen, mounted near the fridge/pantry | €150–300 | Prefers a native Wayland `wl_touch` device, same as §1.14 — unlike that host, `hosts/kitchen-display/` does not (yet) ship the `type:pointer`/udev-override fallback described there; a misclassified touchscreen here is still an open problem | | USB webcam, pointed at wherever items get held up for scanning | €15–40 | Either built into the panel or on a short cable/gooseneck so its angle can be set independently of the screen. Any UVC webcam works — this is the same "no depth camera, no accelerator needed" bar as the thin client's gesture-control camera (§1.11), just used for a photo instead of continuous tracking | *(No new container-host hardware — `pantry-vision` is a container on the existing @@ -383,11 +383,20 @@ New hardware: §1.14. No container-host changes. repo are reused, not reinvented**: `eww` (same as the thin client's now-playing widget) and `wvkbd` — neither is in Debian bookworm main, and both hooks stop at a documented placeholder rather than a hardcoded release URL if apt doesn't have them. -8. Nothing built or flashed on real hardware — no touch-panel unit has been chosen - (§1.14), and in particular whether the touchscreen exposes itself as a native - Wayland `wl_touch` device (this image's one hard assumption, since there is no - pointer-emulation fallback the way the thin client's gesture control has one) is - unverified. See the itemized list in `hosts/touch-panel/README.md`. +8. **Touch input degrades instead of hard-requiring `wl_touch`**: `configs/sway/config` + ships both `input type:touch` (full multi-touch, if the hardware reports + correctly) and an `input type:pointer` fallback (flat accel profile, no pointer + acceleration, cursor hidden on idle) for touchscreens that misreport as an + emulated-mouse HID device — a real, documented failure mode for cheap touch + controllers, not a hypothetical. `configs/udev/99-touchscreen-override.rules` is + the actual fix once a specific unit's USB vendor/product ID is known: it re-tags + the device so udev/libinput treat it as a genuine touchscreen instead of settling + for the pointer fallback's single-touch ceiling. Ships as an inert template + (`0000:0000`, matches nothing) until then. +9. Nothing built or flashed on real hardware — no touch-panel unit has been chosen + (§1.14). Both the `wl_touch` path and the `type:pointer` fallback above are + unverified against real touch hardware either way — see the itemized list in + `hosts/touch-panel/README.md`. ### Phase 17 — Kitchen/fridge display (camera-vision grocery cataloguing) @@ -515,7 +524,7 @@ These need a decision before their respective implementation steps can be built 13. **The sys-admin-llm's HA-side wiring has no real data source or tool definition yet** (new, Phase 13) — same shape as open decision #9 above: `admin-canvas/README.md` documents the expected `rest_command:`/tool-call contract and worked example JSON, but which HA entities/history back something like "the kitchen outlet's power draw" is unresolved, and no metering-capable Zigbee smart plug is in this plan's hardware list (§1.4) yet. Needs a hardware decision (a power-monitoring outlet) and an actual HA tool/script, neither of which exists in this repo by design — see the Phase 13 "nothing under this repo builds the HA side" note. 14. **The voice/display satellite has no real hardware verification, and two of its data sources are unpicked** (new, Phase 14) — `firmware/esp32-s3-touch-lcd-1.85c/voice-display.yaml` passes ESPHome's own config validator but has never been flashed to a physical unit; the display init sequence, the AEC audio path, and wake-word sensitivity are all adapted/assumed, not measured (see the itemized list in that directory's README). Separately, `media_player_entity_id` and `weather_entity_id` are placeholders — which media player this unit should mirror needs a decision if the household ends up with more than one active at a time. 15. **The headless audio endpoint has no real hardware verification on either architecture** (new, Phase 15) — neither the arm64 (`rpi-image-gen`) nor amd64 (`live-build`) pipeline has been run to completion, let alone flashed and booted. rpi-image-gen's exact config/layer YAML schema in particular was written from documentation only, with no ARM build environment available to validate it against the real tool — see `hosts/audio-endpoint/README.md`'s prominent risk callout. Also still open: whether `spotifyd` or `librespot` actually installs cleanly from current bookworm apt sources at all (the fallback list is documented, not exercised), and how stable USB DAC/amp ALSA enumeration turns out to be on a real amd64 mini PC. -16. **No touch-panel hardware has been chosen** (new, Phase 16) — nothing in `hosts/touch-panel/` has been booted on real metal or a real touchscreen. In particular, whether the panel's touch input actually surfaces as a native Wayland `wl_touch` device (this image's one hard assumption) is unverified — see `hosts/touch-panel/README.md`'s verification list, item 3. +16. **No touch-panel hardware has been chosen** (new, Phase 16) — nothing in `hosts/touch-panel/` has been booted on real metal or a real touchscreen. Which of the two shipped input tiers a real device lands in (native `wl_touch`, or the `type:pointer` fallback for hardware that misreports as an emulated-mouse HID device — see `hosts/touch-panel/README.md`'s "Touch input: two tiers") is unverified either way, as is whether `configs/udev/99-touchscreen-override.rules`' `ATTRS{idVendor}`/`ATTRS{idProduct}` match actually walks up to the right USB parent for a given controller — see that README's verification list, item 3. 17. **The touch panel's Spotify/Chromium integration details are assumed, not confirmed** (new, Phase 16) — the Flathub app ID `com.spotify.Client`, the Spotify Flatpak's real MPRIS bus name (assumed `spotify`), and Chromium's Wayland `app_id` for a `--app=` kiosk window (assumed to start with `chromium`) are all flagged for on-hardware verification in `hosts/touch-panel/README.md`. 18. **No vision-capable Ollama model has been picked, pulled, or benchmarked** (new, Phase 17) — `pantry-vision`'s `OLLAMA_VISION_MODEL` defaults to `llava` with no confirmation it's the right choice for any given LLM host's hardware tier, and grocery-item identification latency/accuracy is completely unmeasured. This is the single highest-risk unknown in Phase 17: if it's too slow or too inaccurate, "hold item up to camera" stops being a usable interaction and the phase needs a different approach (a smaller/faster model, a barcode-scan fallback via Grocy's existing scanning support, or both). 19. **`pantry-vision`'s Grocy API integration is written from documentation, not a live instance** (new, Phase 17) — `GET /api/stock`'s response shape, `POST /api/objects/products`'s minimum required fields, and the Recipes/fulfillment endpoints' setup requirements are all assumed; `pantry-vision/README.md` points at each real Grocy instance's own live OpenAPI spec (`/api/openapi/specification`) as the way to check before trusting any of it. `GROCY_DEFAULT_LOCATION_ID`/`GROCY_DEFAULT_QU_ID` are fresh-install-default guesses that need confirming against Settings → Locations/Quantity units on the real instance too. diff --git a/hosts/touch-panel/README.md b/hosts/touch-panel/README.md index 280db04..e9709f6 100644 --- a/hosts/touch-panel/README.md +++ b/hosts/touch-panel/README.md @@ -19,7 +19,7 @@ What ends up on the image: |---|---| | Compositor | Sway, workspaces `1:spotify` / `2:home` / `3:web`, always-on touch dock | | Autologin | greetd, `default_session` straight into `/usr/local/bin/kiosk-session` | -| Touch input | Native Wayland `wl_touch` (libinput), no pointer-emulation layer | +| Touch input | Native Wayland `wl_touch` preferred; degrades to a usable single-touch pointer if the hardware only exposes an emulated-mouse HID interface — see below | | Music | Full Spotify GUI client (Flathub `com.spotify.Client`) — not a headless Connect receiver | | Home dashboard | Chromium in kiosk mode, `--app=$HA_URL`, auto-restart if it crashes | | Web browser | Firefox, minimal chrome (back/forward/reload/address bar), general browsing | @@ -30,8 +30,8 @@ What ends up on the image: ## Before you build > **No touch-panel hardware has been chosen.** Nothing here has been booted on real -> metal or a real touchscreen. Touch-as-`wl_touch` (as opposed to some panels that only -> expose an emulated-mouse HID interface) is assumed, not confirmed. +> metal or a real touchscreen. See "Touch input: two tiers" below for how this image +> handles either way a real touchscreen might show up to Linux. Edit the `# CONFIGURATION` block at the top of [`scripts/build-touch-panel-iso.sh`](scripts/build-touch-panel-iso.sh): @@ -56,6 +56,43 @@ human-edited, git-tracked source of truth; `live-build/config/includes.chroot/` templated tokens are `@KIOSK_USERNAME@`/`@KEYBOARD_LAYOUT@`; everything else the in-chroot hooks need comes from `/etc/touchpanel-agent/config.env`. +## Touch input: two tiers + +Not every touchscreen tells Linux the truth about being a touchscreen. Some cheap USB +controllers implement single-touch by emulating an absolute-position HID **mouse** +(a click at wherever the finger is) instead of a proper HID **digitizer**. udev reads +the device's capability bits to decide `ID_INPUT_TOUCHSCREEN` vs. `ID_INPUT_MOUSE`, +gets it wrong for exactly this class of hardware, and libinput then hands sway a +`type:pointer` device instead of `type:touch` — every tap becomes a mouse click, not +a touch event. This image handles both cases rather than assuming the good one: + +1. **Native `wl_touch`** (`input type:touch` in `configs/sway/config`) — full + multi-touch, works with no extra setup. This is what you get if the hardware + reports correctly. +2. **Fallback: `input type:pointer`** — active on this image regardless, so a + misclassified touchscreen is still usable out of the box: `accel_profile flat` + + `pointer_accel 0` keep the absolute tap position from being distorted by mouse- + acceleration curves meant for relative motion, `map_to_output "*"` keeps the + coordinate space aligned to the screen, and `seat seat0 hide_cursor 1` hides the + cursor within ~1ms of it stopping so a tap doesn't leave a visible arrow sitting on + screen. The ceiling here is single-touch tap/click-drag — no pinch, no true + multi-touch gestures — which is enough for the dock and most kiosk UI, not enough + for e.g. pinch-zooming a map in the web browser workspace. + +**The real fix, once real hardware is known**: +`configs/udev/99-touchscreen-override.rules` re-tags the specific device by its USB +vendor/product ID so udev (and therefore libinput, and therefore sway) treats it as a +genuine touchscreen — restoring full `wl_touch` semantics instead of settling for the +pointer fallback's ceiling. It ships as an inert `0000:0000` template that matches no +real hardware; that file's own header comment has the exact `udevadm`/`libinput +list-devices` commands to find your device's real IDs and confirm the fix took. Fill +it in and rebuild — or edit it directly on a booted image and +`udevadm control --reload-rules && udevadm trigger && swaymsg reload`, no rebuild +needed to test it. + +Quick check on a booted image: `libinput list-devices | grep -A2 Capabilities` — if it +lists `touch`, you're on tier 1 already and don't need the udev override at all. + ## Why there's no wayvnc on this image The thin client's primary control surface is deliberately remote (HA/MQTT + wayvnc) @@ -169,11 +206,14 @@ None of this has been run on hardware. In rough order: 1. The ISO builds at all (`lb build` is network-heavy and can fail on mirror hiccups). 2. greetd lands in Sway with no login prompt, on vt1, with getty@tty1 masked. -3. **Touch input actually arrives as `wl_touch`**, not an emulated pointer — the whole - design (native touch in Chromium/Firefox/Spotify, no gesture-translation layer) - assumes a real Wayland touchscreen driver. If it only shows up as a mouse, tapping - will still mostly work by accident (a single point maps to a click) but pinch/ - multi-touch in Chromium or Spotify won't. +3. **Which tier the real touchscreen lands in** — see "Touch input: two tiers" above. + Both `input type:touch` and the `input type:pointer` fallback are shipped and + should both work without a rebuild; what's unverified is whether the fallback's + `accel_profile flat`/`pointer_accel 0`/`hide_cursor` combination actually feels + good on real absolute-position-emulated-as-mouse hardware (as opposed to just + being technically functional), and whether `99-touchscreen-override.rules`' + `ATTRS{idVendor}`/`ATTRS{idProduct}` match actually walks up to the right USB + parent on a given controller's specific kernel driver. 4. `touchpanel-agent` connects to Mosquitto and the device appears in HA. 5. **Flathub app ID `com.spotify.Client` is correct** — flagged for verification in `0300-flatpak-spotify.hook.chroot`, same as the thin client's Steam Link ID. diff --git a/hosts/touch-panel/configs/sway/config b/hosts/touch-panel/configs/sway/config index 6814dd2..e69a8c2 100644 --- a/hosts/touch-panel/configs/sway/config +++ b/hosts/touch-panel/configs/sway/config @@ -29,7 +29,9 @@ input type:keyboard { # Real touchscreen hardware, not the thin client's couch-distance camera-gesture # trick: libinput/Wayland surfaces (GTK, Chromium, Firefox) all speak wl_touch -# natively, so taps/scrolls/pinches just work without a pointer-emulation layer. +# natively, so taps/scrolls/pinches just work without a pointer-emulation layer — +# when the kernel/udev actually classifies the device as a touchscreen. See +# configs/udev/99-touchscreen-override.rules for the case where it doesn't. input type:touch { map_to_output "*" } @@ -38,6 +40,35 @@ input type:tablet_tool { map_to_output "*" } +# --- Fallback: some cheap touch controllers report themselves as an absolute- +# position HID mouse instead of a proper touch digitizer (ID_INPUT_MOUSE rather than +# ID_INPUT_TOUCHSCREEN in udev, so libinput hands sway a `type:pointer` device, not a +# `type:touch` one, and every tap becomes a mouse click at that position instead of a +# touch event). Rather than assume this never happens, this block makes that +# degraded mode usable on its own: +# - accel_profile flat + pointer_accel 0: a touch-emulated pointer's coordinates +# are already absolute; libinput's normal mouse acceleration curve is tuned for +# relative motion and would make taps land somewhere other than where the finger +# is, or make the cursor visibly drift/overshoot before settling. +# - map_to_output: same coordinate-space fix `type:touch` already gets above, +# needed here too since this device isn't going through that block. +# See configs/udev/99-touchscreen-override.rules for the real fix (reclassifying the +# device as a touchscreen instead of merely working around it being a pointer), and +# the "Touch input: two tiers" section in README.md for the full picture, including +# why single-touch click-drag (not true multi-touch/pinch) is the ceiling here. +input type:pointer { + accel_profile flat + pointer_accel 0 + map_to_output "*" +} + +# Hides the cursor after ~1ms of no input instead of leaving a static arrow sitting +# on screen. Irrelevant for real wl_touch input (Wayland never draws a cursor for +# touch events at all) but is what keeps the type:pointer fallback above from looking +# broken — a touch-emulated tap moves the cursor, clicks, and it's gone again before +# anyone would register it as a cursor rather than a tap. +seat seat0 hide_cursor 1 + # --------------------------------------------------------------------------- # Look # --------------------------------------------------------------------------- diff --git a/hosts/touch-panel/configs/udev/99-touchscreen-override.rules b/hosts/touch-panel/configs/udev/99-touchscreen-override.rules new file mode 100644 index 0000000..7dee5fc --- /dev/null +++ b/hosts/touch-panel/configs/udev/99-touchscreen-override.rules @@ -0,0 +1,42 @@ +# Forces a specific touchscreen to be classified as ID_INPUT_TOUCHSCREEN instead of +# ID_INPUT_MOUSE. Installed to /etc/udev/rules.d/99-touchscreen-override.rules. +# +# THE PROBLEM this fixes: some cheap USB touch controllers implement single-touch by +# emulating an absolute-position HID mouse (BTN_LEFT + ABS_X/ABS_Y) rather than a +# proper HID digitizer (BTN_TOUCH). udev's stock 60-input-id rules (via the +# `input_id` builtin) read those capability bits to decide ID_INPUT_TOUCHSCREEN vs. +# ID_INPUT_MOUSE, and get it wrong for exactly this class of hardware — libinput then +# hands sway a `type:pointer` device instead of `type:touch`, which is what +# configs/sway/config's `input type:pointer {}` block degrades gracefully for. +# +# THE REAL FIX, not just a workaround: re-tag the specific device by its USB +# vendor/product ID so udev (and therefore libinput, and therefore sway) treats it as +# a genuine touchscreen — full multi-touch/wl_touch semantics, not the single-touch +# click-drag ceiling of the type:pointer fallback. +# +# 99- (not 61- or similar): udev processes rule files in filename order, and the +# ID_INPUT_* properties this needs to override are set by the *stock* rules around +# priority 60 (60-input-id.rules / 60-persistent-input.rules, packaged with udev +# itself). A rule that runs after them can overwrite what they set; one that runs +# before cannot. 99 guarantees "after." +# +# SETUP — do this once real touch-panel hardware is chosen: +# 1. Plug the touchscreen in, find its input event node: +# ls -l /dev/input/by-id/ # or: libinput list-devices +# 2. Get its USB vendor/product ID: +# udevadm info -a /dev/input/eventN | grep -m1 -E 'idVendor|idProduct' +# (walk up with -p if the input node itself has no idVendor/idProduct attrs — +# udev's ATTRS{} match below walks the parent chain automatically either way) +# 3. Replace the 0000/0000 placeholders below with the real values (lowercase hex, +# no "0x" prefix — exactly as `udevadm info` prints them). +# 4. udevadm control --reload-rules && udevadm trigger +# 5. Confirm: `udevadm info /dev/input/eventN | grep ID_INPUT` should now show +# ID_INPUT_TOUCHSCREEN=1 and no ID_INPUT_MOUSE=1. `swaymsg reload` afterward so +# sway re-evaluates the device against configs/sway/config's `input type:touch` +# block instead of `input type:pointer`. +# +# Ships as an inert template: 0000:0000 matches no real hardware, so this file does +# nothing on an unconfigured image — the type:pointer fallback in configs/sway/config +# is what makes an unconfigured (or not-yet-matched) touchscreen usable in the +# meantime, not this file. +SUBSYSTEM=="input", ATTRS{idVendor}=="0000", ATTRS{idProduct}=="0000", ENV{ID_INPUT_TOUCHSCREEN}="1", ENV{ID_INPUT_MOUSE}="" diff --git a/hosts/touch-panel/scripts/build-touch-panel-iso.sh b/hosts/touch-panel/scripts/build-touch-panel-iso.sh index 65a5c93..e37f0e9 100755 --- a/hosts/touch-panel/scripts/build-touch-panel-iso.sh +++ b/hosts/touch-panel/scripts/build-touch-panel-iso.sh @@ -128,6 +128,7 @@ mkdir -p \ "$INCLUDES/etc/touchpanel-agent" \ "$INCLUDES/etc/firefox/policies" \ "$INCLUDES/etc/touchpanel-firefox" \ + "$INCLUDES/etc/udev/rules.d" \ "$INCLUDES/usr/local/bin" \ "$INCLUDES/opt/touchpanel-agent" \ "$INCLUDES/home/${KIOSK_USERNAME}/.config/sway" \ @@ -152,6 +153,11 @@ install -m 0755 "${CONFIGS_DIR}/sway/ha-kiosk" "$INCLUDES/usr/loca install -m 0755 "${CONFIGS_DIR}/spotify/spotify-launch" "$INCLUDES/usr/local/bin/spotify-launch" install -m 0755 "${CONFIGS_DIR}/keyboard/toggle-keyboard" "$INCLUDES/usr/local/bin/toggle-keyboard" +# Touchscreen misclassification override (inert 0000:0000 template until the real +# hardware's vendor/product ID is filled in — see that file's own setup steps). +install -m 0644 "${CONFIGS_DIR}/udev/99-touchscreen-override.rules" \ + "$INCLUDES/etc/udev/rules.d/99-touchscreen-override.rules" + # Console (VT/TTY) keymap — separate from Sway's own xkb_layout, since greetd briefly # owns the console before Sway starts. mkdir -p "$INCLUDES/etc/default" @@ -261,6 +267,11 @@ echo " Home Assistant : Chromium kiosk, ${HA_URL}, workspace 2, auto-restart echo " Web browser : Firefox, minimal chrome, uBlock Origin + SponsorBlock, workspace 3" echo " Touch dock : bottom bar (eww) — Spotify / Home / Web / Keyboard buttons" echo " On-screen keyboard: wvkbd, toggled from the dock's Keyboard button" +echo " Touchscreen input : native wl_touch preferred; degrades to a usable" +echo " single-touch/click-drag pointer if the hardware reports" +echo " as an emulated-mouse HID device instead — see README.md" +echo " '99-touchscreen-override.rules' to fix it properly once" +echo " the real hardware's USB vendor/product ID is known" echo " Keyboard layout : ${KEYBOARD_LAYOUT} (console + Sway)" echo " Maintenance shell : Super+Shift+Ctrl+M opens a floating terminal locally" echo " Remote admin : SSH only — no wayvnc on this image, see README" @@ -270,8 +281,13 @@ echo " 1. Write the ISO to a USB stick:" echo " sudo dd if=${ISO_PATH} of=/dev/sdX bs=4M status=progress oflag=sync" echo " (double-check /dev/sdX with 'lsblk' first — dd will happily eat the wrong disk)" echo " 2. Boot the target touchscreen machine from it. No touch-panel hardware has been" -echo " chosen yet (see the README) — confirm touch input is recognised as a Wayland" -echo " wl_touch device (not emulated as a pointer) before treating this as validated." +echo " chosen yet (see the README) — check which way libinput classified the" +echo " touchscreen: libinput list-devices | grep -A2 Capabilities" +echo " If it says 'touch', full multi-touch works out of the box. If it says" +echo " 'pointer' instead, taps still work (single-touch click) via the fallback" +echo " input config, but fill in configs/udev/99-touchscreen-override.rules with" +echo " the device's real USB vendor/product ID and rebuild for the real fix —" +echo " see that file's own setup steps and the README." echo " 3. Confirm greetd autologin lands in Sway: dark background, the touch dock at" echo " the bottom, and the Home Assistant kiosk window on workspace 2:home." echo " 4. Tap through the dock: Spotify (log in on first launch — Premium required),"