| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- #!/usr/bin/env bash
- # Fix 5 (Wayland only): let the game window receive keyboard focus.
- #
- # On KDE Plasma Wayland (via Xwayland) the game's top window advertises the ICCCM
- # "Globally Active" input model (WM_HINTS input=False + WM_TAKE_FOCUS), so the
- # compositor never hands it Wayland keyboard focus; mouse works (position-based)
- # but the keyboard does not. Setting Wine's X11 driver to not use take-focus makes
- # the window advertise the passive model (input=True) and the compositor grants
- # keyboard focus.
- #
- # HKCU\Software\Wine\X11 Driver -> "UseTakeFocus"="N"
- #
- # Harmless on native X11 sessions. Must be applied with the prefix's wineserver
- # stopped so it sticks. This edits the Proton prefix's user.reg directly (no wine
- # tooling needed). Backup written as user.reg.bak-<timestamp>.
- set -euo pipefail
- GAME_ROOT="${1:?usage: 05-wayland-keyboard.sh <game-root-dir>}"
- APPID=2326780
- PFX="$GAME_ROOT/../../compatdata/$APPID/pfx"
- REG="$PFX/user.reg"
- [ -f "$REG" ] || { echo "!! prefix not found: $REG (launch the game once so Proton creates it)"; exit 1; }
- if grep -qa 'UseTakeFocus"="N"' "$REG"; then
- echo "== Fix 5: already applied (UseTakeFocus=N)"; exit 0
- fi
- # stop only this prefix's wineserver, matched via WINEPREFIX in its
- # environment, so the value sticks; other prefixes are left alone
- kill_prefix_wineserver() { # <pfx-dir>
- local pfx pid env_pfx
- pfx="$(cd "$1" 2>/dev/null && pwd)" || return 0
- for pid in $(pgrep -x wineserver 2>/dev/null || true); do
- env_pfx="$(tr '\0' '\n' < "/proc/$pid/environ" 2>/dev/null \
- | sed -n 's/^WINEPREFIX=//p' | head -1 || true)"
- if [ -n "$env_pfx" ] && [ "${env_pfx%/}" = "$pfx" ]; then
- kill -9 "$pid" 2>/dev/null || true
- fi
- done
- }
- kill_prefix_wineserver "$PFX"
- cp "$REG" "$REG.bak-$(date +%s)"
- python3 - "$REG" <<'PY'
- import sys, time
- path = sys.argv[1]
- sec = r'[Software\\Wine\\X11 Driver]' # literal text in user.reg (backslashes doubled)
- key = '"UseTakeFocus"="N"\n'
- def is_global_x11_header(line):
- # the global section only, not AppDefaults\...\X11 Driver; Wine may append
- # a modification time after the bracket
- s = line.strip()
- return s == sec or s.startswith(sec + ' ')
- with open(path, 'r', encoding='utf-8', errors='surrogateescape') as f:
- lines = f.readlines()
- out, i, done = [], 0, False
- while i < len(lines):
- line = lines[i]
- if not done and is_global_x11_header(line):
- out.append(line); i += 1
- if i < len(lines) and lines[i].startswith('#time='): # keep the timestamp line
- out.append(lines[i]); i += 1
- out.append(key)
- while i < len(lines) and not lines[i].lstrip().startswith('['):
- if not lines[i].strip().startswith('"UseTakeFocus"'): # drop any stale copy
- out.append(lines[i])
- i += 1
- done = True
- continue
- out.append(line); i += 1
- if not done: # section absent: append it
- now = int(time.time())
- filetime = (now + 11644473600) * 10000000 # Wine #time= is a hex FILETIME
- out.append('\n' + sec + ' %d\n' % now)
- out.append('#time=%x\n' % filetime)
- out.append(key)
- with open(path, 'w', encoding='utf-8', errors='surrogateescape') as f:
- f.writelines(out)
- print("wrote UseTakeFocus=N")
- PY
- echo "== Fix 5: applied (Wayland keyboard focus). Relaunch the game."
|