Character case mismatch when launching Medley on Linux with Caps Lock on
Describe the bug If I launch Medley from Linux with Caps Lock turned on, the case of the characters typed in any editor (e.g. the Excec) doesn't match the state of the Caps Lock and Shift keys.
Typing a letter while Caps Lock is on yields the lowercase letter and typing a letter with Caps Lock off yields the uppercase version. If Caps Lock is turned off immediately after Medley starts, typing a letter still yields the uppercase version as well as typing Shift + letter with Caps Lock off.
To Reproduce Steps to reproduce the behavior:
- from the Linux shell, execute
medley & - at the Exec, type a letter
Expected behavior Typing letters with Caps Lock on yields uppercase letters. Typing letters with Caps Lock off yields lowercase letters.
Screenshots
N/A
Context (please complete the following information):
- OS: Crostini Linux
- OS Version: Debian 11 Bullseye Linux container of chromeOS 119.0.6045.192
- Host arch: x86_64 (ASUS Chromebox 3)
- Maiko version: 3.51
- IL:MAKESYSDATE: 1 Dec 2023 21:04:05
Additional context I use the SDL backend of Medley built from source on Linux. A similar issue happens with Medley SDL under Raspberry Pi OS Bookworm on my Raspberry Pi 400.
This is likely a known issue but, since I haven't found any specific reports here, I thought I'd record it in its own issue.
The root cause is that Medley/Maiko is unaware of key transitions that happen outside the Lisp window and therefore don't generate key state transition events to the emulator.
I was looking in maiko/src/initkbd.c to figure out the keyboard mapping, and that led me to discover the XkbGetNamedIndicator function. It looks like (for X Windows) this could be invoked to get the current state of the Caps_Lock key and use the state_rtrn value to initialize Medley with the current state of that mode.
It could also be used for Num_Lock; that mode is already in Medley. (Lisp keyboard code 73.)
I don't know that we can initialize the Medley state - the caps-lock isn't (usually) based on whether the caps-lock key is down or up in the key bit table, at least not under most X servers. You usually get keydown, keyup, then it's in lock mode, then keydown, keyup, and it's not in lock mode. In the Lisp code, the keyaction for the caps-lock key is set to (LOCKTOGGLE . IGNORE) and there's the whole Lisp mechanism that is a black box to the Maiko code for turning LOCKTOGGLE into the current caps-lock state. I suspect the same (wrt X11) goes for the num-lock key.
I've been doing some digging into the keyboard code, and experiments.
- The
XKeyEventstructure (i.e.,report.xkey) that is handled byprocess_Xevents(in maiko/src/xwinman.c) contains both thekeycodeof theKeyPressorKeyReleaseevent and astatefield. Thestatefield purports to encode the current state of the keyboardShift,CapsLock, andControlmodes (plus a few others). - I added DEBUG code on
KeyPressandKeyReleaseto printkeycode,state, and the mapped to Lisp key number values. - By experiment I verified, that the
statefield is correct even if the keyboard focus is not in the medley Xwindow on theCapsLockkey press. This was on Windows 11, WSL with Ubuntu, AND on Ubuntu installed natively on an old laptop, both. (In fact, on Windows, a Windows application had the focus for that test.) -
ShiftandControlreport for either the left or right corresponding keys are down. -
NumLockis also encoded. -
Altis encoded/reported for either the left or right key down. - The
WindowsandMenukeys are not encoded instate. - Although the
statefield is anunsigned int, it appears that only the low-order 8 bits are used (at present).
So, this means that at each key transition, we can (should) know the correct state of the CapsLock (and NumLock).
If this information is passed to Lisp, then it can handle each key correctly, even if it doesn't see the key press that set/cleared these modes. It also could know if the Shift and/or Control keys are already pressed when medley is started.
This change probably would be considered as a breaking change, since older sysouts wouldn't know about the modes status.
Here is my maiko/src/xwinman.c file (.txt because can't attach .c file) xwinman.c.txt