SDL
SDL copied to clipboard
Improve handling of CTRL key
When CTRL is pressed, SDL2 does not generate any SDL_TEXTINPUT event which mean that the code can only use the information provided in SDL_KEYPRESS ; that is the 'keycode' and the 'modifiers' bits.
This is problematic because because there is no practical way to figure out which character should be used when Shift or AltGr is enabled. For example, if an application want to handle ctrl-@ then it should detect Shift-2 with the US qwerty layout, Shift-' with the UK qwerty layout and AltGr-à with the French azerty layout.
This is not feasible with the current API because the layout is not (and should probably not) be exposed to the user.
That limitation is related to https://github.com/libsdl-org/SDL/issues/1767#issuecomment-929977899 and https://github.com/libsdl-org/SDL/issues/5685
My proposed solution is to produce a new event of kind SDL_TEXTINPUTCTRL that will be emitted when CTRL prevents the production of SDL_TEXTINPUT. That should be a non-breaking change since old applications can ignore the new events.
I have a working proof of concept for X11 and Wayland in https://github.com/schauveau/SDL-ctrl
See the README.md for more more details.
I made the incorrect assumption that SDL 2 was never producing a SDL_TEXTINPUT event when CTRL is set
That seems to the case for wayland because SDL_SendKeyboardText() is never called when KMOD_CTRL is set.
However, this is not always true for x11. Some key combination with CTRL are producing a SDL_TEXTINPUTwhile other are not. For example, CTRL-1 produces 1 while CTRL-2 produces nothing.
This is probably because SDL_SendKeyboardText is explicitly ignoring any text starting with a character that is not printable (lower than 32 or equal to 127).
That does not necessarily make SDL_TEXTINPUTCTRL a bad idea but the expected behavior should be standardized.
Yes, that's more the problem, that we haven't defined standard behavior. Usually this ends up being what Windows does, to conform with the expectations of the majority of game developers.
I do not have any Windows machine to check the behavior. Can someone provide a sample output of checkkeys on Windows showing how various keys are reported with and without CTRL and SHIFT?
I am especially interested by the CTRL behavior with '@', 'a' to 'z', [ , \ , ], ^ and _.
The reason being that on Unix/Linux they are traditionally mapped to the control characters 0 to 31.
The x11 SDL backend does not produce any inputtext because SDL_SendKeyboardText is explicitly discarding those characters.
Does Window have similar rules? no idea!
After a bit of digging, I figured out how CTRL is handled by X11, Wayland and any Linux application based on the libxkbcommon library. Basically, the key is decoded to a unicode codepoint which is then modified by the following function:
static char
XkbToControl(char ch)
{
char c = ch;
if ((c >= '@' && c < '\177') || c == ' ')
c &= 0x1F;
else if (c == '2')
c = '\000';
else if (c >= '3' && c <= '7')
c -= ('3' - '\033');
else if (c == '8')
c = '\177';
else if (c == '/')
c = '_' & 0x1F;
return c;
}
https://github.com/xkbcommon/libxkbcommon/blob/master/src/state.c#L899
That explains a lot about the seemingly odd behavior of CTRL. Never too late to learn even after 25 years of Linux/Unix.
Of course, since this is performed on the application side that means it is trivial to obtain the text of the key by temporarily clearing out the ctrl state during decoding as done in my proof of concept code.
Unfortunately, that may be more tricky to do on Windows since the text seems to be provided by the OS via WM_UNICHAR or WM_CHAR messages.