Jump to content
  • Advertisement
Sign in to follow this  
Tom Olsson

Keyboard input: poll, push or pull?

This topic is 1527 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.


Recommended Posts

Hello everyone!
 
I'm trying to decide on wether to use polling, pulling or pushing for keyboard input. I tried searching but did not find any good answer containing all three these in a comparison, and I've reached a point where I need to decide for a bigger project. I'm well aware that there's rarely one best solution, but I'm curious as to wether there is any preferred method amongst other game developers.
 
As far as definitions go (my opinions, of course), polling means that each individual module checks it's own keybinds towards the underlying API (in my case, Windows).

Pros:

  • Easy to implement
  • Keybindings are easy to manage inside the class
  • Multiple keybinds for same button

Cons:

  • Lots and lots of API calls to check key states
  • Will become more difficult to change if performance becomes an issue
  • Will need N polls per frame, N -> number of binding
Pulling is essentially the same, but instead of each individual module polling, we would do one big API-poll in a KeybindManager and then each module polls that one - pulling a keystate variable instead of polling the API.
Pros:
  • It's sort-of Observer-patttern
  • Keybindings are easily visible inside the class
  • Can easily be refactored into either of the others by being a middle ground.
  • Multiple keybinds for same button
Cons:
  • Still need to do lots and lots of checks
  • Still needs 1 API-poll + N pulls per frame
Pushing is the same as pulling, but as the name suggest it tells each class when a button changes state instead of each class checking its buttons.
 
Pros:
  • It's a correct Observer-pattern
  • An effecient implementation will only notify changes, reducing CPU-cycles needed
Cons: 
  • It requires an interface/mediator/semaphore-style variable
  • If we want to reduce notifications, we increase complexity in KeyboardManager
  • Multiple keybinding leads to drastically increased complexity.
 
If I've done either of the styles injustice in my pros/cons, or if you disagree with the descriptions, please say so. In a code scenario, simplified they'd be like this:
 
Polling 
//Vehicle.cpp
void Vehicle::UpdatePoll(int time){    
    if(GetKeyState(VK_RETURN){         //Do something ?    }
}
 
Pulling
//Vehicle.cpp
void Vehicle::UpdatePull(int time){
    if (kbManager->IsKey(VK_RETURN){ ... }
}

//Keyboardmanager.cpp
void KBManager::Update(){
    localKeyStates = GetKeyStates();
}
UINT KBManager::IsKey(UINT virtualKey){
    return localKeyStates[virtualKey];
}
Pushing
//Vehicle.cpp inherits KeyObserver
Vehicle::Vehicle(){
    kbManager->Register(VK_RETURN, this);
}
void Vehicle::UpdateKeyState(UINT keyVal, bool state){
    if (keyVal == VK_RETURN)    this->keyReturn = state;
}
void Vehicle::Update(int time){
    if(this->keyReturn) { ... }
}


//Keyboardmanager.cpp
void KBManager::Register(UINT virtualKey, KeyObserver& obj){
     this->BindingList[virtualKey] = obj;
}
void KBManager::Update(int time){
    this->localKeyStates = GetKeyStates();
    for_each (UINT key : BindingList.Keys){
        Notify(key);
    } 
}
void KBManager::Notify(UINT key){
    if (IsChanged(localKeyStates[key])){
        BindingList[key]->Update(key, localKeyStates[key]);
    }
}

 

Share this post


Link to post
Share on other sites
Advertisement

I concur with SmkViper. On Windows, you want to handle Windows messages for keyboard and mouse input (WM_KEYDOWN/UP, WM_CHAR, WM_MOUSE*, WM_*BUTTONDOWN/UP/DBLCLK, etc.). I supposed this is the "push" option you listed, although I'd just call it "event-driven".

 

You'd then have a middle layer that translates raw input into game "actions" (i.e. "move camera left", "move camera right", "jump", "shoot", etc.), and dispatches those actions via events to the rest of the game. These can be rebound by the user in a number of different ways for maximum customization. The input system I designed also dispatches raw virtual keys, and in the case of WM_CHAR events, raw character codes. But those are only handled in a few very special places, such as debug modules and chat interfaces. 95% of the game listens for the abstract action codes.

Share this post


Link to post
Share on other sites

I concur with SmkViper.

 

^^^ Yes.  

 

The first one, where each object polls the input makes it hard to add keyboard/joystick mapping.  Imagine you need an analog stick or the arrow keys to both do the same thing in the game.  You don't want game objects worrying about that.

 

The last one, pushing, seems like a good idea at first, but it doesn't work either.  Again, you can't smooth out data, you have no way to fire events when two or more keys are down, or use two buttons as a combo, or anything like that.  Imagine a fighting game.  If the input was pushed on another thread you would never make sense of it.  Plus, you may want some way to record player input and play it back at a slow speed.  You can't do replays by simulating input events pushed from the OS.  

 

Do the massive poll, generate any input events, and either make the events available or have objects request push notifications when an event fires.  You can still have poll, push, and pull that way, but one level away from the input.

Edited by Glass_Knife

Share this post


Link to post
Share on other sites

Interesting input so far - I've never considered adding action messages. I guess that sort of makes sense. Sort of like XAML/WPF does it.

 

But then if you did, would you push key states (or rather action states, I guess?) or would you push actions?
 

F.ex., would you tell it to MOVE_LEFT, or keep it as a bool that you then check in another function?

Edited by tgolsson

Share this post


Link to post
Share on other sites

Hi,

 

I voted for the second one, because it's easier and takes less time to code.

 

To be honest, if it is for a complex game, I'd go for an event-driven solution, sending the actions to the objects via an event manager when an input event is detected.

Share this post


Link to post
Share on other sites

Interesting input so far - I've never considered adding action messages. I guess that sort of makes sense. Sort of like XAML/WPF does it.

 

But then if you did, would you push key states (or rather action states, I guess?) or would you push actions?
 

F.ex., would you tell it to MOVE_LEFT, or keep it as a bool that you then check in another function?

 

You push actions (dispatch events), but track states. In this particular example, the movement system would listen for a MOVE_LEFT action, and it would be flagged as a "press". The system then knows to set its own internal state variable indicating that left movement is active. During the system's logical service, it would check that flag and apply the left movement logic if the state is active. If the system later receives a MOVE_LEFT action flagged as "release", it would reset the left movement flag, and the service would no longer apply movement.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!