I’m trying to handle keypad keys depending on state of NumLock.
For example, if NumLock is ON and key KP_7 was pressed I call one function,
otherwise, if NumLock is OFF and key KP_7 was pressed I call another function.
Function SDL_GetModState returns zero.
Function SDL_GetKeyState returns for SDL_SCANCODE_NUMLOCKCLEAR also zero.
Is this a bug or there is a proper way to check the NumLock state?
Any advice would be much appreciated.
GetModState actually is working, its just that on startup the mod state is always off so when you press numlock while its on before starting the application the state gets reversed. You can either use platform specific methods to get the key state or use platform specific methods to toggle the LED so its off on start.
(SDL_GetModState() & KMOD_NUM) == (KMOD_NUM)
bibendovsky wrote:> Hello.
I’m trying to handle keypad keys depending on state of NumLock.
For example, if NumLock is ON and key KP_7 was pressed I call one function,
otherwise, if NumLock is OFF and key KP_7 was pressed I call another function.
Function SDL_GetModState returns zero.
Function SDL_GetKeyState returns for SDL_SCANCODE_NUMLOCKCLEAR also zero.
Is this a bug or there is a proper way to check the NumLock state?
Any advice would be much appreciated.
[quote=“AlexRou”]GetModState actually is working, its just that on startup the mod state is always off so when you press numlock while its on before starting the application the state gets reversed. You can either use platform specific methods to get the key state or use platform specific methods to toggle the LED so its off on start.
I will bump this thread since it’s definitely a bug in SDL2.
We have no way of knowing the real state of the numlock state, so basically if it’s off then SDL2 is generating both SDL_TEXTINPUT and SDL_KEYDOWN events resulting in typing the text and navigating around (if numpad is used as arrow keys). However, only SDL_KEYDOWN events are send when the numlock is enabled. It is impossible to check the numlock state by using SDL_GetModState since it’s always false when the application is started (even though the numpad is actually on).
I think it’s SDL_PumpEvents (which is called from SDL_PollEvent) that updates the mod state. If it has not been called recently, for whatever reason, the return value of SDL_GetModState() might be outdated. This is unlikely to be a problem if you’re using SDL_PollEvent to handle events frequently which most applications do.
It should be fine as long as you call SDL_PumpEvents (Yes, I have tested. It works for me when I call SDL_PumpEvents regardless of whether I call SDL_PeepEvents)
Why do you not just test this yourself? Does it not work for you?
Yes it works for me but it is apparently not working for one of my customers. He is receiving incorrect characters from the numeric keypad and although I don’t fully understand what is happening it could possibly be explained if the NumLock status is being incorrectly detected. I found this old thread hence the question.
Unless I have missed something, it is non-trivial in SDL2 to make the keypad work as one would want it to. When NumLock is on I expect to receive the characters ‘0’ to ‘9’ via the SDL_TEXTINPUT event but when NumLock is off I expect to receive the edit keypresses (Up, Down, Home, End etc.) via the SDL_KEYDOWN event.
To arrange that it seems that I have to monitor the NumLock status myself; although SDL2 seems automatically to generate the required SDL_TEXTINPUT events only when NumLock is on, the SDL_KEYDOWN events are (perhaps not unexpectedly) received whether it is on or off!
If there’s some simple way that I have missed to make the numeric keypad behave ‘properly’ without explicitly detecting and acting upon the NumLock state I would love to know.
I agree, it would have made sense to receive for example a SDL_KP_UP when pressing 8 on the numpad when NumLock is off but there is no such key code.
The way I have been handling this is by manually checking for KMOD_NUM when receiving a SDL_KP_8, something like this:
switch (event.key.keysym.sym)
{
case SDLK_KP_8:
if (!(event.key.keysym.mod & KMOD_NUM))
{
onKeyUpPressed();
}
break;
case SDLK_UP:
onKeyUpPressed();
break;
...
Or if you want to avoid repeating the code for SDLK_UP and don’t mind using fallthrough:
switch (event.key.keysym.sym)
{
case SDLK_KP_8:
if (event.key.keysym.mod & KMOD_NUM)
{
break;
}
// fallthrough
case SDLK_UP:
onKeyUpPressed();
break;
...
This has worked well enough for my purposes. My only concern has been that I don’t know for sure that it doesn’t exist keyboard layouts where the meaning of these keys are different, but I suspect not because 1) in that case SDL would probably have provided a better way to handle this in a cross-platform way, and 2) SDL3’s got an internal function SDL_ConvertNumpadKeycode that uses nothing other than the NumLock status to map the numpad key codes.
Yes, that code is pretty much exactly what I am using. I’m pleased that I’m not missing a simpler alternative, such as the SDL_KP_UP etc. you suggested. I presume SDL3 doesn’t have these either?
Not as far as I can see. I did however find a hint that seems to be able to remap the numpad keys automatically but I haven’t tried it. This seems to be exactly what you asked for originally.
SDL_HINT_KEYCODE_OPTIONS
“hide_numpad”: The numpad keysyms will be translated into their non-numpad versions based on the current NumLock state. For example, SDLK_KP_4 would become SDLK_4 if SDL_KMOD_NUM is set in the event modifiers, and SDLK_LEFT if it is unset.
Ah, it’s good to know that this issue has at least been addressed in SDL3. I wonder if there’s some way it could be made to work via SDL2-compat which I can in principle use on desktop platforms (not mobile because of the lack of support for an OpenGLES 1.1 backend, which I need).