• src/doors/termgfx/termgfx_termio.c src/doors/termgfx/test/test_termgfx

    From Rob Swindell (on Windows 11)@1:103/705 to Git commit to main/sbbs/master on Thu Jul 23 02:11:47 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/176d3044c585aaf120e777ab
    Modified Files:
    src/doors/termgfx/termgfx_termio.c src/doors/termgfx/test/test_termgfx_termio_input.c test_termgfx_termio_input_evdev.c
    Log Message:
    termgfx: fix Escape and Enter going nowhere on SyncTERM

    Three defects in the keyboard decode, all reachable from any door that
    binds Escape or Enter (EasyRPG/RPG Maker's Cancel and Confirm, 1oom's back-out). Found playing SyncRPG's Yume Nikki over SyncTERM, where the
    arrows and letter keys worked and those two did nothing whatsoever.

    1. evdev (SyncTERM's physical-key reports) delivered Escape and Enter
    as bare ASCII 27 and 13. termgfx_evdev_edge()'s switch maps the
    arrows, nav keys, F-keys and KP5 to TERMGFX_KEY_*, but has no case
    for Escape or Enter, so both fell through to the generic tail --
    termgfx_key_event(c, c, 0, down) -- carrying whatever
    termgfx_evdev_ascii() returned. Those values sit BELOW
    TERMGFX_KEY_FIRST, so a door routes them into its printable-ASCII
    fallback, where they match nothing and are silently dropped. The
    legacy byte and kitty CSI-u paths both translate these keys before
    reporting them; only evdev did not. Now normalized there too, for
    Escape, Enter (keypad Enter, code 96, included), Backspace and Tab.

    2. A LONE Escape never fired on the legacy byte path. ESC introduces
    every CSI/APC sequence, so parse_bytes() parks in P_ESC and waits
    for the next byte to decide -- right for a sequence, whose remaining
    bytes are already in flight, but a bare Escape has no next byte. The
    press only surfaced later, bundled with whatever was pressed after
    it. Added a 50ms timer, checked once per pump: long enough to
    outlast a segment split (a terminal writes ESC and the rest of a
    sequence in one write), short enough not to feel laggy.

    3. LF decoded as Ctrl+J rather than Enter. termgfx_key_byte() claimed
    CR, BS and TAB but let 0x0a fall into the Ctrl+letter branch as 'j'
    -- which a game binding HJKL movement (EasyRPG's default table:
    J = DOWN) reads as a step downward. A client whose Enter sends LF
    therefore either did nothing or walked the player. CR and LF are
    both Enter now, with a CR latch so CRLF stays ONE Enter, not two.

    All three date to 42f2aba29d7 (unless-13-specs), the keyboard decode as
    first written in syncscumm's sst_io.c; the evdev key table itself
    arrived in e07e8480928 (blame-4-multi). This is shared code, so
    syncdoom, syncduke, syncmoo1, syncretro and syncscumm all pick the
    fixes up on their next rebuild -- syncmoo1 notably, since 1oom uses
    Escape to back out of a screen.

    Tests cover all three: LF and CRLF, the ESC timer plus two negative
    cases proving it never shreds a real or a late-arriving sequence, and
    the four evdev control keys press-and-release. The ESC test back-dates
    the timer through a new TERMGFX_TEST seam instead of sleeping, so it is deterministic. Verified live on SyncTERM against the Win32/MSVC build;
    the unit tests are UNRUN -- unit_termgfx_termio.sh needs a cc this box
    lacks -- so they want a Unix build before this is trusted.

    Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)