add squeekboard, remove llm comments
This commit is contained in:
@@ -0,0 +1,67 @@
|
|||||||
|
{ pkgs
|
||||||
|
, lib
|
||||||
|
, inputs
|
||||||
|
, system
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
att_menu = inputs.att_menu.packages.${system}.default;
|
||||||
|
att_wm = inputs.att_wm.packages.${system}.default;
|
||||||
|
|
||||||
|
attwmctl = pkgs.writeShellScriptBin "attwmctl" ''
|
||||||
|
exec ${att_wm}/bin/att_wmctl "$@"
|
||||||
|
'';
|
||||||
|
|
||||||
|
tablet_mode =
|
||||||
|
pkgs.writeShellScriptBin "tablet-mode"
|
||||||
|
(builtins.readFile ./tablet-mode.sh);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
home.packages = [
|
||||||
|
att_menu
|
||||||
|
attwmctl
|
||||||
|
tablet_mode
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.user.services = {
|
||||||
|
att_menu = {
|
||||||
|
Unit = {
|
||||||
|
Description = "att_menu touch panel (tablet mode)";
|
||||||
|
PartOf = [ "graphical-session.target" ];
|
||||||
|
After = [ "graphical-session.target" ];
|
||||||
|
StartLimitIntervalSec = 0;
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
ExecStart = lib.getExe att_menu;
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 3;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
tablet-mode = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Run the tablet-only services while the machine is folded";
|
||||||
|
PartOf = [ "graphical-session.target" ];
|
||||||
|
After = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Environment = [
|
||||||
|
"PATH=${lib.makeBinPath [
|
||||||
|
pkgs.evtest
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.systemd
|
||||||
|
pkgs.bash
|
||||||
|
]}"
|
||||||
|
];
|
||||||
|
ExecStart = ''
|
||||||
|
${tablet_mode}/bin/tablet-mode \
|
||||||
|
--on 'systemctl --user start att_menu.service squeekboard.service' \
|
||||||
|
--off 'systemctl --user stop att_menu.service squeekboard.service'
|
||||||
|
'';
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = 5;
|
||||||
|
};
|
||||||
|
Install.WantedBy = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Executable
+187
@@ -0,0 +1,187 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# auto-rotate — rotate a wlroots output from iio-sensor-proxy orientation events.
|
||||||
|
#
|
||||||
|
# Unlike rot8 this does not read the accelerometer itself. iio-sensor-proxy owns
|
||||||
|
# sensor selection (fuji has two accel_3d devices), applies its own hysteresis,
|
||||||
|
# and reports `undefined` when the device is too flat to have a meaningful
|
||||||
|
# orientation — so there is no dead zone in which we silently keep a stale state.
|
||||||
|
#
|
||||||
|
# SIGUSR1 toggle rotation lock (current transform is kept)
|
||||||
|
# SIGUSR2 re-apply the last known orientation (e.g. after kanshi resets it)
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
OUTPUT="${AUTOROTATE_OUTPUT:-eDP-1}"
|
||||||
|
HOOKS=()
|
||||||
|
VERBOSE=0
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<-EOF
|
||||||
|
usage: auto-rotate [-o OUTPUT] [-H HOOK]... [-v]
|
||||||
|
|
||||||
|
-o, --output OUTPUT output to rotate (default: ${OUTPUT})
|
||||||
|
-H, --hook CMD run CMD after each rotation; may be repeated.
|
||||||
|
\$ORIENTATION and \$PREV_ORIENTATION are exported.
|
||||||
|
-v, --verbose log every sensor event, not just rotations
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
-o | --output)
|
||||||
|
OUTPUT="${2:?--output needs a value}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-H | --hook)
|
||||||
|
HOOKS+=("${2:?--hook needs a value}")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-v | --verbose)
|
||||||
|
VERBOSE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h | --help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'auto-rotate: unknown argument: %s\n' "$1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
for cmd in monitor-sensor wlr-randr; do
|
||||||
|
command -v "$cmd" >/dev/null || {
|
||||||
|
printf 'auto-rotate: %s not found in PATH\n' "$cmd" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
log() { printf '[auto-rotate] %s\n' "$*"; }
|
||||||
|
vlog() { [ "$VERBOSE" = 1 ] && log "$@"; return 0; }
|
||||||
|
|
||||||
|
# iio-sensor-proxy orientation -> wlr-randr transform.
|
||||||
|
#
|
||||||
|
# NOTE: if the screen ends up 180 degrees off, swap the left-up and right-up
|
||||||
|
# lines. This mapping is the common convention but it is not something the
|
||||||
|
# sensor tells us, so it has to be confirmed by hand once.
|
||||||
|
transform_for() {
|
||||||
|
case "$1" in
|
||||||
|
normal) printf 'normal' ;;
|
||||||
|
left-up) printf '90' ;;
|
||||||
|
bottom-up) printf '180' ;;
|
||||||
|
right-up) printf '270' ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
current_transform() {
|
||||||
|
wlr-randr 2>/dev/null |
|
||||||
|
awk -v o="$OUTPUT" '
|
||||||
|
$1 == o { found = 1; next }
|
||||||
|
/^[^ \t]/ { found = 0 }
|
||||||
|
found && $1 == "Transform:" { print $2; exit }
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
applied="$(current_transform)"
|
||||||
|
[ -n "$applied" ] || {
|
||||||
|
printf 'auto-rotate: output %s not found\n' "$OUTPUT" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
log "output ${OUTPUT}, current transform ${applied}"
|
||||||
|
|
||||||
|
orientation="" # last non-undefined orientation from the sensor
|
||||||
|
prev_orientation="" # the one before that, exported to hooks
|
||||||
|
locked=0
|
||||||
|
|
||||||
|
toggle_lock() {
|
||||||
|
locked=$((1 - locked))
|
||||||
|
[ "$locked" = 1 ] && log "rotation locked at ${applied}" || log "rotation unlocked"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply() {
|
||||||
|
local target
|
||||||
|
target="$(transform_for "$orientation")" || return 0
|
||||||
|
[ "$target" = "$applied" ] && return 0
|
||||||
|
|
||||||
|
if ! wlr-randr --output "$OUTPUT" --transform "$target"; then
|
||||||
|
# Do not advance `applied` — a failed rotation must not desync our idea
|
||||||
|
# of the output state from reality. This was rot8's other failure mode.
|
||||||
|
log "wlr-randr failed, keeping transform as ${applied}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
log "${applied} -> ${target} (${orientation})"
|
||||||
|
applied="$target"
|
||||||
|
|
||||||
|
local hook
|
||||||
|
for hook in ${HOOKS+"${HOOKS[@]}"}; do
|
||||||
|
ORIENTATION="$orientation" PREV_ORIENTATION="$prev_orientation" \
|
||||||
|
bash -c "$hook" || log "hook failed: ${hook}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
reapply() {
|
||||||
|
applied="$(current_transform)"
|
||||||
|
log "re-syncing, output is at ${applied}"
|
||||||
|
[ "$locked" = 0 ] && [ -n "$orientation" ] && apply
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
trap toggle_lock USR1
|
||||||
|
trap reapply USR2
|
||||||
|
|
||||||
|
exec 3< <(stdbuf -oL monitor-sensor 2>&1)
|
||||||
|
monitor_pid=$!
|
||||||
|
trap 'kill "$monitor_pid" 2>/dev/null; exit 0' INT TERM EXIT
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
# A signal interrupts read; that is not an error, so retry rather than exit.
|
||||||
|
IFS= read -r line <&3 || {
|
||||||
|
kill -0 "$monitor_pid" 2>/dev/null && continue
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$line" in
|
||||||
|
*"Accelerometer orientation changed: "*)
|
||||||
|
new="${line##*: }"
|
||||||
|
;;
|
||||||
|
*"Has accelerometer (orientation: "*)
|
||||||
|
# The initial state only ever arrives on this banner line; a
|
||||||
|
# "changed" line is not emitted until the orientation moves.
|
||||||
|
new="${line#*orientation: }"
|
||||||
|
new="${new%%,*}"
|
||||||
|
;;
|
||||||
|
*"iio-sensor-proxy appeared"*)
|
||||||
|
# The proxy restarted; our cached transform may be stale.
|
||||||
|
reapply
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
*"Compass heading changed"*)
|
||||||
|
# ~1 Hz of noise we have no use for; drop it even when verbose.
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
vlog "$line"
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
vlog "sensor says ${new}"
|
||||||
|
|
||||||
|
# `undefined` means the device is lying too flat to tell. Hold position.
|
||||||
|
[ "$new" = undefined ] && continue
|
||||||
|
[ "$new" = "$orientation" ] && continue
|
||||||
|
|
||||||
|
prev_orientation="$orientation"
|
||||||
|
orientation="$new"
|
||||||
|
|
||||||
|
[ "$locked" = 1 ] && {
|
||||||
|
vlog "locked, ignoring ${orientation}"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
apply
|
||||||
|
done
|
||||||
|
|
||||||
|
log "monitor-sensor exited"
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# tablet-mode — run commands as the machine is folded into, and out of, a tablet.
|
||||||
|
#
|
||||||
|
# sway has `bindswitch tablet:on`, but att_wm has none and river's init is a
|
||||||
|
# startup script rather than an IPC surface, so there is nothing to bind there.
|
||||||
|
# Reading SW_TABLET_MODE off evdev is the one mechanism that works in both
|
||||||
|
# sessions, which is why it is the only one used here — sway's bindswitch is
|
||||||
|
# left gating rotation and nothing else.
|
||||||
|
#
|
||||||
|
# evtest does the reading: without --grab it only listens, so the compositor
|
||||||
|
# still gets the switch, and its opening dump reports the *current* state. That
|
||||||
|
# last part is the reason it is evtest and not `libinput debug-events` — a
|
||||||
|
# session that starts already folded has no transition to react to.
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
DEVICE="${TABLET_MODE_DEVICE:-}"
|
||||||
|
ON_CMD=""
|
||||||
|
OFF_CMD=""
|
||||||
|
VERBOSE=0
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<-EOF
|
||||||
|
usage: tablet-mode [-d DEVICE] [--on CMD] [--off CMD] [-v]
|
||||||
|
|
||||||
|
-d, --device DEVICE evdev node to watch (default: found by capability)
|
||||||
|
--on CMD run CMD when the machine enters tablet mode
|
||||||
|
--off CMD run CMD when it leaves
|
||||||
|
-v, --verbose log every line evtest prints
|
||||||
|
|
||||||
|
Both commands run through \`bash -c\` with \$TABLET_MODE set to 1 or 0.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
-d | --device)
|
||||||
|
DEVICE="${2:?--device needs a value}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--on)
|
||||||
|
ON_CMD="${2:?--on needs a value}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--off)
|
||||||
|
OFF_CMD="${2:?--off needs a value}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-v | --verbose)
|
||||||
|
VERBOSE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h | --help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'tablet-mode: unknown argument: %s\n' "$1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
command -v evtest >/dev/null || {
|
||||||
|
printf 'tablet-mode: evtest not found in PATH\n' >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log() { printf '[tablet-mode] %s\n' "$*"; }
|
||||||
|
vlog() {
|
||||||
|
[ "$VERBOSE" = 1 ] && log "$@"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find the switch by capability rather than by name or by-path: on fuji it is an
|
||||||
|
# intel-hid device that is registered after boot, so neither its event number
|
||||||
|
# nor its presence at our start time can be counted on. Not finding it is a
|
||||||
|
# non-zero exit, which is what makes systemd try us again a few seconds later.
|
||||||
|
#
|
||||||
|
# In /proc/bus/input/devices each device ends with its capability bitmaps, and
|
||||||
|
# SW_TABLET_MODE is bit 1 of the switch one. `H:` precedes `B:` in every record,
|
||||||
|
# so the handler list is always already in hand by the time the bitmap arrives.
|
||||||
|
find_device() {
|
||||||
|
local line handlers="" bitmap handler
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
"H: Handlers="*)
|
||||||
|
handlers="${line#H: Handlers=}"
|
||||||
|
;;
|
||||||
|
"B: SW="*)
|
||||||
|
# A bitmap is hex words, most significant first; bit 1
|
||||||
|
# lives in the last of them.
|
||||||
|
bitmap="${line#B: SW=}"
|
||||||
|
bitmap="${bitmap##* }"
|
||||||
|
[ -n "$bitmap" ] || continue
|
||||||
|
(((0x$bitmap & 2) == 0)) && continue
|
||||||
|
for handler in $handlers; do
|
||||||
|
case "$handler" in
|
||||||
|
event*)
|
||||||
|
printf '/dev/input/%s' "$handler"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done </proc/bus/input/devices
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -z "$DEVICE" ]; then
|
||||||
|
DEVICE="$(find_device)" || {
|
||||||
|
printf 'tablet-mode: no input device reports SW_TABLET_MODE\n' >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
[ -r "$DEVICE" ] || {
|
||||||
|
printf 'tablet-mode: cannot read %s\n' "$DEVICE" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
log "watching ${DEVICE}"
|
||||||
|
|
||||||
|
state="" # last seen switch state, "" until evtest reports the first one
|
||||||
|
|
||||||
|
apply() {
|
||||||
|
local cmd
|
||||||
|
case "$1" in
|
||||||
|
1) cmd="$ON_CMD" ;;
|
||||||
|
0) cmd="$OFF_CMD" ;;
|
||||||
|
*) return 0 ;;
|
||||||
|
esac
|
||||||
|
[ -n "$cmd" ] || return 0
|
||||||
|
TABLET_MODE="$1" bash -c "$cmd" || log "hook failed: ${cmd}"
|
||||||
|
}
|
||||||
|
|
||||||
|
exec 3< <(stdbuf -oL evtest "$DEVICE" 2>&1)
|
||||||
|
evtest_pid=$!
|
||||||
|
# Only kill the child here — an `exit` in an EXIT trap would overwrite the
|
||||||
|
# status below, and systemd needs to see a failure to restart us.
|
||||||
|
trap 'kill "$evtest_pid" 2>/dev/null' EXIT
|
||||||
|
trap 'exit 0' INT TERM
|
||||||
|
|
||||||
|
while IFS= read -r line <&3; do
|
||||||
|
case "$line" in
|
||||||
|
# A transition:
|
||||||
|
# Event: time ..., type 5 (EV_SW), code 1 (SW_TABLET_MODE), value 1
|
||||||
|
*"(SW_TABLET_MODE), value "*)
|
||||||
|
new="${line##*, value }"
|
||||||
|
;;
|
||||||
|
# The opening dump, which is where the state at startup comes from:
|
||||||
|
# Event code 1 (SW_TABLET_MODE) state 0
|
||||||
|
*"(SW_TABLET_MODE) state "*)
|
||||||
|
new="${line##* state }"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
vlog "$line"
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ "$new" = "$state" ] && continue
|
||||||
|
state="$new"
|
||||||
|
[ "$state" = 1 ] && log "tablet mode on" || log "tablet mode off"
|
||||||
|
apply "$state"
|
||||||
|
done
|
||||||
|
|
||||||
|
log "evtest exited"
|
||||||
|
exit 1
|
||||||
Reference in New Issue
Block a user