• Legacy (non-SGR) mouse reports: wrong click coordinates, truncated pas

    From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Fri Oct 30 14:26:32 2026
    open https://gitlab.synchro.net/main/sbbs/-/work_items/1313

    Mouse reports in the legacy (non-SGR) encoding, `ESC [ M Cb Cx Cy`, are decoded incorrectly by `ANSI_Terminal::handle_non_SGR_mouse_sequence()` (`src/sbbs3/ansi_terminal.cpp`). Synchronet requests SGR-encoded reports (`ESC[?1006h`), so this path is only taken with terminals that support mouse click reporting but ignore 1006. SyncTERM and modern xterm always send SGR reports and are not affected.

    Both problems are regressions from the Terminal class refactor, 374282bf81 (skins-28-shop, 2025-03-30). The SGR path broke in the same refactor and was fixed under #900.

    ### 1. Click coordinates are computed from the wrong variable

    The X and Y bytes are read into `inch`, but the coordinates (and the `< '!'` sanity check on Y) still use `ch`, which holds ESC at that point:

    ```cpp
    int inch = sbbs->kbincom(100); // X byte
    ...
    int x = ch - '!'; // should be inch
    inch = sbbs->kbincom(100); // Y byte
    if (ch < '!') { // should be inch
    ...
    int y = ch - '!'; // should be inch
    ```

    The pre-refactor code in `inkey()` read each byte back into `ch`, so `x = ch - '!'` was correct there. Now every click decodes as x = y = 0x1B - 0x21 = -6, which `handle_left_press()` receives as a huge unsigned value. As a result:

    - No mouse hotspot ever matches: clicking menu items or lightbar entries does nothing.
    - Clicking the pause prompt's line no longer continues (`y == rows - 1` never matches).
    - The debug log reports bogus coordinates, and the two `< '!'` log messages print `ch` where they mean the received byte.

    Right-click (abort), the scroll wheel and button release still work, since they only depend on the button byte.

    ### 2. Passed-through reports lose their button and coordinate bytes

    With `CON_MOUSE_CLK_PASSTHRU` / `CON_MOUSE_REL_PASSTHRU` set, the report should be handed to the JS module intact. `stuff_unhandled()` re-queues `ansi.ansi_sequence`, but that holds only `ESC [ M`: the three report bytes were read separately with `kbincom()` and never appended to it. The pre-refactor code re-queued all six bytes. Now a module that decodes reports itself receives `ESC[M` and then takes the user's next three keystrokes as the button and coordinates. That affects `lbshell.js` (which enables `MOUSE_MODE_X10 | MOUSE_MODE_EXT`) and the shared `exec/load/mouse_getkey.js` decoder used by `lightbar.js`, `dd_lightbar_menu.js`, `uselect_tree.js` and others.

    ### Fix

    - Compute `x`/`y` from `inch` and sanity-check/log the received bytes.
    - Append the button, X and Y bytes to `ansi.ansi_sequence` as they are read, so pass-through re-queues the complete report.

    *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.38-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)