diff --git a/main_sdl.m b/main_sdl.m index db6daf9..93d6606 100644 --- a/main_sdl.m +++ b/main_sdl.m @@ -20,6 +20,12 @@ along with this program. If not, see . */ #include +#include + +@interface DPPCResponder : NSResponder +@end + +static DPPCResponder *dppcResponder; /** @file SDL-specific main function additions for macOS hosts. */ @@ -37,4 +43,55 @@ void remap_appkit_menu_shortcuts(void) { } } } + + // Add a "Grab Mouse" commamand to the Window menu. + NSMenuItem *windowMenuItem = [[NSApp mainMenu] itemWithTitle:@"Window"]; + if (windowMenuItem) { + NSMenu *windowMenu = [windowMenuItem submenu]; + if (windowMenu) { + NSMenuItem *grabMouseMenuItem = [[NSMenuItem alloc] initWithTitle:@"Grab Mouse" + action:@selector(grabMouse:) + keyEquivalent:@"g"]; + [grabMouseMenuItem setKeyEquivalentModifierMask:NSEventModifierFlagControl]; + [windowMenu addItem:grabMouseMenuItem]; + } + } + + // Insert a responder in the chain to handle the command (SDL does not + // expose its NSAppDelegate implementation so we can't subclass it). + dppcResponder = [DPPCResponder new]; + [dppcResponder setNextResponder:[NSApp nextResponder]]; + [NSApp setNextResponder:dppcResponder]; } + +@implementation DPPCResponder + +- (BOOL)validateMenuItem:(NSMenuItem *)menuItem { + if ([menuItem action] == @selector(grabMouse:)) { + [menuItem setState:SDL_GetRelativeMouseMode() ? NSControlStateValueOn : NSControlStateValueOff]; + return YES; + } + return [super validateMenuItem:menuItem]; +} + +- (void)grabMouse:(id)sender { + NSWindow *mainWindow = NSApp.mainWindow; + if (mainWindow) { + // If we're about to grab the mouse, move the mouse to the middle of the + // window so that SDL knows that this window is what we want coordinates + // to be relative to. + if (!SDL_GetRelativeMouseMode()) { + NSRect frame = mainWindow.frame; + NSPoint center = NSMakePoint(frame.size.width/2, frame.size.height/2); + center = [mainWindow convertPointToScreen:center]; + CGWarpMouseCursorPosition(center); + mainWindow.subtitle = @"Mouse grabbed"; + } else { + mainWindow.subtitle = @""; + } + } + + SDL_SetRelativeMouseMode(!SDL_GetRelativeMouseMode()); +} + +@end