views:

34

answers:

1

I work on a very keyboard intensive application. Both hands on the keyboard. No hands on the mouse.

A user can, via the keyboard, popup a context menu, select an item and finally hit enter.

[NSMenu popUpContextMenu] displays the menu without highlighting any item. The user will have to press arrow_down one time in order to highlight the first item.

A friend of mine observed that you have to press arrow_down every time you use this menu and suggested that I removed this step, so that the first item is always highlighted when the menu is popuped.

I suspect it requires a carbon hack?

How can one programmatically highlight the first item?


I use this code to popup a menu.

NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined
    location:location 
    modifierFlags:0 
    timestamp:0
    windowNumber:[[self window] windowNumber]
    context:[[self window] graphicsContext]
    subtype:100
    data1:0
    data2:0
];
[NSMenu popUpContextMenu:menu withEvent:event forView:self];

update: I have tried sending my app an arrow_down event right after the popUpContextMenu, however the event isn't executed when the menu is visible. (The event is executed after the menu is gone).

unichar code = NSDownArrowFunctionKey;
NSString* chars = [NSString stringWithFormat: @"%C", code];
NSEvent* event = [NSEvent keyEventWithType:NSKeyDown location:location modifierFlags:0 timestamp:0 windowNumber:[[self window] windowNumber] context:[[self window] graphicsContext] characters:chars charactersIgnoringModifiers:chars isARepeat:NO keyCode:code];
[NSApp sendEvent:event];
A: 

I have found an answer to my original question. However it has problems and I think _NSGetCarbonMenu() is necessary to fix them.

  1. PROBLEM: how does one draw the menu item so it looks like a native menu item?
  2. PROBLEM: how does one make the custom view behave as an ordinary menuitem.. right now you have to press arrow_down two times to get the next item selected.

How to fix these issues?

@interface MyMenuItem : NSView {
    BOOL m_active;
}
@end

@implementation MyMenuItem
- (BOOL)acceptsFirstResponder { return YES; }
- (BOOL)becomeFirstResponder { m_active = YES; return YES; }
- (BOOL)resignFirstResponder { m_active = NO; return YES; }

- (void)viewDidMoveToWindow { [[self window] makeFirstResponder:self]; }

- (void)drawRect:(NSRect)rect {
    if(m_active) {
        [[NSColor blueColor] set];
    } else {
        [[NSColor blackColor] set];
    }
    NSRectFill(rect);
}
@end


// this makes sure the first item gets selected when the menu popups
MyMenuItem* view = [[[MyMenuItem alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)] autorelease];
[view setAutoresizingMask:NSViewWidthSizable];
NSMenuItem* item = [menu itemAtIndex:0];
[item setView:view];
[NSMenu popUpContextMenu:menu withEvent:event forView:self];

SOLVED IT!!! Forget all the stuff above. I have just found an elegant solution that doesn't require Carbon at all.

// simulate a key press of the arrow-down key
CGKeyCode key_code = 125;  // kVK_DownArrow = 125
CGEventRef event1, event2;
event1 = CGEventCreateKeyboardEvent(NULL, key_code, YES);
event2 = CGEventCreateKeyboardEvent(NULL, key_code, NO);
CGEventPost(kCGSessionEventTap, event1);
CGEventPost(kCGSessionEventTap, event2);
CFRelease(event1);
CFRelease(event2);

[NSMenu popUpContextMenu:menu withEvent:event forView:self];
neoneye