68 lines
2.8 KiB
Text
68 lines
2.8 KiB
Text
|
|
#!/bin/sh
|
||
|
|
# Report a hardware button edge to the session authority. That is all it does.
|
||
|
|
#
|
||
|
|
# It replaces `blueline-power-button`, which was policy in shell script: it read
|
||
|
|
# its own copy of the panel state, asked the SHELL to lock over `qs ipc`, polled
|
||
|
|
# `session state` twenty times at 100 ms grepping JSON for `"locked": true`, and
|
||
|
|
# then called `blueline-screen-toggle off` itself. Three separate problems:
|
||
|
|
#
|
||
|
|
# 1. It blanked the panel without going through sessiond's `request_blank()`,
|
||
|
|
# so LOCK-DPMS-LESSONS §1 ("every path to a dark panel routes through it —
|
||
|
|
# an invariant, not a coincidence") had a hole in it, and the hole was the
|
||
|
|
# most-used control on the device.
|
||
|
|
# 2. It carried its own copy of the lock-then-blank ordering, which is the
|
||
|
|
# exact duplication DEVICE-STATE-MACHINE §1 is about: seven blind actors,
|
||
|
|
# three of which can turn the screen off.
|
||
|
|
# 3. It could only ever see one edge, so it could never tell a tap from a
|
||
|
|
# hold. Gesture recognition needs time, and a process that exits cannot
|
||
|
|
# hold any.
|
||
|
|
#
|
||
|
|
# Now the machine owns all three. This reports `down` and `up`; sessiond
|
||
|
|
# accumulates them into tap / double / triple / hold and decides what, if
|
||
|
|
# anything, that means.
|
||
|
|
#
|
||
|
|
# Wire it up in hyprland.lua as a PAIR — press and release:
|
||
|
|
#
|
||
|
|
# hl.bind( "XF86PowerOff", hl.dsp.exec_cmd("souveraine-button power down"), { locked = true })
|
||
|
|
# hl.bindr("XF86PowerOff", hl.dsp.exec_cmd("souveraine-button power up"), { locked = true })
|
||
|
|
#
|
||
|
|
# Only reporting `down` gives you a machine that thinks the button is held
|
||
|
|
# forever: the hold threshold passes, `Hold` fires, and no `Tap` ever resolves.
|
||
|
|
set -eu
|
||
|
|
|
||
|
|
button=${1:-power}
|
||
|
|
edge=${2:-down}
|
||
|
|
|
||
|
|
case "$edge" in
|
||
|
|
down | up) ;;
|
||
|
|
*)
|
||
|
|
echo "usage: souveraine-button <power|volume_up|volume_down> <down|up>" >&2
|
||
|
|
exit 2
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
|
||
|
|
runtime=${XDG_RUNTIME_DIR:-/run/user/$(id -u)}
|
||
|
|
sock="$runtime/souveraine/sessiond.sock"
|
||
|
|
|
||
|
|
line="{\"op\":\"button\",\"button\":\"$button\",\"edge\":\"$edge\"}"
|
||
|
|
|
||
|
|
# Fire and forget, with a hard timeout. A button press must never block on the
|
||
|
|
# authority being slow — the user is holding the button and the phone must not
|
||
|
|
# feel stuck. Losing an edge degrades to a missed gesture, which is recoverable;
|
||
|
|
# hanging here is not.
|
||
|
|
#
|
||
|
|
# No nc/socat on this device (checked), so this is Python's stdlib or nothing.
|
||
|
|
exec timeout 1 python3 -c '
|
||
|
|
import socket, sys
|
||
|
|
sock, line = sys.argv[1], sys.argv[2]
|
||
|
|
try:
|
||
|
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||
|
|
s.settimeout(0.8)
|
||
|
|
s.connect(sock)
|
||
|
|
s.sendall((line + "\n").encode())
|
||
|
|
except Exception:
|
||
|
|
# sessiond down. Say so in the journal and drop it: a button reporter that
|
||
|
|
# falls back to acting on its own is the thing this file exists to delete.
|
||
|
|
print("sessiond unreachable; button edge dropped: " + line, file=sys.stderr)
|
||
|
|
sys.exit(1)
|
||
|
|
' "$sock" "$line"
|