Question

I have been trying to create an app for Cocoa without a nib/xib (No, I don't want to use a nib/xib. I want to be in full control programatically) and I can't seem to be able to catch the Events such as keystrokes and mouse clicks. Here is the code I have so far:

Main.m

#import <Cocoa/Cocoa.h>
#import "AppDelegate.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        NSApplication *app = [NSApplication sharedApplication];

        AppDelegate *appDelegate = [[AppDelegate alloc] init];

        [app setDelegate:appDelegate];
        [app activateIgnoringOtherApps:YES];
        [app run];
    }
    return EXIT_SUCCESS;
}

AppDelegate.h/m

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>
{
    NSWindow *window;
}

@end

#import "AppDelegate.h"
#import "GLView.h"

@implementation AppDelegate

- (id)init{
    self = [super init];
    if (!self) {
        return nil;
    }

    NSRect bounds = [[NSScreen mainScreen] frame];

    GLView *view = [[GLView alloc]initWithFrame:bounds];

    window = [[NSWindow alloc] initWithContentRect:bounds 
                               styleMask:NSBorderlessWindowMask
                               backing:NSBackingStoreBuffered 
                               defer:NO];
    [window setReleasedWhenClosed:YES];
    [window setAcceptsMouseMovedEvents:YES];
    [window setContentView:view];

    return self;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [window makeKeyAndOrderFront:self];
}

@end

GLView.h/m

#import <Cocoa/Cocoa.h>

@interface GLView : NSView

@end

#import "GLView.h"

@implementation GLView

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
    }

    return self;
}

- (void)drawRect:(NSRect)dirtyRect
{
    // Drawing code here.
}

- (BOOL)canBecomeKeyView
{
    return  YES;
}

- (BOOL)acceptsFirstResponder
{
    return YES;
}

- (BOOL)becomeFirstResponder
{
    return YES;
}

- (BOOL)resignFirstResponder
{
    return YES;
}

- (void)keyDown:(NSEvent *)theEvent
{
    NSString*   const   character   =   [theEvent charactersIgnoringModifiers];
    unichar     const   code        =   [character characterAtIndex:0];

    NSLog(@"Key Down: %hu", code);

    switch (code)
    {
        case 27:
        {
            EXIT_SUCCESS;
            break;
        }
    }
}

- (void)keyUp:(NSEvent *)theEvent
{

}
@end

Nothing I have tried for it has worked. I thought that by setting the view as the first responder I would be able to get the events. So far... Not working. Any ideas on how I can fix this? Remember, NO NIB.

Thanks, Tyler

Was it helpful?

Solution

First, you need to make sure that your window can actually become key, by subclassing and returning YES from canBecomeKeyWindow, because windows without title bars cannot become key by default.

Next, your build target needs to be an application. I would guess that you're starting from the Command-Line Tool template in Xcode. This is fine, but you need to produce an application bundle in order for your app to recieve key events. Create a new target in your project that will build a Cocoa Application. It needs to have an Info.plist file (from which you'll want to delete the "Main nib file base class" entry) and have a "Copy Bundle Resources" Build Phase.

I can't quite figure out what all the other differences are in the build process, but starting from your code, I got the window to accept key events with these two steps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top