7

I want to react on hot key press by displaying NSMenu at mouse cursor position.

My application is UIElement and doesn't have its own window.

I know there is method of NSMenu :

-(void)popUpContextMenu:(NSMenu *)menu
              withEvent:(NSEvent *)event
                forView:(NSView *)view;

But it seems it doesn't work when there is no view :(.

Should I create a fake transparent view at mouse cursor position, and then display there NSMenu, or there is better way?

May it can be implemented using Carbon?

ThinkingStiff
  • 64,767
  • 30
  • 146
  • 239
flagman
  • 502
  • 4
  • 18

2 Answers2

22

Use this instead:

  [theMenu popUpMenuPositioningItem:nil atLocation:[NSEvent mouseLocation] inView:nil];
1

Here is solution which uses transparent window:

+ (NSMenu *)defaultMenu {
    NSMenu *theMenu = [[[NSMenu alloc] initWithTitle:@"Contextual Menu"] autorelease];
    [theMenu insertItemWithTitle:@"Beep" action:@selector(beep:) keyEquivalent:@"" atIndex:0];
    [theMenu insertItemWithTitle:@"Honk" action:@selector(honk:) keyEquivalent:@"" atIndex:1];
    return theMenu;
}

- (void) hotkeyWithEvent:(NSEvent *)hkEvent 
{
    NSPoint mouseLocation = [NSEvent mouseLocation];

    // 1. Create transparent window programmatically.

    NSRect frame = NSMakeRect(mouseLocation.x, mouseLocation.y, 200, 200);
    NSWindow* newWindow  = [[NSWindow alloc] initWithContentRect:frame
                                                     styleMask:NSBorderlessWindowMask
                                                       backing:NSBackingStoreBuffered
                                                         defer:NO];
    [newWindow setAlphaValue:0];
    [newWindow makeKeyAndOrderFront:NSApp];

    NSPoint locationInWindow = [newWindow convertScreenToBase: mouseLocation];

    // 2. Construct fake event.

    int eventType = NSLeftMouseDown;

    NSEvent *fakeMouseEvent = [NSEvent mouseEventWithType:eventType 
                                                 location:locationInWindow
                                            modifierFlags:0
                                                timestamp:0
                                             windowNumber:[newWindow windowNumber]
                                                  context:nil
                                              eventNumber:0
                                               clickCount:0
                                                 pressure:0];
    // 3. Pop up menu
    [NSMenu popUpContextMenu:[[self class]defaultMenu] withEvent:fakeMouseEvent forView:[newWindow contentView]];

}

It works, but i'm still looking for more elegant solution.

flagman
  • 502
  • 4
  • 18
  • did you ever find a better solution? –  Feb 17 '13 at 20:47
  • @Wesley Unfortunately not. Still using that in many projects :( – flagman Feb 18 '13 at 06:44
  • 10
    This seems to work a little better? [theMenu popUpMenuPositioningItem:nil atLocation:[NSEvent mouseLocation] inView:nil]; –  Feb 18 '13 at 07:09
  • 1
    Wow :) Looks good and right in the method description. "If view is nil, the location is interpreted in the screen coordinate system. This allows you to pop up a menu disconnected from any window." Thank you. – flagman Feb 18 '13 at 07:33
  • @Wesley **Great** answer! You've saved me so much time... :-) – Dr.Kameleon Aug 23 '13 at 09:04
  • @Wesley Please post this as an answer! I first didn't see your comment, but this is definitely the much better solution. – idmean Apr 18 '14 at 19:32