# 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 (F11), so no Ctrl reaches the # program. The mapper replaces every DOSBox binding: only these keys and # Escape reach the machine. Source after joyGate.sh. # # dosboxJoyMapper FILE write the mapper file # dosboxJoyTap NAME press and let go of a key of the table # (escape, shot) # 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). DOSBOX_JOY_DISPLAY="" DOSBOX_JOY_WINDOW="" DOSBOX_JOY_SHOTS="" DOSBOX_JOY_SHOT_SECONDS=5 # the screenshot key until DOSBox has written the file DOSBOX_JOY_TAP_SECONDS=0.3 # 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" "shot F11 68 hand_rawshot" "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 key local code local event for entry in "${DOSBOX_JOY_KEYS[@]}"; do read -r _ key code event <<< "$entry" printf '%s "key %s"\n' "$event" "$code" done > "$1" } 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 "$@" } # DOSBox makes the file before it writes it: it is done when it has bytes # and one more poll adds none. joyShot() { local before local found local size="" local deadline before=$(find "$DOSBOX_JOY_SHOTS" -name '*.png' | wc -l) dosboxJoyTap shot deadline=$((SECONDS + DOSBOX_JOY_SHOT_SECONDS)) while [ "$SECONDS" -lt "$deadline" ]; do sleep 0.2 [ "$(find "$DOSBOX_JOY_SHOTS" -name '*.png' | wc -l)" -gt "$before" ] || continue found=$(ls -t "$DOSBOX_JOY_SHOTS"/*.png | head -1) [ -s "$found" ] || continue if [ "$(stat -c %s "$found")" = "$size" ]; then mv "$found" "$1" return 0 fi size=$(stat -c %s "$found") done return 1 }