Repository navigation
Keyboard: don't auto-toggle CODE/KANA lock while that key is held down - #2158
Merged
Merged
Conversation
On a machine where CODE/KANA locks, pressUnicodeByUser() can auto-toggle the lock by flipping 'locksOn' and pressing the CODE key in the matrix. But pressKeyMatrixEvent() is a no-op when the key is already down, so when the user is physically holding the host CODE/KANA key (by default right-Alt, which on many host layouts is AltGr and must be held to type '@', '#', ...) the MSX never sees a new key-press edge and never toggles its lock, while openMSX did flip 'locksOn'. From that moment on the two are inverted and stay inverted: tapping the host key appears to switch the lock off, but the next ordinary keystroke auto-toggles it straight back on, and there is no way to get out of it short of restarting openMSX. A reset does not help, since 'locksOn' is not reset while the MSX does clear its own state. Only take the auto-toggle path when the CODE key is currently released, so that the press really produces an edge for the MSX. When the user is holding the key, just type the character with CODE/KANA held, like a real MSX does. Extract the "already pressed" test from pressKeyMatrixEvent() into isKeyMatrixPressed() so both places share it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses the stuck CODE/KANA lock reported in #1331. That ticket bundles
several distinct problems that happen to share the same trigger; this PR fixes
the one that makes the lock impossible to switch off again, which is what
@Colpocorto describes there. See "Not covered here" at the bottom for the parts
it deliberately does not touch, so please don't auto-close the issue on merge.
On a machine where CODE/KANA locks (e.g. a Japanese MSX), the lock can get
permanently out of sync with what openMSX thinks it is, after which it can no
longer be switched off:
The only way out is restarting openMSX; a machine reset does not help, because
locksOnis never reset while the MSX does clear its own state. This is easyto run into on host layouts where AltGr has to be held down to type common
characters such as
@,#or~, because the host CODE/KANA key defaults toright-Alt.
Cause
Keyboard::pressUnicodeByUser()auto-toggles the CODE/KANA lock by flippinglocksOnand callingpressKeyMatrixEvent()for the CODE key. That call is ano-op when the key is already down (it deliberately bails out when pressing
would not change the matrix).
So while the user physically holds the host CODE/KANA key, the MSX never sees
a new key-press edge and never toggles its lock, but openMSX flips
locksOnanyway. From then on the two are inverted, and because
needsLockToggle()nowreports the wrong direction, every following keystroke auto-toggles the real
lock the wrong way.
Fix
Only take the auto-toggle path when the CODE key is currently released, so the
press really produces an edge the MSX can act on. When the user is holding the
key, just type the character with CODE/KANA held down, which is what a real
MSX does.
The "already pressed" test is extracted from
pressKeyMatrixEvent()intoisKeyMatrixPressed()so both call sites share it. When the CODE key is notheld - the common case - behaviour is unchanged.
How it was verified
Driven against a real emulator run (
-control stdio) with synthetic host keyevents posted through the OS, observing
$led_kana, i.e. the actual KANA LEDas driven by the emulated MSX via PSG register 15. Every injected press and
release is confirmed against
debug read keymatrix <row>before the next step,so a dropped host event cannot silently produce a wrong trace.
Note: on macOS right-Alt is Option, which mangles the unicode of the following
key, so the character never reaches the unicode mapping path. Binding
kbd_code_kana_host_keytoENDhits exactly the same code path with anunmangled character, which is what AltGr+3=
#does on a Windows/Spanishkeyboard.
Machine
Canon_V-20_JP,kbd_code_kana_host_key END,kbd_auto_toggle_code_kana_lockon. Steps:KANA LED after each step, for all three mapping modes:
In CHARACTER mode before the fix, steps 7-9 are the bug: a plain letter
switches the KANA lock back on, and it stays stuck that way. Step 5 shows the
same desync from the other side - the lock is on and typing a plain letter
should auto-toggle it off, but openMSX already believes it is off so nothing
happens. After the fix step 5 auto-toggles correctly and steps 7-9 leave the
lock off.
KEY and POSITIONAL are byte-identical before and after, as expected:
processKeyEvent()forcesunicode = 0for those two modes, sopressUnicodeByUser()- and with it the changed branch - is unreachable there.Those traces do exercise the
isKeyMatrixPressed()extraction heavily though,since every keystroke in those modes goes through
pressKeyMatrixEvent()viaprocessSdlKey().Also checked to be unchanged:
kbd_auto_toggle_code_kana_lockis off;
helo,HELO, and kanaglyphs while CODE/KANA is held (which is correct MSX behaviour).
Not covered here
(Revised after merge: the Windows claim in the original version of this
section was wrong, see below.)
The ticket also mentions right-Alt behaving like CTRL on Windows (right-Alt+G
beeping). That one looks like it is already fixed, on the SDL side rather than
here. Windows generates a synthetic left-Ctrl alongside AltGr, and SDL2 started
filtering it in 2.30.4:
skip_bad_lcrtl()insrc/video/windows/SDL_windowsevents.cpeeks the message queue on WM_KEYDOWNand drops a non-extended VK_CONTROL when the next queued message is an extended
VK_MENU down with the same timestamp. It is absent in 2.30.3 and every earlier
release, and was renamed to
SkipAltGrLeftControl()in the 2.32 line. openMSXhas pinned SDL 2.30.7 since ae1dfac (2024-09-30) and both Windows build paths
use that pin, so every 21.0 build should have it. The original report is from
2021, when we still bundled SDL 2.0.x.
I have no Windows machine, so that is source archaeology rather than an
observation - someone on a non-US layout pressing right-Alt+G on a current
build would settle it in ten seconds.
One gap does remain, and it is in SDL rather than here: the same helper is also
called on WM_KEYUP, but it only matches when the next queued message is a
VK_MENU key-down, which cannot happen on release. So the fake left-Ctrl
release is still delivered. For openMSX that is normally harmless - releasing
a key that was never pressed is a no-op - but if you hold real left-Ctrl and
tap AltGr, the MSX sees CTRL released early. That also wants confirming on
Windows before it is worth reporting upstream.
The macOS half of the ticket is untouched as well: Option acts as a
dead-key/compose modifier there, so the character following it is altered by
the host before openMSX sees it. That is why the macOS symptoms in the report
read as "sometimes the character appears, sometimes nothing" rather than as a
lock you cannot clear.