joeylib2/scripts/lib/dosboxJoy.sh

128 lines
4.4 KiB
Bash

# shellcheck shell=bash
# Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
# See LICENSE.md for license information.
# SPDX-License-Identifier: MIT
#
# Shared by the joystick gates that run in DOSBox Staging (DOS, DVX,
# Win16): how a stick is moved and how JOY is photographed there. DOSBox's
# joysticktype 4axis puts four axes and four buttons on the game port with
# no host joystick, which a two-stick reader takes as sticks A (axes 0-1,
# buttons 0-1) and B (axes 2-3, buttons 2-3), as a Y cable gives them. A
# mapper file binds a host key to each line and xdotool holds the keys; the
# raw screenshot is on a key of its own (scripts/lib/dosboxKeys.sh), so no
# Ctrl reaches the program. The mapper replaces every DOSBox binding: only
# these keys and Escape reach the machine. Source after joyGate.sh.
#
# DOSBOX_JOY_SETTINGS [joystick] settings every run needs
# ("name=value"); DOSBOX_JOY_SET_ARGS has them
# as DOSBox --set arguments
# dosboxJoyMapper FILE write the mapper file
# dosboxJoyTap NAME press and let go of a key of the table
# (escape)
# joyPress / joyRelease joyGate.sh's: hold the controls' keys
# joyShot PNG joyGate.sh's: the raw screenshot as PNG
#
# The gate sets DOSBOX_JOY_DISPLAY and DOSBOX_JOY_WINDOW (DOSBox's X
# display and window) and DOSBOX_JOY_SHOTS (its capture_dir).
source "$JOEY_REPO/scripts/lib/dosboxKeys.sh"
DOSBOX_JOY_DISPLAY=""
DOSBOX_JOY_WINDOW=""
DOSBOX_JOY_SHOTS=""
DOSBOX_JOY_TAP_SECONDS=0.3
# DOSBox Staging 0.83's 4axis sticks wrap buttons at two when no host
# joystick is open: CStickBindGroup sets the wrap to its two buttons, and
# C4AxisBindGroup raises the count to four but copies it to the wrap only
# with buttonwrap on, so stick B's buttons would press stick A's. buttonwrap
# on wraps at four. A host pad DOSBox opened set the wrap to its own button
# count and hid this, and would add its own axes and buttons, so every host
# pad is hidden from DOSBox's SDL (an id no device has is the only one let
# through) and the runs are the same whatever is plugged in.
DOSBOX_JOY_SETTINGS=("buttonwrap=on")
DOSBOX_JOY_SET_ARGS=()
for setting in "${DOSBOX_JOY_SETTINGS[@]}"; do
DOSBOX_JOY_SET_ARGS+=(--set "$setting")
done
unset setting
export SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT=0x0000/0x0000
# Control or name, its host key (xdotool's name), the key's SDL scancode and
# the DOSBox mapper event it drives.
DOSBOX_JOY_KEYS=(
"A-left j 13 jaxis_0_0-" "A-right l 15 jaxis_0_0+"
"A-up i 12 jaxis_0_1-" "A-down k 14 jaxis_0_1+"
"A-button0 a 4 jbutton_0_0" "A-button1 s 22 jbutton_0_1"
"B-left f 9 jaxis_0_2-" "B-right h 11 jaxis_0_2+"
"B-up t 23 jaxis_0_3-" "B-down g 10 jaxis_0_3+"
"B-button0 q 20 jbutton_0_2" "B-button1 w 26 jbutton_0_3"
"escape Escape 41 key_esc"
)
# dosboxJoyKey NAME -- the host key for a control or name of the table.
dosboxJoyKey() {
local entry
local name
local key
for entry in "${DOSBOX_JOY_KEYS[@]}"; do
read -r name key _ <<< "$entry"
if [ "$name" = "$1" ]; then
printf '%s\n' "$key"
return 0
fi
done
return 1
}
dosboxJoyMapper() {
local entry
local code
local event
local entries=()
for entry in "${DOSBOX_JOY_KEYS[@]}"; do
read -r _ _ code event <<< "$entry"
entries+=("$code $event")
done
dosboxKeysMapper "$1" "${entries[@]}"
}
dosboxJoyTap() {
local key
key=$(dosboxJoyKey "$1") || return 1
DISPLAY="$DOSBOX_JOY_DISPLAY" xdotool keydown --window "$DOSBOX_JOY_WINDOW" "$key"
sleep "$DOSBOX_JOY_TAP_SECONDS"
# A key that ends the program (escape) can take DOSBox's window with it.
DISPLAY="$DOSBOX_JOY_DISPLAY" xdotool keyup --window "$DOSBOX_JOY_WINDOW" "$key" 2> /dev/null || true
}
# dosboxJoyHold keydown|keyup CONTROL...
dosboxJoyHold() {
local action="$1"
local control
local key
shift
for control in "$@"; do
key=$(dosboxJoyKey "$control") || { joyFail "no key for $control"; continue; }
DISPLAY="$DOSBOX_JOY_DISPLAY" xdotool "$action" --window "$DOSBOX_JOY_WINDOW" "$key"
done
}
joyPress() {
dosboxJoyHold keydown "$@"
}
joyRelease() {
dosboxJoyHold keyup "$@"
}
joyShot() {
dosboxShot "$DOSBOX_JOY_DISPLAY" "$DOSBOX_JOY_WINDOW" "$DOSBOX_JOY_SHOTS" "$1"
}