0
\$\begingroup\$

I have a pretty generic input class. In the main app, I forward an event to the game. The game an input object that manages Keyup and Keydown presses. It stores the keys pressed in a vector<key> until the keyup function is called. For some reason, the keyup isn't always caught. I will add the relevant code, but let me know if you need more.

input.cpp

void Input::update() {

    //iterate held keys vector and perform held functions for them.

    for( std::vector<key>::iterator it = HeldKeys.begin(); it != HeldKeys.end(); it++ ) {
        std::map<key,std::function<void()>>::iterator func = OnHoldFuncs.find(*it);
        if( func != OnHoldFuncs.end() )
            func->second();
    }

}

void Input::KeyDown(SDL_KeyboardEvent pkey) {
    //Check the keyboard event if the key is held and return if it is.  We've already dealt with it.
    if( pkey.repeat == 1 ) 
        return;

    //Create the key object (struct is in header)
    key nkey(pkey.keysym.scancode,pkey.keysym.mod);                        

    //Look for registered call back on the keydown event
    std::map<key,std::function<void()>>::iterator func = OnDownFuncs.find(nkey);
    if( func != OnDownFuncs.end() )
        func->second();
    else
        std::cout << "unknown key " << pkey.keysym.scancode << " is pressed" << std::endl; //just debug message

    //look for held key function
    func = OnHoldFuncs.find(nkey);
    if( func != OnHoldFuncs.end() )
        HeldKeys.push_back(nkey); //function exist, store the key in the vector
    else {
        //to add a debug so I don't have to manually register keys right now for testing.
        RegOnKeyHold(pkey.keysym.scancode,pkey.keysym.mod,[=](){
            std::cout << "I AM BEING HELD AGAINST MY WILL " << pkey.keysym.scancode << std::endl;
        });
        HeldKeys.push_back(nkey);
    }

    return;
}

void Input::KeyUp(SDL_KeyboardEvent pkey) {
    //create key object
    key nkey(pkey.keysym.scancode,pkey.keysym.mod);

    //look for registered call back
    std::map<key,std::function<void()>>::iterator func = OnUpFuncs.find(nkey);
    if( func != OnUpFuncs.end() )
        func->second();
    else
        std::cout << "unknown key " << pkey.keysym.scancode << " is released" << std::endl; //debug msg

    for( std::vector<key>::iterator it = HeldKeys.begin(); it != HeldKeys.end(); it++ ) {
        if(*it == nkey) {
            HeldKeys.erase(it); //remove it from the vector
            break;
        }
    }

}

And the game.cpp, game is passed all events by default right now.

void Game::Handle(SDL_Event* Event) {
    switch(Event->type) {

    case SDL_KEYDOWN:
        input.KeyDown(Event->key);
        break;
    case SDL_KEYUP:
        input.KeyUp(Event->key);
        break;
    default:
        break;


    }

    return;
}

EDIT: Polling loop from application forwards all events to application Handle function. Here is the polling loop and handle function and game handle function.

while(GameState == RUNNING) {
    while(SDL_PollEvent(&Event)) {
        Handle(&Event);
    }

    Update();

    if( SDL_GetTicks() > Time + 100) {
        Render();
        Time = SDL_GetTicks();
    }
    else
    {
        SDL_Delay(1);
    }
}   

Handle function that forwards to game for all cases but quit. Probably should forward that one too so the game can ask to save first or stop the quit.

void KApp::Handle(SDL_Event* Event) {

    switch (Event->type)
    {
    case SDL_QUIT: 
        GameState = HALTED;
        break;

    default:
        game.Handle(Event);
        break;
    }

}

And the game handle function which handles all up and down events.

void Game::Handle(SDL_Event* Event) {
    switch(Event->type) {

    case SDL_KEYDOWN:
        input.KeyDown(Event->key);
        break;
    case SDL_KEYUP:
        input.KeyUp(Event->key);
        break;
    default:
        break;


    }

    return;
}
\$\endgroup\$
  • \$\begingroup\$ Are you sure that you are polling all the events with SDL_PollEvent(SDL_Event)? \$\endgroup\$ – kaspyre Jul 23 '15 at 21:58
  • \$\begingroup\$ I don't think I should miss any events (added code in edit above). I found out I can reproduce it if I am holding shift, press a, release shift and then release a. \$\endgroup\$ – Chemistpp Jul 23 '15 at 22:04
  • \$\begingroup\$ By the way, what does RegOnKey(... [=](){ function? } ) do? This is part of c++ I don't know! Have never seen [=] before. \$\endgroup\$ – david van brink Jul 23 '15 at 22:29
  • 1
    \$\begingroup\$ @davidvanbrink thats a closure. \$\endgroup\$ – tkausl Jul 23 '15 at 22:44
  • \$\begingroup\$ Are there specific circumstances in which a key-up is not caught? It's common for these to be lost if a key is held down and then the user alt-tabs away from the window, for instance (the key-up will go to the new window, not the one that originally received the key-down). \$\endgroup\$ – Sean Middleditch Aug 23 '15 at 5:53
1
\$\begingroup\$

I'm using SDL-2 also. Your code, at a basic reading, looks all correct to me. To help debug it, you could put a switch or printf right in the main loop, like

while(GameState == RUNNING) {
    while(SDL_PollEvent(&Event)) {
        printTheEventIfItsKeyUpOrKeyDown(&Event); // as needed
        Handle(&Event);
    }

A modifier key down also generates an event (shift key is value 0x400000e1). Even with the shift-key down, and 'A' key press will be 0x61 (lower case 'a').

My main monster SDL-2-based loop looks like:

while (!quit)
{
    SDL_GL_SwapWindow(this->mainwindow);
    while (SDL_PollEvent(&e))
    {
        switch(e.type)
        {
            case SDL_QUIT:
                quit = true;
                break;

            case SDL_KEYDOWN:
            {
                int key = e.key.keysym.sym;
                switch(key)
                {
                   // ... some stuff
                }
                break;
            }

            case SDL_KEYUP:
            {
                int key = e.key.keysym.sym;
                switch(key)
                {
                   // ... some stuff
                }
                break;
            }
        }
    }
}

The only difference from your code is mine is monolithic...

Hope that may help a little bit.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Yeah, I am trying to print the key presses now as well to solve this. I know what you mean about A's scancode not changing, but I stored with a struct between scancode and mod. So if I release the mod key first, then the actual key, the keyup event is with a different mod value and thus, it doesn't remove it from the heldkeys container. Found the problem. \$\endgroup\$ – Chemistpp Jul 24 '15 at 13:34
  • \$\begingroup\$ Yup! the "mods" field are the mod keys that happen to be down at the time of the event. So shift+A down won't necessarily be matched by shift+A up. Nailed it. \$\endgroup\$ – david van brink Jul 24 '15 at 19:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.