Added support for cthulhu's window reader plugin.

This commit is contained in:
Storm Dragon
2026-01-12 11:52:07 -05:00
parent 876d787e0a
commit 0c8a749240

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
# shellcheck disable=SC1091
# Get script directory for relative paths
scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -11,6 +12,136 @@ export DIALOGOPTS='--no-lines --visit-items'
# Wine32 version for SAPI compatibility
wineThirtyTwoVersion="9.0"
# Track nvda2speechd lifecycle for this launcher run.
nvda2speechdPid=""
nvda2speechdStarted="false"
customLaunchHandled="false"
cthulhuTitleReaderEnabled="false"
cthulhuTitleReaderTried="false"
log_msg() {
local logFile="${scriptDir}/game.log"
local timestamp=""
timestamp="$(date)"
echo "${1} [${timestamp}]" >> "$logFile"
}
start_nvda2speechd() {
if [[ "$nvda2speechdStarted" == "true" ]]; then
return
fi
if ! ss -ltnp | rg 3457 | grep -q 'cthulhu'; then
if [[ -x "${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd" ]]; then
local translateSetting="${TRANSLATE:-unset}"
local translateFromSetting="${TRANSLATE_FROM:-unset}"
local translateToSetting="${TRANSLATE_TO:-unset}"
log_msg "Preparing nvda2speechd with TRANSLATE=${translateSetting} TRANSLATE_FROM=${translateFromSetting} TRANSLATE_TO=${translateToSetting}."
if [[ "${translateSetting,,}" == "true" ]] || [[ "$translateSetting" == "1" ]]; then
if ! command -v trans &> /dev/null; then
log_msg "TRANSLATE is enabled but 'trans' is missing; nvda2speechd may fail to start."
fi
fi
"${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd" &> /dev/null &
nvda2speechdPid=$!
nvda2speechdStarted="true"
log_msg "Started nvda2speechd (pid ${nvda2speechdPid})."
else
log_msg "nvda2speechd binary not found or not executable; skipping start."
fi
else
log_msg "cthulhu is already listening on port 3457; skipping nvda2speechd start."
fi
}
stop_nvda2speechd() {
if [[ "$nvda2speechdStarted" != "true" ]]; then
return
fi
if [[ -n "$nvda2speechdPid" ]] && kill -0 "$nvda2speechdPid" 2>/dev/null; then
kill "$nvda2speechdPid" 2>/dev/null
wait "$nvda2speechdPid" 2>/dev/null
fi
nvda2speechdPid=""
nvda2speechdStarted="false"
}
enable_cthulhu_window_title_reader() {
if [[ "$cthulhuTitleReaderEnabled" == "true" ]]; then
return 0
fi
if [[ "$cthulhuTitleReaderTried" == "true" ]]; then
return 1
fi
cthulhuTitleReaderTried="true"
if ! command -v gdbus &> /dev/null; then
log_msg "gdbus not found; cannot enable Cthulhu WindowTitleReader."
return 1
fi
local dbusService="org.stormux.Cthulhu.Service"
local modulePath="/org/stormux/Cthulhu/Service/PluginSystemManager"
local titleModulePath="/org/stormux/Cthulhu/Service/Plugin_WindowTitleReader"
local moduleInterface="org.stormux.Cthulhu.Module"
local enableResult=""
local titleEnableResult=""
gdbus call --session --dest "$dbusService" \
--object-path "$modulePath" \
--method "${moduleInterface}.ExecuteCommand" \
"RescanPlugins" false &> /dev/null || true
enableResult="$(gdbus call --session --dest "$dbusService" \
--object-path "$modulePath" \
--method "${moduleInterface}.ExecuteParameterizedCommand" \
"SetPluginActive" \
'{"plugin_name": <"WindowTitleReader">, "active": <true>}' \
false 2>/dev/null || true)"
if [[ "$enableResult" != *"true"* ]]; then
log_msg "Failed to activate Cthulhu WindowTitleReader plugin via D-Bus."
return 1
fi
titleEnableResult="$(gdbus call --session --dest "$dbusService" \
--object-path "$titleModulePath" \
--method "${moduleInterface}.ExecuteParameterizedCommand" \
"SetEnabled" \
'{"enabled": <true>}' \
false 2>/dev/null || true)"
if [[ "$titleEnableResult" == *"true"* ]]; then
cthulhuTitleReaderEnabled="true"
log_msg "Enabled Cthulhu WindowTitleReader tracking via D-Bus."
return 0
fi
log_msg "Failed to enable Cthulhu WindowTitleReader tracking via D-Bus."
return 1
}
kill_nvda2speechd_listener() {
local nvdaPids=()
mapfile -t nvdaPids < <(pgrep -u "${USER}" -x nvda2speechd 2>/dev/null)
if [[ ${#nvdaPids[@]} -eq 0 ]]; then
log_msg "No nvda2speechd process found to stop."
return
fi
log_msg "Stopping nvda2speechd process(es): ${nvdaPids[*]}."
for pid in "${nvdaPids[@]}"; do
kill "$pid" 2>/dev/null
done
local remainingPids=()
mapfile -t remainingPids < <(pgrep -u "${USER}" -x nvda2speechd 2>/dev/null)
if [[ ${#remainingPids[@]} -gt 0 ]]; then
log_msg "nvda2speechd still running after stop attempt: ${remainingPids[*]}."
fi
}
cleanup_and_exit() {
stop_nvda2speechd
}
# Check and manage wine32 installation
check_wine32() {
local wine32Dir="${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/wine32"
@@ -316,27 +447,33 @@ kill_game() {
# for games that require custom scripts before launch or custom launch parameters
custom_launch_parameters() {
if [[ "${game[2]}" == "Dragon Pong" ]]; then
"${scriptDir}/speech/speak_window_title.sh" DragonPong.exe &
if ! enable_cthulhu_window_title_reader; then
"${scriptDir}/speech/speak_window_title.sh" DragonPong.exe &
fi
start_nvda2speechd
pushd "$(winepath "$winePath")" || exit 1
wine "$wineExec"
popd || exit 1
exit 0
customLaunchHandled="true"
return 0
fi
if [[ "${game[2]}" == "Dreamland" ]]; then
"$WINE" "${game[1]}" &> /dev/null &
exit 0
start_nvda2speechd
"$WINE" "${game[1]}" &> /dev/null
customLaunchHandled="true"
return 0
fi
# executioner's-rage: DLL replacement now handled by update_nvda_dlls()
if [[ "${game[2]}" == "Laser Breakout" ]]; then
"${scriptDir}/speech/speak_window_title.sh" play.exe &
if ! enable_cthulhu_window_title_reader; then
"${scriptDir}/speech/speak_window_title.sh" play.exe &
fi
fi
if [[ "${game[2]}" == "Bokurano Daibouken 2" ]]; then
find "${WINEPREFIX}/drive_c/nyanchangame/bk2" -type f -name 'nvdaControllerClient.dll' -exec rm -v "{}" \;
"${scriptDir}/speech/clipboard_translator.sh" "play.exe" bokurano-daibouken2 &
export TRANSLATE=true
fi
if [[ "${game[2]}" == "Bokurano Daibouken" ]]; then
find "${WINEPREFIX}/drive_c/nyanchangame/bk" -type f -name 'nvdaControllerClient.dll' -exec rm -v "{}" \;
"${scriptDir}/speech/clipboard_translator.sh" "play.exe" bokurano-daibouken &
export TRANSLATE=true
fi
if [[ "${game[2]}" == "Bokurano Daibouken 3" ]]; then
dictPath="$(winepath "${winePath}")"
@@ -358,13 +495,19 @@ custom_launch_parameters() {
fi
fi
if [[ "${game[2]}" == "Bop It Emulator" ]]; then
"${scriptDir}/speech/speak_window_title.sh" bop.exe &
if ! enable_cthulhu_window_title_reader; then
"${scriptDir}/speech/speak_window_title.sh" bop.exe &
fi
fi
if [[ "${game[2]}" == "Road to Rage" ]]; then
"${scriptDir}/speech/speak_window_title.sh" trtr.exe &
if ! enable_cthulhu_window_title_reader; then
"${scriptDir}/speech/speak_window_title.sh" trtr.exe &
fi
fi
if [[ "${game[2]}" == "Axel Pong" ]]; then
"${scriptDir}/speech/speak_window_title.sh" axel_pong.exe &
if ! enable_cthulhu_window_title_reader; then
"${scriptDir}/speech/speak_window_title.sh" axel_pong.exe &
fi
fi
if [[ "${game[2]}" == "Sequence Storm" ]]; then
"${scriptDir}/speech/clipboard_reader.sh" SequenceStorm &
@@ -375,30 +518,40 @@ custom_launch_parameters() {
#fi
# sketchbook: DLL replacement now handled by update_nvda_dlls()
if [[ "${game[2]}" == "Audiodisc" ]]; then
start_nvda2speechd
wine "$winePath\\$wineExec"
exit 0
customLaunchHandled="true"
return 0
fi
if [[ "${game[2]}" == "Audioquake" ]]; then
start_nvda2speechd
wine "$winePath\\$wineExec"
exit 0
customLaunchHandled="true"
return 0
fi
if [[ "${game[2]}" == "Screaming Strike 2" ]]; then
start_nvda2speechd
pushd "$(winepath "$winePath")" || exit 1
wine "$wineExec"
popd || exit 1
exit 0
customLaunchHandled="true"
return 0
fi
if [[ "${game[2]}" == "Warsim" ]]; then
start_nvda2speechd
pushd "$(winepath "${game[1]%\\*}")" || exit 1
wine "${game[1]##*\\}"
popd || exit 1
exit 0
customLaunchHandled="true"
return 0
fi
if [[ "${game[2]}" == "Interceptor" ]]; then
start_nvda2speechd
pushd "$(winepath "$winePath")" || exit 1
wine "$wineExec"
popd || exit 1
exit 0
customLaunchHandled="true"
return 0
fi
}
@@ -474,14 +627,8 @@ game_launcher() {
[[ "$agmNoLaunch" == "true" ]] && return
# shellcheck source=.includes/bottle.sh
source "${scriptDir}/.includes/bottle.sh"
# Start nvda2speechd if available
if ! ss -ltnp | rg 3457 | grep -q 'cthulhu'; then
if [[ -x "${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd" ]]; then
"${XDG_DATA_HOME:-$HOME/.local/share}/audiogame-manager/nvda2speechd" &> /dev/null &
fi
fi
# Ensure a clean nvda2speechd state before launching a new game.
kill_nvda2speechd_listener
# Replace NVDA controller client DLLs in wine64 bottle
update_nvda_dlls
mapfile -t lines < <(sed -e '/^$/d' -e '/^ *#/d' "${configFile}" 2> /dev/null | sort -t '|' -k3,3f)
@@ -568,15 +715,22 @@ game_launcher() {
fi
fi
process_launcher_flags
customLaunchHandled="false"
custom_launch_parameters
if [[ "$debugGdb" == "1" ]]; then
# Change to game directory before launching
pushd "$(winepath "${game[1]%\\*}")" > /dev/null || exit 1
winedbg --gdb "${game[1]##*\\}"
popd > /dev/null || exit 1
else
wine start /d "${game[1]%\\*}" "${game[1]##*\\}" /realtime
if [[ "$customLaunchHandled" == "true" ]]; then
exit 0
fi
start_nvda2speechd
# Change to game directory before launching (required for proper game operation)
pushd "$(winepath "${game[1]%\\*}")" > /dev/null || exit 1
if [[ "$debugGdb" == "1" ]]; then
winedbg --gdb "${game[1]##*\\}"
else
# Use direct wine execution instead of 'wine start' to ensure clipboard works
# See: https://bugs.winehq.org/show_bug.cgi?id=50598
wine "${game[1]##*\\}"
fi
popd > /dev/null || exit 1
fi
exit 0
}
@@ -584,10 +738,12 @@ game_launcher() {
# main script
trap "exit 0" SIGINT
trap cleanup_and_exit EXIT
trap "cleanup_and_exit; exit 0" SIGINT SIGTERM
# Detect dialog interface type BEFORE potentially setting DISPLAY
# This must happen before we modify DISPLAY to preserve console detection
# shellcheck disable=SC2034
if [[ -z "$DISPLAY" ]]; then
dialogType="dialog"
elif command -v yad &> /dev/null; then