-
Notifications
You must be signed in to change notification settings - Fork 834
fix: macOS window close and quit shortcuts #22134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements macOS standard keyboard shortcuts (Command+W to close windows and Command+Q to quit the application) for the Uno Platform's Skia.MacOS runtime. The implementation addresses issue #22032 by adding both menu-based shortcuts and custom keyboard event handling to ensure these shortcuts work consistently across different application configurations.
Key changes:
- Adds default application menu with Command+W (Close Window) and Command+Q (Quit) menu items when no menu exists
- Implements custom
performKeyEquivalent:method in UNOWindow to handle keyboard shortcuts directly - Refactors the
applicationShouldTerminate:delegate method for improved code clarity
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/Uno.UI.Runtime.Skia.MacOS/UnoNativeMac/UnoNativeMac/UNOApplication.m |
Creates default menu with Command+W and Command+Q shortcuts when mainMenu is nil; refactors terminate callback logic |
src/Uno.UI.Runtime.Skia.MacOS/UnoNativeMac/UnoNativeMac/UNOWindow.m |
Adds performKeyEquivalent method to handle Command+W (close) and Command+Q (quit) keyboard shortcuts |
src/Uno.UI.Runtime.Skia.MacOS/UnoNativeMac/UnoNativeMac/UNOWindow.h |
Adds performKeyEquivalent method declaration to the UNOWindow interface |
| if (app.mainMenu == nil) { | ||
| NSMenu *mainMenu = [[NSMenu alloc] init]; | ||
|
|
||
| // App menu | ||
| NSMenuItem *appMenuItem = [[NSMenuItem alloc] init]; | ||
| NSMenu *appMenu = [[NSMenu alloc] init]; | ||
|
|
||
| // Quit menu item with Command+Q | ||
| NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:@"Quit" | ||
| action:@selector(terminate:) | ||
| keyEquivalent:@"q"]; | ||
| [appMenu addItem:quitMenuItem]; | ||
| [appMenuItem setSubmenu:appMenu]; | ||
| [mainMenu addItem:appMenuItem]; | ||
|
|
||
| // File menu | ||
| NSMenuItem *fileMenuItem = [[NSMenuItem alloc] initWithTitle:@"File" action:nil keyEquivalent:@""]; | ||
| NSMenu *fileMenu = [[NSMenu alloc] initWithTitle:@"File"]; | ||
|
|
||
| // Close window menu item with Command+W | ||
| NSMenuItem *closeMenuItem = [[NSMenuItem alloc] initWithTitle:@"Close Window" | ||
| action:@selector(performClose:) | ||
| keyEquivalent:@"w"]; | ||
| [fileMenu addItem:closeMenuItem]; | ||
| [fileMenuItem setSubmenu:fileMenu]; | ||
| [mainMenu addItem:fileMenuItem]; | ||
|
|
||
| [app setMainMenu:mainMenu]; | ||
| #if DEBUG | ||
| NSLog(@"uno_app_initialize: Created default menu with Command+Q and Command+W shortcuts"); | ||
| #endif | ||
| } |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The menu creation logic creates a duplicate handling mechanism for keyboard shortcuts. The menu items define Command+W and Command+Q with keyEquivalent properties, but the performKeyEquivalent method in UNOWindow.m also handles these same shortcuts directly. This creates two separate code paths for the same functionality, which can lead to maintenance issues.
Consider removing the redundant performKeyEquivalent implementation in UNOWindow.m and relying solely on the menu system to handle these shortcuts. macOS will automatically route menu keyboard equivalents to their associated actions (performClose: and terminate:) without requiring manual event handling.
| if (!uno_get_application_can_exit_callback()()) { | ||
| return NSTerminateCancel; | ||
| } | ||
|
|
||
| return NSTerminateNow; |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The refactoring of applicationShouldTerminate is functionally equivalent to the original ternary expression but more verbose. The original code was clear and concise. The new version with early return for NSTerminateCancel followed by returning NSTerminateNow adds lines without improving readability or functionality.
Consider reverting to the original ternary expression format as it was more concise and equally readable.
| if (!uno_get_application_can_exit_callback()()) { | |
| return NSTerminateCancel; | |
| } | |
| return NSTerminateNow; | |
| return uno_get_application_can_exit_callback()() ? NSTerminateNow : NSTerminateCancel; |
| - (BOOL)performKeyEquivalent:(NSEvent *)event { | ||
| // Handle Command+W (close window) and Command+Q (quit app) | ||
| if ([event type] == NSEventTypeKeyDown && ([event modifierFlags] & NSEventModifierFlagCommand)) { | ||
| NSString *characters = [event charactersIgnoringModifiers]; | ||
|
|
||
| // Command+W - Close window | ||
| if ([characters isEqualToString:@"w"]) { | ||
| #if DEBUG | ||
| NSLog(@"UNOWindow %p performKeyEquivalent Command+W", self); | ||
| #endif | ||
| [self performClose:self]; | ||
| return YES; | ||
| } | ||
|
|
||
| // Command+Q - Quit application | ||
| if ([characters isEqualToString:@"q"]) { | ||
| #if DEBUG | ||
| NSLog(@"UNOWindow %p performKeyEquivalent Command+Q", self); | ||
| #endif | ||
| [[NSApplication sharedApplication] terminate:self]; | ||
| return YES; | ||
| } | ||
| } | ||
|
|
||
| return [super performKeyEquivalent:event]; | ||
| } |
Copilot
AI
Dec 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The performKeyEquivalent implementation may intercept keyboard shortcuts before they reach the menu system, potentially bypassing menu validation and delegate methods. When both a menu item with a keyEquivalent and a custom performKeyEquivalent handler exist for the same shortcut, the custom handler in the window takes precedence, which can cause inconsistent behavior.
If the menu approach doesn't work in all scenarios (e.g., when no menu is present), consider documenting why both mechanisms are needed, or ensure the menu creation is mandatory rather than conditional on app.mainMenu == nil.
|
π€ Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-22134/wasm-skia-net9/index.html |
|
π€ Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-22134/docs/index.html |
GitHub Issue: #22032
PR Type:
PR Checklist β
Please check if your PR fulfills the following requirements:
Screenshots Compare Test Runresults.