The International Simutrans Forum

Development => Bug Reports => Topic started by: victor_18993 on August 11, 2026, 06:30:16 AM

Title: [Patch] SDL2: refresh modifier state on key release
Post by: victor_18993 on August 11, 2026, 06:30:16 AM
While testing the contextual construction UI patch, I found a small pre-existing issue in the SDL2 input backend.

When Ctrl or Shift is released, SDL_KEYUP generates an event, but Simutrans does not refresh sys_event.key_mod for that event.

Because key_mod is kept between events and fill_event() copies it into control_shift_state for every event, releasing a modifier can effectively republish the previous state.

The visible result is simple:

1. Hold Ctrl.
2. Release Ctrl.
3. Do not move the mouse.

Simutrans can still report Ctrl as pressed until another event, such as mouse movement, refreshes the modifier state.

This is not specific to the new UX work. Tools that read event_get_last_control_shift() see the same stale value.

The fix is one functional line in the SDL_KEYUP handler:

sys_event.key_mod = ModifierKeys();

This is the same modifier-state query already used by the other SDL event paths.

I also checked that SDL_GetModState() already reflects the released key by the time SDL_KEYUP is received. This was tested using real OS keyboard input through SDL rather than only synthetic internal state.

Test results:

Baseline:
14/24 modifier checks pass.
10/24 fail, and all 10 failures are key-release cases.

With the patch:
24/24 pass.

Covered cases include:

- Ctrl press/release;
- Shift press/release;
- Ctrl+Shift, releasing Ctrl first;
- Shift+Ctrl, releasing Shift first;
- auto-repeat;
- modifier release during dragging;
- release without any mouse movement;
- normal key while Ctrl remains held.

Negative control:
- remove the line -> the same 10 failures return;
- restore it -> 24/24 pass again.

Full regression suite:

SDL2:
238/238 before
238/238 after

headless:
238/238 before
238/238 after

Compiler warnings:
no new warnings.

Diff:
1 file
4 inserted lines
1 functional line

I have deliberately not touched the Windows/GDI backend.

GDI has a related symptom, but not the same cause: it currently does not generate a corresponding WM_KEYUP event through this path. Fixing that would require changing event behaviour and is outside the scope of this patch.

The patch only refreshes an existing field in an SDL_KEYUP event that already exists; it adds no new event type, state or polling.

Patch attached.