CocoaDev

Edit AllPages

I provide an alternate solution I believe to be much easier at GameKeyBoardHandling. –AlainODea —-

I’ve seen a lot of discussions on how to do proper game-like handling of the keyboard in cocoa apps. Most of the answers involve writing your own app-loop or using some scary Carbon level stuff, involving turning off keyboard repeat and other things which I’d rather not delve into.

What I’ve figured out is a way, in cocoa, to make ~90% “Good Enough” game keyboard handling, where you can have multiple keypresses simultaneously ( as in, Left + Up at same time ) and handling of shift, ctrl, option and command keys independently.

The reason I say it’s only ~90% complete, is because handling of the Command key isn’t quite right. If you hold command and then press and release an arrow key, the keyUp operation is never called. Baffling. As far as I can tell every other combination works ( as in Shift, Ctrl, Opt ) Perhaps somebody can add some code below to fix the problem.

Here’s the header for GameView, which in your game might better be derived from NSOpenGLView or some more appropriate for games.

There’s a small problem with using this code which arises when the user depresses a key with shift held down, releases the shift key and then releases the held-down key. The key recorded as being pressed and the key recorded as being released differ, leading to your game believing the key has not been released.

This can be fixed by storing the key returned by [self translateKeyCode: key] in an array indexed by [theEvent keyCode] in keyDown, and then using that array indexed [theEvent keyCode] to provide the key that is released in keyUp, this ensures that the key released is always the same as the key depressed.

That explains behavioral oddities I had, but didn’t consider worth fixing. Care to provide a fix? My best guess ATM is to have translateKeyCode detect if the key was a non-arrow key and simply to convert it to lowercase.

Okay, I fixed up the code using key_pressed_for_keycode to store the translated keypress between press and release, that solves the problem with the shift key being pressed or released while a key is held down. I used these very routines in Oolite ( http://oolite.aegidian.org/ )

AH - 1/5/2005 - Tiger (Mac OS X 10.4) seems to have broken this by intercepting some key events before they are sent to the view.

I’ve long since dropped this for an overidden NSApplication::sendEvent; seems to work fine on tiger –ShamylZakariya


/* Since the Cocoa constants for arrow keys are left shifted by 16, they can’t fit in the bool array. So they’re being defined at the end going inwards. */ enum GameViewKeys { gvArrowKeyUp = 255, gvArrowKeyDown = 254, gvArrowKeyLeft = 253, gvArrowKeyRight = 252 };

@interface GameView : NSView { BOOL keys[256]; // FIX : store key pressed for a particular keycode int key_pressed_for_keycode[256]; BOOL opt, ctrl, command, shift; }

And the definition:

@interface GameView(Internal)

@end

@implementation GameView

/* Capture shift, ctrl, opt and command press & release */

/////////////////////////////////////////////////////////////

/* Turn the Cocoa ArrowKeys into our arrow key constants. */

/////////////////////////////////////////////////////////////

@end

One thing to remember, somewhere you must call something like: [mainWindow makeFirstResponder: gameView];

If you forget, you’ll not receive the key events in the first place.


Usage is simple – it assumes you have a game loop and as such is designed for polling. Each time your loop runs, have a method, for example -(void) pollKeyboard; which looks for the state of certain keys…

I used it in a manner like this:

}

This works well enough for what I’m doing, which isn’t a game, but being a environment/ai simulation does involve chasing robots around so good keyboarding is useful.

Of course, if you’re writing a serious game, you’d probably be using pure Carbon or SDL.

–ShamylZakariya

Why would you? Omni uses Cocoa for their game ports, and they’re definitely serious.

Well, chances are quite good that only the window which houses the game’s graphics, an NSOpenGLView, some sort of event-handling and possibly a preferences window are done in Cocoa. Most likely the original game was C++ or even C code, and converting it all to Objective-C would be too time-consuming (not to mention pointless and taxing on the frame rate).


I’ve run into the same command key oddness when trying to do something similar. Try overiding -sendEvent and passing NSFlagsChanged events to yourself…

I think that way you get a chance to see if it’s up or down before it gets stripped out.


There appears to be a bug in AppKit, where key up events that are pressed while holding the command key don’t get routed to the NSWindow. They do, however, get routed through the NSApplication. Therefore it’s fairly trivial to handle that ourselves.

Add this to your NSApplication subclass:

This will ensure that you get your command key-up’d events. –[[SteveStreza


THANK YOU for this bug fix! I was banging my head at this for hours until I stumbled across this. Why hasn’t this bug been fixed yet? —-


From the developer documentation, as of July 2011:

“NSApplication sends a Control-key event to the key window via performKeyEquivalent: before sending it as an NSKeyDown event through the responder chain.”

You could add something like this to your NSView subclass for it to receive the equivalent of a Cmd-Key press: