Merge pull request #110 from outis1one/claude/offline-install-readme-kfpr5u
Claude/offline install readme kfpr5u
This commit is contained in:
@@ -317,6 +317,9 @@ Both can be used at the same time — they serve different purposes:
|
|||||||
- **build-essential** - GCC, make, etc.
|
- **build-essential** - GCC, make, etc.
|
||||||
- **Python 3** with evdev for PTT
|
- **Python 3** with evdev for PTT
|
||||||
- **jq** - JSON processing
|
- **jq** - JSON processing
|
||||||
|
- **curl / git** - Downloading and version control
|
||||||
|
- **net-tools** - Legacy networking utilities (ifconfig, netstat, etc.)
|
||||||
|
- **ncdu** - Disk usage analyzer for troubleshooting
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -375,6 +378,57 @@ id kiosk
|
|||||||
sudo -u kiosk DISPLAY=:0 xdpyinfo
|
sudo -u kiosk DISPLAY=:0 xdpyinfo
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**External monitor/TV (HDMI) shows nothing, or shows a cropped/scaled picture:**
|
||||||
|
|
||||||
|
Any connected display beyond the primary is mirrored automatically at the **primary's exact resolution** (not the external display's own native resolution) — both at kiosk login/boot (via Openbox autostart) and live when plugged/unplugged afterward (via a udev rule that triggers `kiosk-hotplug.service`). Both paths call the same `/usr/local/bin/kiosk-mirror-display.sh`. If the external display doesn't natively list the primary's resolution (e.g. a 1366x768 laptop panel mirrored to a 1920x1080-native TV), a matching mode is generated on the fly with `cvt` and forced onto the output — most monitors/TVs accept a close, non-native CVT timing without issue, but a few strict ones may reject it (see below).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List outputs and check if the external display is detected
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority xrandr
|
||||||
|
|
||||||
|
# Look for your output (e.g. HDMI1/HDMI2/HDMI-1) as "connected" with a mode list.
|
||||||
|
|
||||||
|
# Check what the mirroring logic actually did (native mode vs. forced CVT mode, or failures)
|
||||||
|
journalctl | grep "KIOSK:" | tail -20
|
||||||
|
|
||||||
|
# Check whether the hotplug handler fired
|
||||||
|
sudo journalctl -u kiosk-hotplug.service -n 20
|
||||||
|
|
||||||
|
# Manually re-trigger it
|
||||||
|
sudo systemctl start kiosk-hotplug.service
|
||||||
|
|
||||||
|
# Run the mirroring logic by hand for more verbose output
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority bash -x /usr/local/bin/kiosk-mirror-display.sh
|
||||||
|
```
|
||||||
|
If the output shows `disconnected`, it's a cabling/port/EDID issue, not software — try a different cable/port or a monitor known to work.
|
||||||
|
|
||||||
|
If a forced CVT mode is rejected by the display (blank screen only after mirroring runs, works fine before), that display's EDID doesn't accept out-of-spec timings — you'll need to manually pick one of its natively listed modes instead:
|
||||||
|
```bash
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority xrandr --output HDMI2 --mode 1360x768 --same-as eDP1
|
||||||
|
```
|
||||||
|
|
||||||
|
**No sound over HDMI (audio only from laptop/built-in speakers):**
|
||||||
|
|
||||||
|
Whenever an external display is connected/mirrored, `kiosk-audio-route.sh` switches PipeWire's default sink to whichever sink's name contains `hdmi`, and moves any already-playing audio stream onto it. It's called at kiosk login (after PipeWire is confirmed ready) and by `kiosk-hotplug.service` on every plug/unplug — see `/usr/local/bin/kiosk-mirror-display.sh` above for the display side of the same hotplug event.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List sinks and confirm an HDMI one exists (name will contain "hdmi")
|
||||||
|
sudo -u kiosk pactl list sinks short
|
||||||
|
|
||||||
|
# Check what the routing logic actually did
|
||||||
|
journalctl | grep "KIOSK: audio routed\|KIOSK: failed to route" | tail -10
|
||||||
|
|
||||||
|
# Check current default sink
|
||||||
|
sudo -u kiosk pactl get-default-sink
|
||||||
|
|
||||||
|
# Manually re-trigger routing
|
||||||
|
sudo systemctl start kiosk-hotplug.service
|
||||||
|
|
||||||
|
# Force it by hand if needed (replace with your sink name from the list above)
|
||||||
|
sudo -u kiosk pactl set-default-sink alsa_output.pci-0000_00_1f.3.hdmi-stereo
|
||||||
|
```
|
||||||
|
If no sink name contains `hdmi`, the audio codec on that HDMI port either isn't exposed by ALSA/PipeWire on this hardware, or the monitor/TV doesn't report HDMI audio support in its EDID (common on monitors that only do video) — in that case there's no PipeWire-side fix, audio has to come from the laptop speakers or a separate cable.
|
||||||
|
|
||||||
**Audio not working:**
|
**Audio not working:**
|
||||||
```bash
|
```bash
|
||||||
# Check PipeWire (use menu: Advanced → Audio Diagnostics)
|
# Check PipeWire (use menu: Advanced → Audio Diagnostics)
|
||||||
@@ -1119,6 +1173,9 @@ See the LICENSE file in the repository for full terms.
|
|||||||
**Current Version:** 1.0.3
|
**Current Version:** 1.0.3
|
||||||
|
|
||||||
**Recent Updates (v1.0.3):**
|
**Recent Updates (v1.0.3):**
|
||||||
|
- **HDMI/external display mirroring:** any connected display beyond the primary (e.g. HDMI-out to a monitor/TV) is now mirrored automatically at the primary's exact resolution — generating a custom `cvt` mode if the external display doesn't natively list it — both at kiosk login/boot and live on plug/unplug via a new udev-triggered `kiosk-hotplug.service`. Previously the external output was left inactive even when detected by X, and would otherwise mirror at its own native resolution instead of matching the kiosk panel
|
||||||
|
- **HDMI audio routing:** audio now follows the same hotplug event — the default PipeWire sink automatically switches to the HDMI audio output when an external display is connected/mirrored, and back to the built-in sink when it's disconnected (`kiosk-audio-route.sh`)
|
||||||
|
- **Package install:** installer now also installs `net-tools` and `ncdu` (alongside the already-installed `curl` and `git`)
|
||||||
- **Touch input fix (keyring):** added `--password-store=basic` to the Electron launch. Under LightDM autologin the GNOME keyring stays locked; when Chromium accessed it, the keyring unlock dialog grabbed all keyboard/touch input — the kiosk rendered fine but ignored every tap and keypress. This flag stops Electron from using the keyring, so the dialog never appears.
|
- **Touch input fix (keyring):** added `--password-store=basic` to the Electron launch. Under LightDM autologin the GNOME keyring stays locked; when Chromium accessed it, the keyring unlock dialog grabbed all keyboard/touch input — the kiosk rendered fine but ignored every tap and keypress. This flag stops Electron from using the keyring, so the dialog never appears.
|
||||||
- **Touch gesture fix (libinput):** any touch screen is now forced to the `libinput` driver via `/etc/X11/xorg.conf.d/99-finger-libinput.conf` (matched by hardware capability, so it works on any brand and never affects keyboards, mice, or the pen/stylus). Some drivers — notably `wacom` — only do single-touch pointer emulation and never pass real multitouch to Chromium, so 1-finger and 2-finger swipe gestures could not fire. libinput delivers proper multitouch.
|
- **Touch gesture fix (libinput):** any touch screen is now forced to the `libinput` driver via `/etc/X11/xorg.conf.d/99-finger-libinput.conf` (matched by hardware capability, so it works on any brand and never affects keyboards, mice, or the pen/stylus). Some drivers — notably `wacom` — only do single-touch pointer emulation and never pass real multitouch to Chromium, so 1-finger and 2-finger swipe gestures could not fire. libinput delivers proper multitouch.
|
||||||
- **Upgrade reliability:** `start.sh` is now refreshed on every upgrade alongside `main.js` and `preload.js`
|
- **Upgrade reliability:** `start.sh` is now refreshed on every upgrade alongside `main.js` and `preload.js`
|
||||||
@@ -1160,7 +1217,7 @@ See the LICENSE file in the repository for full terms.
|
|||||||
**Known Limitations:**
|
**Known Limitations:**
|
||||||
- Raspberry Pi support untested in production
|
- Raspberry Pi support untested in production
|
||||||
- No web-based configuration (CLI menu only)
|
- No web-based configuration (CLI menu only)
|
||||||
- Single display only (extended desktop not supported)
|
- Extended desktop not supported — additional connected displays (e.g. HDMI-out to a monitor/TV) are automatically **mirrored**, not extended
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -3844,6 +3844,8 @@ complete_uninstall() {
|
|||||||
echo "[5/13] Removing scripts..."
|
echo "[5/13] Removing scripts..."
|
||||||
sudo rm -f /usr/local/bin/kiosk-*
|
sudo rm -f /usr/local/bin/kiosk-*
|
||||||
sudo rm -f /usr/local/bin/rtc-wake.sh
|
sudo rm -f /usr/local/bin/rtc-wake.sh
|
||||||
|
sudo rm -f /etc/udev/rules.d/99-kiosk-hotplug.rules
|
||||||
|
sudo udevadm control --reload-rules 2>/dev/null || true
|
||||||
|
|
||||||
# Remove CUPS
|
# Remove CUPS
|
||||||
echo "[6/13] Removing CUPS..."
|
echo "[6/13] Removing CUPS..."
|
||||||
@@ -3953,7 +3955,8 @@ first_time_install() {
|
|||||||
libegl-mesa0 libegl1-mesa-dev libgles2-mesa-dev \
|
libegl-mesa0 libegl1-mesa-dev libgles2-mesa-dev \
|
||||||
pipewire pipewire-pulse pipewire-alsa wireplumber pipewire-audio-client-libraries alsa-utils libnotify-bin \
|
pipewire pipewire-pulse pipewire-alsa wireplumber pipewire-audio-client-libraries alsa-utils libnotify-bin \
|
||||||
gstreamer1.0-pipewire libspa-0.2-bluetooth \
|
gstreamer1.0-pipewire libspa-0.2-bluetooth \
|
||||||
systemd-timesyncd acpid xbindkeys xdotool python3-evdev unzip
|
systemd-timesyncd acpid xbindkeys xdotool python3-evdev unzip \
|
||||||
|
net-tools ncdu
|
||||||
|
|
||||||
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
|
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
|
||||||
sudo apt install -y intel-gpu-tools xserver-xorg-video-intel \
|
sudo apt install -y intel-gpu-tools xserver-xorg-video-intel \
|
||||||
@@ -7388,9 +7391,118 @@ TOUCHCFG
|
|||||||
# Create empty xbindkeysrc to prevent errors
|
# Create empty xbindkeysrc to prevent errors
|
||||||
sudo -u "$KIOSK_USER" touch "$KIOSK_HOME/.xbindkeysrc"
|
sudo -u "$KIOSK_USER" touch "$KIOSK_HOME/.xbindkeysrc"
|
||||||
|
|
||||||
|
# Shared logic for mirroring any connected display beyond the primary at
|
||||||
|
# the primary's exact resolution (forcing a custom CVT mode if the
|
||||||
|
# external output doesn't natively list it). Called from both the
|
||||||
|
# Openbox autostart below (already running as kiosk user in the X
|
||||||
|
# session) and kiosk-hotplug.sh (root, via systemd/udev — wraps the call
|
||||||
|
# with sudo -u kiosk DISPLAY=:0 XAUTHORITY=...).
|
||||||
|
sudo tee /usr/local/bin/kiosk-mirror-display.sh > /dev/null <<'MIRRORSCRIPT'
|
||||||
|
#!/bin/bash
|
||||||
|
# Assumes it's run with DISPLAY/XAUTHORITY already set for the kiosk user's
|
||||||
|
# X session (either inherited, as from Openbox autostart, or exported by the
|
||||||
|
# caller). Mirrors every connected non-primary output at the primary's exact
|
||||||
|
# current resolution so kiosk content isn't cropped/letterboxed/blank on a
|
||||||
|
# TV/monitor with a different native resolution than the kiosk panel.
|
||||||
|
|
||||||
|
QUERY=$(xrandr --query 2>/dev/null)
|
||||||
|
[ -z "$QUERY" ] && exit 0
|
||||||
|
|
||||||
|
PRIMARY_OUTPUT=$(echo "$QUERY" | awk '/ primary/{print $1; exit}')
|
||||||
|
[ -z "$PRIMARY_OUTPUT" ] && exit 0
|
||||||
|
|
||||||
|
PRIMARY_RES=$(echo "$QUERY" | awk -v p="$PRIMARY_OUTPUT" '$1==p{for(i=1;i<=NF;i++) if ($i ~ /^[0-9]+x[0-9]+\+/){split($i,a,"+"); print a[1]; exit}}')
|
||||||
|
[ -z "$PRIMARY_RES" ] && exit 0
|
||||||
|
|
||||||
|
for OUT in $(echo "$QUERY" | awk '/ connected/{print $1}'); do
|
||||||
|
[ "$OUT" = "$PRIMARY_OUTPUT" ] && continue
|
||||||
|
|
||||||
|
HAS_NATIVE=$(echo "$QUERY" | awk -v out="$OUT" -v res="$PRIMARY_RES" '
|
||||||
|
$0 ~ "^"out" " {infound=1; next}
|
||||||
|
/^[^ \t]/ {infound=0}
|
||||||
|
infound && $1==res {print "yes"; exit}
|
||||||
|
')
|
||||||
|
|
||||||
|
if [ "$HAS_NATIVE" = "yes" ]; then
|
||||||
|
xrandr --output "$OUT" --mode "$PRIMARY_RES" --same-as "$PRIMARY_OUTPUT" 2>/dev/null \
|
||||||
|
&& logger "KIOSK: mirrored $OUT at native $PRIMARY_RES" \
|
||||||
|
|| logger "KIOSK: mirror of $OUT at $PRIMARY_RES failed"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# $OUT doesn't natively list the primary's resolution - force a matching mode
|
||||||
|
CVT_LINE=$(cvt "${PRIMARY_RES%x*}" "${PRIMARY_RES#*x}" 2>/dev/null | grep Modeline)
|
||||||
|
MODENAME=$(echo "$CVT_LINE" | sed -n 's/^Modeline "\([^"]*\)".*/\1/p')
|
||||||
|
TIMINGS=$(echo "$CVT_LINE" | sed -n 's/^Modeline "[^"]*" *//p')
|
||||||
|
|
||||||
|
if [ -z "$MODENAME" ] || [ -z "$TIMINGS" ]; then
|
||||||
|
logger "KIOSK: could not generate a $PRIMARY_RES mode for $OUT (cvt failed or missing)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
xrandr --newmode "$MODENAME" $TIMINGS 2>/dev/null
|
||||||
|
xrandr --addmode "$OUT" "$MODENAME" 2>/dev/null
|
||||||
|
xrandr --output "$OUT" --mode "$MODENAME" --same-as "$PRIMARY_OUTPUT" 2>/dev/null \
|
||||||
|
&& logger "KIOSK: mirrored $OUT at forced $PRIMARY_RES ($MODENAME)" \
|
||||||
|
|| logger "KIOSK: mirror of $OUT at forced $PRIMARY_RES failed"
|
||||||
|
done
|
||||||
|
MIRRORSCRIPT
|
||||||
|
sudo chmod +x /usr/local/bin/kiosk-mirror-display.sh
|
||||||
|
|
||||||
|
# Shared logic for routing audio to an HDMI audio sink whenever an
|
||||||
|
# external (non-primary) display is connected/mirrored, and back to the
|
||||||
|
# built-in sink when it isn't. Requires PipeWire/pipewire-pulse to
|
||||||
|
# already be running (pactl needs a live socket), so unlike
|
||||||
|
# kiosk-mirror-display.sh this is called later in autostart, after the
|
||||||
|
# "wait for PipeWire/ALSA" steps below — and from kiosk-hotplug.sh, where
|
||||||
|
# the system is already fully booted by the time it fires.
|
||||||
|
sudo tee /usr/local/bin/kiosk-audio-route.sh > /dev/null <<'AUDIOSCRIPT'
|
||||||
|
#!/bin/bash
|
||||||
|
# Assumes DISPLAY/XAUTHORITY are set (for xrandr) and pactl already has a
|
||||||
|
# working PipeWire/pulse socket for the invoking context.
|
||||||
|
|
||||||
|
QUERY=$(xrandr --query 2>/dev/null)
|
||||||
|
[ -z "$QUERY" ] && exit 0
|
||||||
|
|
||||||
|
PRIMARY_OUTPUT=$(echo "$QUERY" | awk '/ primary/{print $1; exit}')
|
||||||
|
[ -z "$PRIMARY_OUTPUT" ] && exit 0
|
||||||
|
|
||||||
|
EXTERNAL_CONNECTED=$(echo "$QUERY" | awk -v p="$PRIMARY_OUTPUT" '/ connected/ && $1!=p{f=1} END{print (f==1)?"yes":"no"}')
|
||||||
|
|
||||||
|
HDMI_SINK=$(pactl list sinks short 2>/dev/null | awk 'tolower($2) ~ /hdmi/{print $2; exit}')
|
||||||
|
NON_HDMI_SINK=$(pactl list sinks short 2>/dev/null | awk 'tolower($2) !~ /hdmi/{print $2; exit}')
|
||||||
|
|
||||||
|
route_to() {
|
||||||
|
local sink="$1" label="$2"
|
||||||
|
if [ -z "$sink" ]; then
|
||||||
|
logger "KIOSK: no $label audio sink found, leaving routing unchanged"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
pactl set-default-sink "$sink" 2>/dev/null \
|
||||||
|
&& logger "KIOSK: audio routed to $label sink ($sink)" \
|
||||||
|
|| logger "KIOSK: failed to route audio to $label sink ($sink)"
|
||||||
|
pactl list sink-inputs short 2>/dev/null | awk '{print $1}' | while read -r sid; do
|
||||||
|
pactl move-sink-input "$sid" "$sink" 2>/dev/null
|
||||||
|
done
|
||||||
|
pactl set-sink-volume "$sink" 100% 2>/dev/null
|
||||||
|
pactl set-sink-mute "$sink" 0 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$EXTERNAL_CONNECTED" = "yes" ]; then
|
||||||
|
route_to "$HDMI_SINK" "HDMI"
|
||||||
|
else
|
||||||
|
route_to "$NON_HDMI_SINK" "built-in"
|
||||||
|
fi
|
||||||
|
AUDIOSCRIPT
|
||||||
|
sudo chmod +x /usr/local/bin/kiosk-audio-route.sh
|
||||||
|
|
||||||
sudo -u "$KIOSK_USER" tee "$KIOSK_HOME/.config/openbox/autostart" > /dev/null <<'AUTOSTART'
|
sudo -u "$KIOSK_USER" tee "$KIOSK_HOME/.config/openbox/autostart" > /dev/null <<'AUTOSTART'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Mirror any connected external display (e.g. HDMI-out to a monitor/TV) onto
|
||||||
|
# the primary display, forcing it to the primary's exact resolution.
|
||||||
|
/usr/local/bin/kiosk-mirror-display.sh
|
||||||
|
|
||||||
# AGGRESSIVE DPMS disable - multiple methods
|
# AGGRESSIVE DPMS disable - multiple methods
|
||||||
xset s off
|
xset s off
|
||||||
xset s noblank
|
xset s noblank
|
||||||
@@ -7460,6 +7572,9 @@ for i in {1..10}; do
|
|||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Route audio to HDMI if an external display is connected/mirrored, else built-in
|
||||||
|
/usr/local/bin/kiosk-audio-route.sh
|
||||||
|
|
||||||
# Set audio levels (speakers 100%, mic 100%, mic unmuted)
|
# Set audio levels (speakers 100%, mic 100%, mic unmuted)
|
||||||
pactl set-sink-volume @DEFAULT_SINK@ 100%
|
pactl set-sink-volume @DEFAULT_SINK@ 100%
|
||||||
pactl set-source-volume @DEFAULT_SOURCE@ 100%
|
pactl set-source-volume @DEFAULT_SOURCE@ 100%
|
||||||
@@ -7528,6 +7643,40 @@ sleep 2
|
|||||||
AUTOSTART
|
AUTOSTART
|
||||||
sudo chmod 750 "$KIOSK_HOME/.config/openbox/autostart"
|
sudo chmod 750 "$KIOSK_HOME/.config/openbox/autostart"
|
||||||
|
|
||||||
|
# HDMI/display hotplug: re-mirror any newly connected external display
|
||||||
|
# without waiting for the next login. Triggered by udev on DRM "change"
|
||||||
|
# events (monitor plugged/unplugged), which starts a oneshot systemd
|
||||||
|
# service that re-runs the same kiosk-mirror-display.sh logic used at
|
||||||
|
# Openbox autostart, as root, so it wraps the call with sudo -u kiosk.
|
||||||
|
sudo tee /usr/local/bin/kiosk-hotplug.sh > /dev/null <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# Give X a moment to finish enumerating the output after the hotplug event
|
||||||
|
sleep 2
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority /usr/local/bin/kiosk-mirror-display.sh
|
||||||
|
|
||||||
|
kiosk_uid=$(id -u kiosk)
|
||||||
|
sudo -u kiosk DISPLAY=:0 XAUTHORITY=/home/kiosk/.Xauthority XDG_RUNTIME_DIR="/run/user/${kiosk_uid}" /usr/local/bin/kiosk-audio-route.sh
|
||||||
|
EOF
|
||||||
|
sudo chmod +x /usr/local/bin/kiosk-hotplug.sh
|
||||||
|
|
||||||
|
sudo tee /etc/systemd/system/kiosk-hotplug.service > /dev/null <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Kiosk Display Hotplug Handler
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/kiosk-hotplug.sh
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo tee /etc/udev/rules.d/99-kiosk-hotplug.rules > /dev/null <<'EOF'
|
||||||
|
SUBSYSTEM=="drm", ACTION=="change", TAG+="systemd", ENV{SYSTEMD_WANTS}="kiosk-hotplug.service"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
|
||||||
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
|
if lspci | grep -i "VGA.*Intel" >/dev/null 2>&1; then
|
||||||
sudo mkdir -p /etc/X11/xorg.conf.d/
|
sudo mkdir -p /etc/X11/xorg.conf.d/
|
||||||
sudo tee /etc/X11/xorg.conf.d/20-intel.conf > /dev/null <<'EOF'
|
sudo tee /etc/X11/xorg.conf.d/20-intel.conf > /dev/null <<'EOF'
|
||||||
|
|||||||
Reference in New Issue
Block a user