Selecting the first item in a popUpContextMenu
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];
I have found an answer to my original question. However it has problems and I think _NSGetCarbonMenu()
is necessary to fix them.
- PROBLEM: how does one draw the menu item so it looks like a native menu item?
- 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];
For the record, if you are targeting 10.6 and later, don't use the class method popUpContextMenu
, use the instance's popUpMenuPositioningItem:atLocation:inView:
.
If you specify positioningItem
it will be selected automatically. Of course, you will need to recalculate location relative to the selected item.
精彩评论