Nix-Vibe public snapshot (squashed history)
Current state of main at 0240060 feat(hp-laptop): install TeleportFling from its flake. History intentionally collapsed to a single commit; this repo mirrors only the latest state.
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
palette = import ./palette.nix;
|
||||
evdevPython = pkgs.python3.withPackages (ps: [ ps.evdev ]);
|
||||
|
||||
# Text-capable window classes. wvkbd's own --auto relies on Hyprland's
|
||||
# input-method-v2 protocol, which Hyprland advertises but never actually
|
||||
# fires — so auto show/hide is driven here by watching activewindow events.
|
||||
# Add classes (lowercase prefixes are allowed) for anything you type into.
|
||||
textApps = [
|
||||
"kitty"
|
||||
"alacritty"
|
||||
"wezterm"
|
||||
"konsole"
|
||||
"com.mitchellh.ghostty"
|
||||
"ghostty"
|
||||
"xterm"
|
||||
"firefox"
|
||||
"librewolf"
|
||||
"chromium"
|
||||
"chromium-browser"
|
||||
"google-chrome"
|
||||
"microsoft-edge"
|
||||
"brave-browser"
|
||||
"thunderbird"
|
||||
"com.github.xournalpp.xournalpp"
|
||||
"code"
|
||||
"code-url-handler"
|
||||
"zen"
|
||||
];
|
||||
|
||||
# Shell-escaped arg list for the CLI fallback (same content as wvkbdFlags
|
||||
# but space-joined for shell expansion). The daemon receives the JSON form.
|
||||
# The font spec is double-quoted so it survives shell word-splitting.
|
||||
wvkbdFlagsShell = pkgs.lib.concatStringsSep " " [
|
||||
"-l"
|
||||
"simple"
|
||||
"-H"
|
||||
"300"
|
||||
"-L"
|
||||
"200"
|
||||
"--fn"
|
||||
"\"DejaVu Sans 24\""
|
||||
"--alpha"
|
||||
"235"
|
||||
"--bg"
|
||||
"${palette.wvkbdBg}"
|
||||
"--fg"
|
||||
"${palette.surface}"
|
||||
"--fg-sp"
|
||||
"${palette.wvkbdFgSp}"
|
||||
"--press"
|
||||
"${palette.neon}"
|
||||
"--press-sp"
|
||||
"${palette.violet}"
|
||||
"--text"
|
||||
"${palette.text}"
|
||||
"--text-sp"
|
||||
"${palette.muted}"
|
||||
"--text-press"
|
||||
"${palette.ink}"
|
||||
"--text-press-sp"
|
||||
"${palette.ink}"
|
||||
"--swipe"
|
||||
"${palette.cyan}"
|
||||
"--swipe-sp"
|
||||
"${palette.violet}"
|
||||
"--text-swipe"
|
||||
"${palette.ink}"
|
||||
"--text-swipe-sp"
|
||||
"${palette.ink}"
|
||||
];
|
||||
|
||||
# wvkbd argv as a JSON array. The daemon splices this into place as a bare
|
||||
# Python expression — a JSON array of strings IS valid Python (list of
|
||||
# double-quoted strings), so no quote-escaping headaches at build time.
|
||||
wvkbdArgs = [
|
||||
"-l"
|
||||
"simple"
|
||||
"-H"
|
||||
"300"
|
||||
"-L"
|
||||
"200"
|
||||
"--fn"
|
||||
"DejaVu Sans 24"
|
||||
"--alpha"
|
||||
"235"
|
||||
"--bg"
|
||||
"${palette.wvkbdBg}"
|
||||
"--fg"
|
||||
"${palette.surface}"
|
||||
"--fg-sp"
|
||||
"${palette.wvkbdFgSp}"
|
||||
"--press"
|
||||
"${palette.neon}"
|
||||
"--press-sp"
|
||||
"${palette.violet}"
|
||||
"--text"
|
||||
"${palette.text}"
|
||||
"--text-sp"
|
||||
"${palette.muted}"
|
||||
"--text-press"
|
||||
"${palette.ink}"
|
||||
"--text-press-sp"
|
||||
"${palette.ink}"
|
||||
"--swipe"
|
||||
"${palette.cyan}"
|
||||
"--swipe-sp"
|
||||
"${palette.violet}"
|
||||
"--text-swipe"
|
||||
"${palette.ink}"
|
||||
"--text-swipe-sp"
|
||||
"${palette.ink}"
|
||||
];
|
||||
wvkbdArgsJson = builtins.toJSON wvkbdArgs;
|
||||
|
||||
# Text-app allowlist as a JSON array, spliced the same way (valid Python
|
||||
# list literal after substitution).
|
||||
textAppsJson = builtins.toJSON textApps;
|
||||
|
||||
# Place build-time paths into the daemon (replaceVars honours the
|
||||
# @VAR@ placeholders) and run it with the evdev-enabled python.
|
||||
daemon = pkgs.replaceVarsWith {
|
||||
name = "hyprland-tablet-daemon";
|
||||
src = pkgs.writeScript "hyprland-tablet-daemon-src" ''
|
||||
#!${evdevPython}/bin/python3
|
||||
${builtins.readFile ./hyprland-tablet-daemon.py}
|
||||
'';
|
||||
isExecutable = true;
|
||||
replacements = {
|
||||
EVDEV_DEVICE = "/dev/input/event17";
|
||||
WVKBD_PATH = "${pkgs.wvkbd}/bin/wvkbd-mobintl";
|
||||
WVKBD_ARGS = wvkbdArgsJson;
|
||||
TEXT_APPS_JSON = textAppsJson;
|
||||
MONITOR_SENSOR = "${pkgs.iio-sensor-proxy}/bin/monitor-sensor";
|
||||
HYPRCTL = "${pkgs.hyprland}/bin/hyprctl";
|
||||
};
|
||||
};
|
||||
|
||||
# Toggle/show/hide are forwarded to the daemon over a Unix datagram socket
|
||||
# so manual control and focus-driven auto-hide share one visibility state.
|
||||
cli = pkgs.writeShellScriptBin "hyprland-tablet" ''
|
||||
set -eu
|
||||
state_file="$XDG_RUNTIME_DIR/hyprland-tablet"
|
||||
ctl_sock="$XDG_RUNTIME_DIR/hyprland-tablet.ctl"
|
||||
|
||||
ctl_send() {
|
||||
if [ -S "$ctl_sock" ]; then
|
||||
${pkgs.python3}/bin/python3 -c '
|
||||
import os, socket, sys
|
||||
path = os.environ.get("XDG_RUNTIME_DIR", "/tmp") + "/hyprland-tablet.ctl"
|
||||
s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
|
||||
s.sendto(sys.argv[1].encode(), path)
|
||||
' "$1"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
osk_pid() {
|
||||
pgrep -f 'wvkbd-mobintl' | head -n1 || true
|
||||
}
|
||||
|
||||
case "''${1:-}" in
|
||||
status)
|
||||
if [ -f "$state_file" ]; then
|
||||
cat "$state_file"
|
||||
else
|
||||
echo '{"tablet":false,"osk":false}'
|
||||
fi
|
||||
;;
|
||||
# Toggle on-screen keyboard visibility. Manual control wins over the
|
||||
# daemon's focus-derived state until the next activewindow change.
|
||||
keyboard-toggle|osk-toggle)
|
||||
ctl_send toggle || {
|
||||
pid="$(osk_pid)"
|
||||
if [ -z "$pid" ]; then
|
||||
nohup ${pkgs.wvkbd}/bin/wvkbd-mobintl ${wvkbdFlagsShell} >/dev/null 2>&1 &
|
||||
else
|
||||
kill -SIGRTMIN "$pid"
|
||||
fi
|
||||
}
|
||||
;;
|
||||
osk-show)
|
||||
ctl_send show || { pid="$(osk_pid)"; [ -n "$pid" ] && kill -SIGUSR2 "$pid"; }
|
||||
;;
|
||||
osk-hide)
|
||||
ctl_send hide || { pid="$(osk_pid)"; [ -n "$pid" ] && kill -SIGUSR1 "$pid"; }
|
||||
;;
|
||||
*)
|
||||
echo "usage: hyprland-tablet {status|keyboard-toggle|osk-show|osk-hide}" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
in
|
||||
{
|
||||
home.packages = [ cli ];
|
||||
|
||||
systemd.user.services.hyprland-tablet = {
|
||||
Unit = {
|
||||
Description = "Hyprland tablet-mode auto-rotation + on-screen keyboard";
|
||||
After = [ "graphical-session.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = daemon;
|
||||
Restart = "on-failure";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user