2026-08-09 01:22:23 -07:00
|
|
|
# socktop-swipe
|
|
|
|
|
|
|
|
|
|
Swipe-to-zoom touchscreen navigation for a wall-mounted
|
|
|
|
|
[socktop](https://crates.io/crates/socktop) dashboard.
|
|
|
|
|
|
|
|
|
|
One tmux window shows every monitored host tiled together. Swiping right-to-left
|
|
|
|
|
on the panel zooms into each host full-screen, one at a time; swiping
|
|
|
|
|
left-to-right walks back out to the overview.
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
overview -> host 1 -> host 2 -> host 3 -> host 4
|
|
|
|
|
(tiled) zoomed zoomed zoomed zoomed
|
|
|
|
|
<-------------- swipe left-to-right --------------
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Built for a 10" touch panel on a server rack driving four Raspberry Pis, on a
|
|
|
|
|
low-power x86 box running i3 on X11.
|
|
|
|
|
|
|
|
|
|
## How it works, and why
|
|
|
|
|
|
|
|
|
|
**The carousel is tmux pane zoom, not extra socktop instances.** There is exactly
|
|
|
|
|
one socktop process per host. Zooming calls `tmux resize-pane -Z`, which makes one
|
|
|
|
|
pane fill the window and sends `SIGWINCH` so socktop repaints at the new size.
|
|
|
|
|
|
|
|
|
|
That matters for three reasons:
|
|
|
|
|
|
|
|
|
|
- **Half the processes.** Separate full-screen instances would mean N extra
|
|
|
|
|
socktop processes and double the polling load on the monitored hosts. On a
|
|
|
|
|
1.9 GB display host, that is the difference between comfortable and not.
|
|
|
|
|
- **No reconnect delay.** Hidden panes keep running and stay connected, so
|
|
|
|
|
swiping back to a host shows current data, not a stale snapshot.
|
|
|
|
|
- **Constant load.** The monitored hosts see the same connections regardless of
|
|
|
|
|
what is on screen.
|
|
|
|
|
|
|
|
|
|
**Gestures come from lisgd, below the terminal.** No Linux terminal maps
|
|
|
|
|
horizontal swipes to commands, so this cannot be done in terminal config.
|
|
|
|
|
Critically, **libinput deliberately emits gesture events only for touchpads,
|
|
|
|
|
never for touchscreens** — so `libinput-gestures` and similar tools cannot work
|
|
|
|
|
here at all. [lisgd](https://git.sr.ht/~mil/lisgd) reads raw touch events and
|
|
|
|
|
synthesises the swipes itself, reading `/dev/input` directly and bypassing X.
|
|
|
|
|
|
|
|
|
|
## Requirements
|
|
|
|
|
|
|
|
|
|
- `tmux`, `socktop`, and a working `~/.config/socktop/profiles.json`
|
|
|
|
|
- `lisgd` (the installer builds it)
|
|
|
|
|
- A C toolchain plus `libinput` and `libX11` headers, to build lisgd
|
|
|
|
|
- Membership of the `input` group (the installer adds you; needs a relogin)
|
|
|
|
|
|
|
|
|
|
## Install
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
git clone https://gt.wittyoneoff.com/jason/socktop-swipe
|
|
|
|
|
cd socktop-swipe
|
|
|
|
|
./install.sh --xignore --i3
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Then **log out and back in** — the `input` group and the X rule both need a
|
|
|
|
|
fresh session.
|
|
|
|
|
|
|
|
|
|
| Flag | Effect |
|
|
|
|
|
| --- | --- |
|
|
|
|
|
| *(none)* | Build/install lisgd, install the three scripts and the default config |
|
|
|
|
|
| `--xignore` | Also tell X to ignore the touch panel (see below — usually wanted) |
|
|
|
|
|
| `--i3` | Also add i3 autostart lines, with a backup and `i3 -C` validation |
|
|
|
|
|
|
|
|
|
|
Re-running is safe: an existing config file is never overwritten, and the i3
|
|
|
|
|
edit is skipped if already present.
|
|
|
|
|
|
|
|
|
|
### Verify
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
tools/find-device.sh # confirm TOUCH_DEV is right
|
|
|
|
|
tools/diag.sh # stage 1: device live? stage 2: what does lisgd see?
|
|
|
|
|
tools/test-foreground.sh # run the real daemon, watch the display, swipe
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Configuration
|
|
|
|
|
|
|
|
|
|
Everything lives in **`/usr/local/etc/socktop-swipe.env`**. Edit it there, not in
|
|
|
|
|
the repo copy. After changing it, restart the daemon and rebuild the session:
|
|
|
|
|
|
|
|
|
|
```sh
|
2026-08-09 02:29:36 -07:00
|
|
|
socktop-gestures --replace & # restarts the daemon, running or not
|
2026-08-09 01:22:23 -07:00
|
|
|
socktop-rack
|
|
|
|
|
```
|
|
|
|
|
|
2026-08-09 02:29:36 -07:00
|
|
|
Use `--replace` rather than `pkill -x lisgd && socktop-gestures`: `pkill` exits
|
|
|
|
|
non-zero when it matches nothing, so that one-liner silently starts **nothing**
|
|
|
|
|
if no daemon was running — you would swipe, get no response, and reasonably
|
|
|
|
|
blame the config change.
|
|
|
|
|
|
2026-08-09 01:22:23 -07:00
|
|
|
| Option | Default | What it does |
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
| `SOCKTOP_HOSTS` | four Pi profiles | socktop profile names, **in swipe order**. Any count works; layout and carousel adapt. |
|
|
|
|
|
| `SOCKTOP_SESSION` | `socktop4` | tmux session name |
|
|
|
|
|
| `SOCKTOP_BIN` | `$HOME/.cargo/bin/socktop` | Full path — i3 does not have `~/.cargo/bin` on `PATH` |
|
|
|
|
|
| `TOUCH_DEV` | ILITEK by-id path | Touch device. **Always use a `/dev/input/by-id/` path**; `eventN` numbers change on reboot. |
|
|
|
|
|
| `SCREEN_W` / `SCREEN_H` | `1024` / `600` | The **panel's** resolution, not the X screen. See gotcha 2. |
|
|
|
|
|
| `SWIPE_THRESHOLD` | `80` | Pixels of travel before a drag counts as a swipe |
|
|
|
|
|
| `SWIPE_LENIENCY` | `30` | Degrees off-axis tolerated (max 45) |
|
|
|
|
|
| `FINGER_COUNTS` | `1 2 3` | Contact counts accepted. **The setting most likely to need changing** — see gotcha 1. |
|
|
|
|
|
| `GESTURE_IN` / `GESTURE_OUT` | `RL` / `LR` | Swap these to reverse swipe direction |
|
|
|
|
|
|
|
|
|
|
### Adding or removing hosts
|
|
|
|
|
|
|
|
|
|
Edit `SOCKTOP_HOSTS` and run `socktop-rack`. Nothing else needs touching — the
|
|
|
|
|
carousel derives its length from the pane count at runtime.
|
|
|
|
|
|
|
|
|
|
## Autostart
|
|
|
|
|
|
|
|
|
|
`./install.sh --i3` appends to `~/.config/i3/config`. For systemd user sessions
|
|
|
|
|
instead:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
cp socktop-swipe.service ~/.config/systemd/user/
|
|
|
|
|
systemctl --user enable --now socktop-swipe
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Either way, **run exactly one gesture daemon**. lisgd does not grab the input
|
|
|
|
|
device exclusively, so two instances make every swipe fire twice.
|
2026-08-09 02:29:36 -07:00
|
|
|
`socktop-gestures` enforces this: it exits non-zero if one is already running,
|
|
|
|
|
unless given `--replace`.
|
2026-08-09 01:22:23 -07:00
|
|
|
|
|
|
|
|
## Uninstall
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
./uninstall.sh # scripts, config, X rule
|
|
|
|
|
./uninstall.sh --keep-config # keep your settings
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
lisgd, the `input` group and your socktop profiles are deliberately left alone;
|
|
|
|
|
the script prints how to remove each.
|
|
|
|
|
|
|
|
|
|
## Troubleshooting
|
|
|
|
|
|
|
|
|
|
Four gotchas account for nearly every failure. All were found the hard way.
|
|
|
|
|
|
|
|
|
|
### 1. Gestures are recognised but never fire
|
|
|
|
|
|
|
|
|
|
Run `tools/diag.sh` and read stage 2:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
[swipe]: Cfg(f=1/s=3/e=0/d=0) <=> Evt(f=2/s=3/e=1/d=2)
|
|
|
|
|
^ configured ^ what happened
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Matching `s=` with differing `f=` means **your panel reports more contacts than
|
|
|
|
|
you configured**. Many multipoint panels report 2 or even 3 contacts for a
|
|
|
|
|
physically one-finger swipe. Add them to `FINGER_COUNTS`.
|
|
|
|
|
|
|
|
|
|
Direction enum: `0=DU`, `1=UD`, `2=LR`, `3=RL`.
|
|
|
|
|
|
|
|
|
|
### 2. Swipes register, but erratically — resizing panes, zooming text
|
|
|
|
|
|
|
|
|
|
X is also delivering touch to whatever is on screen, so a single swipe hits
|
|
|
|
|
several consumers at once: tmux mouse mode drags pane borders, the terminal
|
|
|
|
|
reads 2-contact swipes as pinch-zoom, and socktop enables its own all-motion
|
|
|
|
|
mouse reporting (`?1003h`). Meanwhile lisgd fires too.
|
|
|
|
|
|
|
|
|
|
Fix with `./install.sh --xignore` and relog. lisgd is unaffected because it
|
|
|
|
|
reads the device directly. Trade-off: no tap or pinch-zoom on that panel —
|
|
|
|
|
terminal keyboard zoom (`Ctrl +` / `Ctrl -`) still works.
|
|
|
|
|
|
|
|
|
|
Also ensure tmux mouse mode is **off**; `socktop-rack` sets this.
|
|
|
|
|
|
|
|
|
|
### 3. Every swipe jumps two panes
|
|
|
|
|
|
|
|
|
|
Two lisgd instances are running. `pgrep -x lisgd` should show exactly one.
|
|
|
|
|
|
2026-08-09 02:29:36 -07:00
|
|
|
`socktop-gestures` refuses to start if a daemon is already running, so this
|
|
|
|
|
should not happen via the normal path; `--replace` restarts cleanly. It can
|
|
|
|
|
still occur if lisgd was launched by hand.
|
|
|
|
|
|
2026-08-09 01:22:23 -07:00
|
|
|
### 4. Swipes do nothing at all
|
|
|
|
|
|
|
|
|
|
In order: is the session running (`tmux ls`)? Is the daemon running
|
|
|
|
|
(`pgrep -x lisgd`)? Does `tools/diag.sh` stage 1 read bytes? Are you in the
|
|
|
|
|
`input` group (`id -nG | grep input`, needs a relogin)?
|
|
|
|
|
|
|
|
|
|
Note lisgd's verbose flag is **`-v`**, not `-D`.
|
|
|
|
|
|
|
|
|
|
### Multi-monitor note
|
|
|
|
|
|
|
|
|
|
If the display host has a second monitor, X reports the **combined** root window
|
|
|
|
|
(e.g. 2304x720). lisgd would scale its maths to that, so `SCREEN_W`/`SCREEN_H`
|
|
|
|
|
must describe the touch panel alone. `socktop-gestures` always passes them
|
|
|
|
|
explicitly.
|
|
|
|
|
|
|
|
|
|
## Known limitations
|
|
|
|
|
|
|
|
|
|
- **~300 ms repaint on zoom-in.** Between tmux making the pane full-screen and
|
|
|
|
|
socktop repainting, you briefly see the old small rendering anchored top-left.
|
|
|
|
|
This is socktop's redraw latency, not the gesture path; nothing outside
|
|
|
|
|
socktop can fix it. Zooming out has no visible artifact, since panes return to
|
|
|
|
|
sizes they were already drawn at.
|
|
|
|
|
- Deliberately **no wrap-around** at the ends of the carousel — on a wall display
|
|
|
|
|
wrapping makes it impossible to tell where you are.
|
|
|
|
|
- X11 only. The lisgd build disables its Wayland backend (`WITHOUT_WAYLAND=1`).
|
|
|
|
|
|
|
|
|
|
## Tested on
|
|
|
|
|
|
|
|
|
|
LattePanda (Atom x5-Z8350, 1.9 GB RAM, Cherry Trail graphics), 1024x600 ILITEK
|
|
|
|
|
DSI touch panel, Debian 11, i3 on X11, Alacritty 0.16.1, lisgd from git,
|
|
|
|
|
monitoring four Raspberry Pis.
|