CocoaDev

Edit AllPages

I propose here what I think is a simpler solution than that proposed in GameKeyboardHandlingAlmost.

Game Keyboard Handling Solution

When writing games or many other programs that heavily involve keyboard interaction it is often desirable to respond many keys being held at once. A common example of this is the user’s desire to perform an action while moving or to move and turn or move diagonally. This was the inspiration for the solution I present below. Note, however, that this solution can be used in any program where the user would likely be holding keys down while pressing others. Through the use of Cocoa data structures like NSMutableSet this solution can be trivially extended to support any number of simultaneous keys. If you wanted to you could use it to support even the absurd edge case of all keys on the keyboard being held at once.

Onward to the solution. There are three steps to this solution: configuring your NIB file in InterfaceBuilder, modifying the header of your custom view class, and finally adding the code for multiple-keys pressed support to the implementation file. I sincerely hope this solution proves as effective for you as it has for me.

STEP 1: Configuring your NIB file in InterfaceBuilder

In your MainMenu.nib or MyDocument.nib file (or any other nib where you have custom drawing code that needs keyboard input) make a connection from the Window object in the Instances tab to the custom view in the window itself and connect it to the initialFirstResponder outlet. If you don’t know how to do this, I recommend doing the CurrencyConverter tutorial in Apple’s Developer Documentation first.

STEP 2: Modifying the Header of Your Custom View Class

Header file:

@interface MyCustomView : NSView { NSMutableSet * keysPressed; }

STEP 3: Adding Multiple-keys Pressed Support

The rest of the code shown is within the @implementation MyCustomView and @end delimeters in MyCustomView.h.

Declare that your view will accept keyboard focus:

Add keys of interest to the keysPressed set as they are hit:

Remove keys of interest from the keysPressed set as they are released:

Setup up a periodic key processing operation:

As a result, the compound effect of multiple keys that are pressed is applied to each frame. Simply add more cases to each switch statement to support more keys or put the add and remove code in the default block to support the full keyboard. How’s that for under 75 lines of code?

If you want to enhance this page please add descriptive comments to the code itself or post comments, additions, and feedback below. This isn’t a perfect solution, but it’s easy to implement and separates key capturing from processing.

–AlainODea


That’s wonderful for simple keyboard handling, but it needs some work for more complex keyboard use.

Specifically, this doesn’t cover state-dependent processing of keys or the order of key processing. I do like your use of a mutable set and key detection, however, that would work well paired with a more capable key processor.

I’ve got a rough idea of how this might be designed. We will need:

*CCDKeyEventDispatcher - Handles the dispatching of a single or multiple key events in the same way. This simply contains the keys we want to respond to and a way to dispatch the event. You could make this an abstract class, with subclasses that dispatch via selector or notification. This is essentially a slightly modified version of the Command DesignPattern.

*CCDKeyProcessor - Our processor (could be a singleton), based on the State DesignPattern. This will hold the set of keys down (key events notify or call the key processor rather than manipulating the set directly). It will also set up the timer and process the keys down at the appropriate interval. The processor will also keep a dictionary of mutable collections of CCDKeyEventDispatchers, keyed by a user-defined string.

So, here’s how it works:

So, what do you think? Is this too complex, not complex enough, or just right?

– AndrewBowman


Andrew, that’s a very good point about my solution losing the key ordering and thus losing an important aspect of key state. From my brief review of your suggestion it seems to be quite sophisticated. My goal in mashing-up the solution I did was to enable people to support very simple keyboard support for games needing to supporting many keys down at once (up and left arrows for example) assuming a one to one relationship of keys to actions. What you are describing sounds like a key dispatcher for keyboard shortcuts in a windowed UI. More than what I need, but perhaps essential in more sophisticated scenarios.

–AlainODea