Keyboard input system handling

Note: I have to poll, rather than do callbacks because of API limitations (SFML). I also apologize for the lack of a 'decent' title.

I think I have two questions here; how to register the input I'm receiving, and what to do with it.

Handling Input

I'm talking about after the fact you've registered that the 'A' key has been pressed, for example, and how to do it from there.

I've seen an array of the whole keyboard, something like:

 bool keyboard[256]; //And each input loop check the state of every key on the keyboard 

But this seems inefficient. Not only are you coupling the key 'A' to 'player moving left', for example, but it checks every key, 30-60 times a second.

I then tried another system which just looked for keys it wanted.

std::map< unsigned char, Key> keyMap; //Key stores the keycode, and whether it's been pressed. Then, I declare a load of const unsigned char called 'Quit' or 'PlayerLeft'. input->BindKey(Keys::PlayerLeft, KeyCode::A); //so now you can check if PlayerLeft, rather than if A. 

However, the problem with this is I cannot now type a name, for example, without having to bind every single key.

Then, I have the second problem, which I cannot really think of a good solution for:

Sending Input

I now know that the A key has been pressed or that playerLeft is true. But how do I go from here?

I thought about just checking  if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
This couples the input greatly to the entities, and I find it rather messy. I'd prefer the player to handle its own movement when it gets updated. I thought some kind of event system could work, but I do not know how to go with it. (I heard signals and slots was good for this kind of work, but it's apparently very slow and I cannot see how it'd fit).

Thanks.

What I'd do is use the observer pattern and have an input class that maintains a list of callbacks or input handling objects. Other objects can register themselves with the input system to be notified when certain things happen. There are different types of callbacks you could register, based on the type of input events observers would like to be notified about. This could be as low level as 'key x is down/up' or more game-specific like 'a jump/shooting/movement event happened'.

Generally game objects have an input handling component that is responsible for registering itself with the input class and providing methods to handle the events it is interested in. For movement, I have an input mover component that has a move(x, y) method. It registers itself with the input system and gets notified on movement events (where x and y would be -1 and 0 to signify moving left), the mover component then changes its parent game object coordinates based on movement direction and object velocity.

I don't know if this is a good solution but it works for me so far. In particular it allows me to provide different kinds of input system that map to the same logical game events so that gamepad button x and keyboard space both generate a jump event for example (it's a bit more complicated than that, allowing the user to reassign key mappings).

• This definitely interests me; would the input component register itself for certain events (something like playerInput registers 'left', 'right', etc) or would every input component that's registered receive all messages? – The Communist Duck Aug 22 '10 at 16:35
• It really depends on your requirement and how you like to implement it. In my case listeners register themselves for specific events and implement the appropriate input handler interface. Having every input component receive all messages should work, but the message format needs to be more generic than what I have. – Firas Assaad Aug 22 '10 at 20:39

I think that the OP's discussion is lumping a bunch of things together, and that the problem can be simplified substantially by breaking it up a bit.

My suggestion:

Keep your array of keys' states. Isn't there an API call to get the entire keyboard state at once? (Most of my work is on consoles, and even on Windows for a connected controller you get the whole controller state at once.) Your key states are a "hard" map on the keys of the keyboard. Untranslated is best, but however you get it easiest out of the APIs.

Then keep a a few parallel arrays that indicate whether the key went up this frame, another indicating that it went down, and a third to indicate simply that the key is "down". Maybe throw in a timer so you can keep track of how long the key has been in its current state.

Next create a method to create a mapping of keys to actions. You'll want to do this a couple of times. Once for UI stuff (and take care to query the Windows mappings because you can't assume the scancode when you press 'A' is going to give an A on the user's computer). Another for each in-game "mode". These are the mappings of keycodes to actions. You can do this a couple of ways, one would be to keep an enum that is used by the receiving system, another would be a function pointer indicating the function to be called on a state change. Maybe even a hybrid of the two, depending on your goals and needs. With these "modes" you can push and pop them onto a controller mode stack, with flags that allow ignored input to keep going down the stack or whatever. The key though is that it is easy to switch in a new mode for handling the input.

Finally, handle those key actions somehow. For motion you might want to do something tricky, translate 'W' down to mean "move forward," but it doesn't need to be a binary solution; you can have "W is down" mean "increase velocity by X until a maximum of Y," and "W is up" to be "decrease velocity by Z until it hits zero." Generally speaking- you want your "controller handling interface in game systems" to be pretty narrow; do all of the key translation in one place and then use the results of that everywhere else. This is in contrast to directly checking to see if Spacebar is pressed anywhere random in the code, because if it's in some random spot it'll probably get hit at some random time when you don't want it to, and you just don't want to deal with that...

I really detest designing to patterns and I think components bring more development cost than good, so that's why I mentioned neither. Patterns will emerge if they're destined to, as will components, but setting out to do either from the outset will only complicate your life.

• Don't you think it's kind of dirty to bind events to graphic frames? I think that should be separated. – Jo So Dec 13 '17 at 1:26
• I mean, I get that in almost all cases the player will be slower to input buttons than the graphics card will emit frames, but really they should be independent, and in fact they are for other event types, like ones gathered taken from the network. – Jo So Dec 13 '17 at 1:28
• Indeed; there's no reason why polling the keyboard (or other input device) can't be run at a rate different from the display. Indeed, if you poll inputs at 100Hz then you can provide a really consistent user control experience regardless of video hardware update frequency. You'll have to be a bit more clever about how you handle your data (regarding latching etc.) but it'll make things like gestures way easier to make consistent. – dash-tom-bang Dec 13 '17 at 1:53

In SFML, you have the keys in the order they have been pressed with the KeyPressed event type. You process each key in a while(getNextEvent()).

So if the pressed key is in your Key->Action map, run the corresponding action, and if it's not, forward it to any widget/stuff that might need it.

Regarding your second question, I'd recommend you to keep it like this because it makes it easier to tweak your gameplay. If you use signals or such, you will have to make a slot for the "RunKeyDown" and another for the "JumpKeySlot". But what happens if in your game, a special action is performed when both are pressed ?

If you want to decorrelate input and entities, you could make your input a State (RunKey = true, FireKey = false, ...) and send it to the player like you send any other event to your AIs.

• I'm not handling keyboard events with sf::Event, rather sf::Input, because it's real-time detection IIRC. I tried to keep it as API-agnostic as possible. :P (The question, that is) – The Communist Duck Aug 22 '10 at 11:01
• But I think the point Calvin1602 is making is that your original statement in the question of "I have to poll, rather than do callbacks because of API limitations (SFML)" is not true; you have events, so you can issue a callback when you handle an event. – Kylotan Aug 23 '10 at 15:31

The correct solution is often a combination of the two methods you discuss:

For gameplay functionality with a predefined set of keys, polling every frame is completely appropriate and you should only poll for keys that are actually bound to something. This is actually analogous to how you would query controller input in a console game, it's going to be entirely polling especially when it comes to analog input devices. During general gameplay you probably want to ignore keypress events and just use polling.

When it comes to typing input for things like names you should switch the game into a different input handling mode. For instance, as soon as a "enter your name" prompt comes up, you can modify what you're input code does. It can either listen for key press events via some callback interface, or you can start polling for each key if required. It turns out that typically during typing events you don't care as much about performance anyway, so polling won't be that bad.

So, you want to use selective polling for gameplay input, and event handling for name typing inputs (or all keyboard polling if event handling is not available).

I like the answer of dash-tom-bang very much, it really highlights some aspects that you should keep in mind when designing an input system.

I'd like to add a little tutorial I stumbled upon which goes in the same direction (including input contexts, 3 layers,...):

http://www.gamedev.net/blog/355/entry-2250186-designing-a-robust-input-handling-system-for-games/