# 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" }