Not registering poll events or keyboard states on macOS

Hi! I am writing my own game engine or rather porting my windows game engine to Mac. I wasn’t using SDL earlier but now I am trying to in the macOS version. The keyboard events doesn’t seem to be polling. I tried logging, getting the keyboard state etc., If I quit my SDL_Window that is polled properly by the SDL_PollEvent but none of my keyboard inputs work.

void WindowMac::Update()
{
    SDL_SetWindowInputFocus(m_sdlWindow);
    SDL_Event event;
    const Uint8 *keyState = SDL_GetKeyboardState(NULL);
    if (keyState[SDL_SCANCODE_X])
    {
        std::cout << "Key pressed: X";
    }
    while (SDL_PollEvent(&event)) {
        if (event.type == SDL_QUIT) {
            SDL_Quit();
        }
        else if(event.type == SDL_KEYDOWN)
        {
            switch (event.key.keysym.sym) {
                case SDLK_ESCAPE:
                    SDL_Quit();
                    break;
                case SDLK_UP:
                    std::cout << "UP key pressed." << std::endl;
            }
        }
        
    }
}

I am guessing it might have to do with permissions? I tried giving my app as well as Xcode permissions on my privacy and security tab on system settings on my Mac. Not sure what else I am missing. Any help would be appreciated! Thanks.

I don’t own a Mac, so I can’t confirm the issue, however, I’m going to swing at some low-hanging fruit real quick, no offense meant:
*1. Is this update function being called from the main thread?
- if I remember correctly, some versions of mac can close a window even if you don’t process the event, so I’m double checking that the function is actually being called. (To be fair, your logging should prove this to not be the case). ~~
- Events are not guaranteed to work on all platforms if they are called from a thread other than the main thread…? [Edit: Actually I think this refutes that. → SDL :: View topic - SDL2 and multi-threading ] *

  1. What does your SDL_Init() function argument look like?

    • Many parts of the SDL library will work even if you forget to call SDL_Init(flags); which catches you off guard if you get used to omitting it and suddenly things break.
    • If you aren’t using SDL_INIT_EVERYTHING, then please confirm that SDL_INIT_EVENTS is one of the flags in use.
  2. Is SDL_PollEvent() being called from anywhere else?

    • As I understand it, this would remove that event from the event queue and block other objects from also polling that event. I generally pass pointers to polled/loaded events as the argument to my Update functions to avoid this. (I do understand that this is your window manager. It’s not a problem how you have it, so long as there isn’t some other object also trying to poll the events queue.)

* Pretty certain my first question is confirmed pointless.

This is just a wild guess, but does it work if you remove the line SDL_SetWindowInputFocus(m_sdlWindow);?

1 Like

Ooh, that’s an interesting one. Certainly not a necessary line.
That’s worth poking around SDL source code to check for side effects.
I think they have it there just to show all the things attempted, but I’m still curious.

A couple recommendations:

  1. Instead of an if-else block, use a switch statement for the outer event checking. If you’re handling a lot of different types of events then it’ll be faster.
  2. Throw a break statement on the end of the SDLK_UP block, as a precaution, so you don’t forget to add it when you start adding more key handling.
  3. Your event processing code should set a flag to be handled outside the event checking loop. Sometimes you can get multiple of the same type of events per frame, especially mouse move and joystick events.
  4. Calling SDL_Quit() shuts down SDL, but it doesn’t exit your application.
  5. You don’t need to call SDL_SetWIndowInputFocus() if that’s your only window. And even if you have multiple windows, you should only call when you want to change input focus. Calling it every frame might incur a performance hit, depending on what the OS needs to do behind the scenes. Even if there’s no big performance hit, it’s pointless to have it in there.

I had no idea that SDL_GetKeyboardState() consumed keyboard events, I don’t tend to use that function, but that’s really good to know beforehand.
… So we still don’t have confirmation on why the SDL_GetKeyboardState was not returning a value, or if the problem can be replicated on another Mac.

That’s not true. SDL_GetKeyboardState just returns a pointer as you can see here.

1 Like

SDL_GetKeyboardState ← So they are connected according to the documentation, just in the reverse of what was indicated. The key states are not updated until events are pumped/polled.
But since WindowMac::Update is being called in a loop and that keyState is a pointer to internal data, that new key state should be caught on the next loop iteration… right?

I’m writing a test for that theory.

That is my understanding, yes.

Yep, confirmed on my Linux machine that it does survive the loop and does not consume the event.

#include <SDL2/SDL.h>

SDL_Event ev;
int main()
{
	SDL_Init(SDL_INIT_EVERYTHING);

	SDL_Window * win = SDL_CreateWindow("title", 20, 20, 800, 800, SDL_WINDOW_SHOWN| SDL_WINDOW_RESIZABLE);
	SDL_Renderer * screen = SDL_CreateRenderer(win, -1, SDL_RENDERER_PRESENTVSYNC);
	SDL_Texture * img = NULL;
	SDL_Rect pos = {20, 20, 200, 200};
	bool run = true;
	while(run)
	{
		const Uint8 * keyState = SDL_GetKeyboardState(NULL);
		if(keyState[SDL_SCANCODE_SPACE])
		{
			SDL_Log("Space is pressed");
		}
		while(SDL_PollEvent(&ev))
		{
			switch(ev.type)
			{
				case SDL_KEYDOWN:
					SDL_Log("Key Down Caught");
					break;
				case SDL_QUIT:
					run = false;
					break;
			}

		}
		SDL_RenderClear(screen);
		SDL_RenderCopy(screen, img, NULL, &pos);
		SDL_RenderPresent(screen);
	}
	SDL_Quit();
}

The cool thing is that the SDL_GetKeyboardState() returns an internal pointer, so I could have called it above the loop and the data would still be updated correctly on event polling. I’m going to be able to use this for player keyboard flags now, very nice.

Edit: Sorry, VigneshMohan, that kind of got off topic… are you still there? Any luck?

Weird, I would’ve sworn I’d had to dig through the keyboard code before and that function looped over and consumed keyboard events.

Now I feel dumb… always check first! Thinking about it, of course it wouldn’t consume the events (even if it looped over them), since the application may want to handle certain keyboard events as well. :man_facepalming:

You’re awesome SJR, this is a very rare event.

1 Like

Initializing with SDL_INIT_VIDEO also initializes the events subsystem, see (SDL2/SDL_Init - SDL Wiki) :

  • SDL_INIT_VIDEO: video subsystem; automatically initializes the events subsystem

That makes sense since many events are so closely tied to the video headers. I wonder why SDL_INIT_EVENTS is available by itself?
You must be able to still get timer events and some others without a window in console mode, but can you still catch keyboard and mouse input without a window?
Interesting.

Edit after another test:
So no mouse/keyboard events in console mode, but it does catch SDL_QUIT, so timers and probably some other subset of events will still fire.

Hi @GuildedDougnut. Sorry I am still here, wasn’t expecting such fast replies from the community. Thanks everyone!

  1. What does your SDL_Init() function argument look like?
    As mentioned by @Sjr I do SDL_Init(SDL_INIT_VIDEO) at the startup of my window manager.
  1. Is SDL_PollEvent() being called from anywhere else?
    No it’s not. I have the window manager run the poll every frame. And it’s called from my App every frame. Pretty sure nothing else is consuming the event.

As for the SDL_SetWindowInputFocus I tried removing it. Didn’t work. And yes I did have that there to show all the things I have tried.

After some more tests. Added some logs instead of trying to catch key hits. It seems I am consistently hitting caps lock but none of the other keys.

@sjr yep tried all your suggestions. I tried setting breakpoint for different events. I started out being generic before moving on to specific events like UP. None of them triggered. Except for Capslock.

I know that you mentioned you’ve already tried some generic things already, but do you mind trying it with these mods;

line 3: comment out the SDL_SetWindowInputFocus call. (Just in case)

line 11: SDL_Log will report in console any event detected. This will be incredibly spammy with mouse motions, so comment it out after testing it the first time. I just want to know if anything at all fires with a normal key press. I can look up the value of the event.type if you do get any hits from the keyboard. (SDL_KEYDOWN on my system reports as event type 771)

line 17: SDL_Log will report in the console if any KeyDown event is detected and the associated sym number.

void WindowMac::Update()
{
//    SDL_SetWindowInputFocus(m_sdlWindow);
    SDL_Event event;
    const Uint8 *keyState = SDL_GetKeyboardState(NULL);
    if (keyState[SDL_SCANCODE_X])
    {
        std::cout << "Key pressed: X";
    }
    while (SDL_PollEvent(&event)) {
        SDL_Log("Event type %d detected", event.type);
        if (event.type == SDL_QUIT) {
            SDL_Quit();
        }
        else if(event.type == SDL_KEYDOWN)
        {
            SDL_Log("KeyDown Event detected: %d", event.key.keysym.sym);
            switch (event.key.keysym.sym) {
                case SDLK_ESCAPE:
                    SDL_Quit();
                    break;
                case SDLK_UP:
                    std::cout << "UP key pressed." << std::endl;
                    break;
            }
        }    
    }
}

If the above still runs with no keys detected, then I’m pretty much out of ideas. The next step is to either show more code or log an issue report with SDL’s github. I really would have liked to have someone with a Mac confirm that there was a repeatable issue on their machine before lodging an issue, though.

After further investigation it seems like that function only does something useful on X11 on Linux.

Is your window visible and has focus when you press the keys?

You say you’re porting your game engine from Windows to Mac but you didn’t use SDL earlier. Does that mean you don’t know if your SDL program works correctly on Windows?

Are you using the latest version of SDL2?

@Peter87 Yes. I got the latest Release 2.30.2 · libsdl-org/SDL · GitHub here. My window is visible and I am polling events (Window Quit and Capslock).
I didn’t need SDL in my windows version since I was using a different system for inputs. I guess porting isn’t a good term. I am rewriting my engine for Mac with some stuff stolen from my windows version.