Catch keyboard events in a Cocoa + Metal + MetalKit app

I'm writing a 3d game. I started out with an X-Code preset "Game" with MetalKit.

It generated an AppDelegate, a GameController, a Renderer, some shaders, and a MainStory board.

In GameController I've got an MTKView instantiated.

I can catch mouse events in GameController with, for example,

override func mouseMoved() {}

but keyboard events elude me.

I've read that keyboard events should be caught in a view, but overriding them on MTKView did not achive anything.

So how is it done?

Replies

This is one way to do it--set up a monitor. This is what I use to intercept key presses for my typewriter sounds.

This only needs to be called once, say in your app delegate. Ignore the [self playTypewriterSound:?]--these are local functions for playing different sounds. I think you can get the idea from this example.


The keyDownMonitor instance is declared in the interface. I have another function to remove the monitor when it is not needed.


//------------------------------------------------------------------------------------------------

-(void)setupTypewriterSounds {

keyDownMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^(NSEvent *event) {


// filter out anything with a command key press

NSUInteger keyPress = [event modifierFlags];

keyPress = keyPress & (unsigned long)NSEventModifierFlagCommand;

if(keyPress) {

return (NSEvent *)event;

}


// filter out if the window is not key (ie. focus is on preference window, etc.)

if([[NSApplication sharedApplication] isOtherKey]) {

return (NSEvent *)event;

}

// else, make some noise

NSString *chars = [event characters];

unichar character = [chars characterAtIndex: 0];

if ((character > 96 ) && (character < 127)) { // lower case and some punctuation

[self playTypewriterSound:5];

return (NSEvent *)event;

}

if (character == 32 ) { // space

[self playTypewriterSound:2];

return (NSEvent *)event;

}

if ((character > 32 ) && (character < 97)) { // upper case, numbers, some punctuation

[self playTypewriterSound:3];

return (NSEvent *)event;

}

if (character == 13 ) { // enter

[self playTypewriterSound:1];

return (NSEvent *)event;

}

if (character == 127 ) { // delete

[self playTypewriterSound:4];

return (NSEvent *)event;

}

[self playTypewriterSound:4];

return (NSEvent *)event;

}];

}

Thank you for your answer. As I understand you suggest to monitor keyboard events directly and not to override NSView methods.

However, since NSView and by inheritance MTKView have keyboard events methods, aren't we meant to override them?

It seems to me, that building a monitor for handling key ups and downs contradicts Apple's idea of how this should be done.