tags:

views:

808

answers:

4

Hi,

I'm new to Mac programming, so I hope this isn't obvious.

In short, I don't seem to be getting multiple key pressed events. I've created this snippet, which never fires an assert, and therefore never prints multiple keys. I get single key prints, though.

- (void)keyDown:(NSEvent *) theEvent {
    NSString *characters = [theEvent characters];
    assert([characters length]<2);
    for (int i=0;i<[characters length];++i) {
      NSLog(@"k=[%d]\n", [characters characterAtIndex:i]);
    }
  }

Does anyone know what I'm doing wrong? In case you're interested, I need multiple key presses for an OpenGL viewing application. Perhaps I am just completely off the mark for this sort of application.

Edit: After further research, I found this: http://www.cocoadev.com/index.pl?GameKeyBoardHandling This makes sense based on the discussion here, in that only the last key repeats. When a keyDown event is thrown, the down key is placed in set and removed on keyUp. This means the set has the complete set of currently held-down keys, avoiding the only-repeats-last-held issue. It's 'good enough', so I'm using this method now. It seems to work well, and because it uses the standard keyboard event system (rather than HID), there shouldn't be any compatibility issues.

Regards, Shane

A: 

I don't believe that you can receive multiple keys at one time under normal circumstances. keyDown is only called when a key is pressed and (I don't think that) two keys can be pressed at exactly the same time; however, a single keypress may generate more than one character according to the Apple docs on NSEvent. My best guess is that multiple characters refer to UNICODE code points except that NSString is a UNICODE sequence so I can't see how you could generate more than one character except by creating your own event.

Modifier keys are a different story however. If you are looking for the modifier keys, then you need something like:

if ([event modifiers] & NSShiftKeyMask) {
    ...
}
D.Shawley
“My best guess is that multiple characters refer to UNICODE code points except that NSString is a UNICODE sequence so I can't see how you could generate more than one character except by creating your own event.” First, it's Unicode, not UNICODE. Second, `unichar` is two bytes; one `unichar` can only hold one UTF-16 code unit. Outside of the Basic Multilingual Plane (that is, above U+FFFF), a character must be represented as two unichars forming a surrogate pair.
Peter Hosey
Ok, but I should at least get repeated key-down events, for each held key. Please see the answer below for more info on what I mean.
Shane
You mean Jon Steinmetz's answer. (Order is not fixed and can change with voting.)
Peter Hosey
A: 

One thing is that you are testing the number of characters in the event which is almost always 1. The most common way to get more than 1 character in an event is when using an IME input method for non western characters.

It is unclear what you are trying to accomplish. If you are trying to react to the user pressing and holding a key you will get multiple keyDown: events. Calling isARepeat on the first event will return NO, on subsequent events it will return YES.

If you are trying to detect multiple key presses at the same time then you need to keep track of the key states yourself between keyDown: and keyUp:. So if you pressed f and g at the same time you would get one keyDown or more keyDown: with f and one or more keyDown: with g. then if you released f while still holding g your would get a keyUp: for f while continuing to receive keyDown: for g. You can set a flag for each key you get and then clear the flag when the key goes up.

If neither of these is what you are trying to do then you might want to explain what you are doing further.

Jon Steinmetz
Ok, so if I get one NSEvent per distinct key-down, then why don't I get repeating keyDown events per held-down key? For instance, if I hold down 'a', wait, then hold down 's', then I should see separate repeating KeyDown events being fired for both keys, yes? What seems to happen is I get only the latest held-down key. Here is a debug log of what I mean (from the code I posted). If I press and hold 'a' (97), then wait, and press and hold 's' (115), you see the 97 repeating stops, and 115 only repeats. Can only one key repeat at a time?"k=[97]k=[97]k=[97]k=[115]k=[115]k=[115]"
Shane
That's correct. Try it in a text view: aoooooooo. Only the most-recently-held-down character key repeats.
Peter Hosey
Ah bummer. When I've written keyboard handlers myself in the past (video game engines) I repeat whatever is held down, which seems natural for me. It's good to know it's only the last in this case.Looks like I'll have to go the HID path.
Shane
A: 

Each NSEvent represents just that: One event. When a key goes down, that's one event. When another key goes down, that's another event.

The characters string is just that: a text string. It's what you would insert into your text storage if you were doing that manually. It does not tell you which character keys were pressed; that's the job of the key codes. For modifier keys, it's the job of the modifierFlags bit-mask.

If you're writing a game, you may find either DDHIDLib or the new HID API in Leopard more useful. Also, remember that the user may have multiple keyboards, so it is possible for the user(s) to press two space bars, for example.

Finally, please test your program with Dvorak. Many applications that try to handle raw keyboard events get it wrong and end up confusing us or even not working at all for us. Flash has a long-standing problem of ignoring keys that are punctuation in QWERTY even when they're letter keys in the active layout (true of several keys in Dvorak). And we're not the only ones who don't use QWERTY; many non-English keyboards deviate from the QWERTY layout.

Peter Hosey
I will take a look at DDHIDLib, that looks interesting. I wonder what GLUT for OS X does... In any case, all I am trying to do is get the current status of various keys, regardless of how many are held down, so I can control my OpenGL view.
Shane
It looks like GLUT for Mac is using the HID libraries:http://developer.apple.com/samplecode/glut/listing106.htmlInteresting.
Shane
“… all I am trying to do is get the current status of various keys…” Sounds like you definitely want the HID, then.
Peter Hosey
Yep, I agree. :)
Shane
A: 

I have posted the answer to my question in the actual question body, but in short I found this: http://www.cocoadev.com/index.pl?GameKeyBoardHandling which works well.

Shane