@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
77import { isMacintosh , language } from 'vs/base/common/platform' ;
88import { IEnvironmentService } from 'vs/platform/environment/common/environment' ;
99import { app , shell , Menu , MenuItem , BrowserWindow } from 'electron' ;
10- import { OpenContext , IRunActionInWindowRequest , getTitleBarStyle } from 'vs/platform/windows/common/windows' ;
10+ import { OpenContext , IRunActionInWindowRequest , getTitleBarStyle , IRunKeybindingInWindowRequest } from 'vs/platform/windows/common/windows' ;
1111import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
1212import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry' ;
1313import { IUpdateService , StateType } from 'vs/platform/update/common/update' ;
@@ -31,6 +31,15 @@ interface IMenuItemClickHandler {
3131 inNoWindow : ( ) => void ;
3232}
3333
34+ type IMenuItemInvocation = (
35+ { type : 'commandId' ; commandId : string ; }
36+ | { type : 'keybinding' ; userSettingsLabel : string ; }
37+ ) ;
38+
39+ interface IMenuItemWithKeybinding {
40+ userSettingsLabel ?: string ;
41+ }
42+
3443export class Menubar {
3544
3645 private static readonly MAX_MENU_RECENT_ENTRIES = 10 ;
@@ -621,17 +630,49 @@ export class Menubar {
621630 }
622631 }
623632
633+ private static _menuItemIsTriggeredViaKeybinding ( event : Electron . Event , userSettingsLabel : string ) : boolean {
634+ // The event coming in from Electron will inform us only about the modifier keys pressed.
635+ // The strategy here is to check if the modifier keys match those of the keybinding,
636+ // since it is highly unlikely to use modifier keys when clicking with the mouse
637+ if ( ! userSettingsLabel ) {
638+ // There is no keybinding
639+ return false ;
640+ }
641+
642+ let ctrlRequired = / c t r l / . test ( userSettingsLabel ) ;
643+ let shiftRequired = / s h i f t / . test ( userSettingsLabel ) ;
644+ let altRequired = / a l t / . test ( userSettingsLabel ) ;
645+ let metaRequired = / c m d / . test ( userSettingsLabel ) || / s u p e r / . test ( userSettingsLabel ) ;
646+
647+ if ( ! ctrlRequired && ! shiftRequired && ! altRequired && ! metaRequired ) {
648+ // This keybinding does not use any modifier keys, so we cannot use this heuristic
649+ return false ;
650+ }
651+
652+ return (
653+ ctrlRequired === event . ctrlKey
654+ && shiftRequired === event . shiftKey
655+ && altRequired === event . altKey
656+ && metaRequired === event . metaKey
657+ ) ;
658+ }
659+
624660 private createMenuItem ( label : string , commandId : string | string [ ] , enabled ?: boolean , checked ?: boolean ) : Electron . MenuItem ;
625661 private createMenuItem ( label : string , click : ( ) => void , enabled ?: boolean , checked ?: boolean ) : Electron . MenuItem ;
626662 private createMenuItem ( arg1 : string , arg2 : any , arg3 ?: boolean , arg4 ?: boolean ) : Electron . MenuItem {
627663 const label = this . mnemonicLabel ( arg1 ) ;
628- const click : ( ) => void = ( typeof arg2 === 'function' ) ? arg2 : ( menuItem : Electron . MenuItem , win : Electron . BrowserWindow , event : Electron . Event ) => {
664+ const click : ( ) => void = ( typeof arg2 === 'function' ) ? arg2 : ( menuItem : Electron . MenuItem & IMenuItemWithKeybinding , win : Electron . BrowserWindow , event : Electron . Event ) => {
665+ const userSettingsLabel = menuItem . userSettingsLabel ;
629666 let commandId = arg2 ;
630667 if ( Array . isArray ( arg2 ) ) {
631668 commandId = this . isOptionClick ( event ) ? arg2 [ 1 ] : arg2 [ 0 ] ; // support alternative action if we got multiple action Ids and the option key was pressed while invoking
632669 }
633670
634- this . runActionInRenderer ( commandId ) ;
671+ if ( isMacintosh && userSettingsLabel && Menubar . _menuItemIsTriggeredViaKeybinding ( event , userSettingsLabel ) ) {
672+ this . runActionInRenderer ( { type : 'keybinding' , userSettingsLabel } ) ;
673+ } else {
674+ this . runActionInRenderer ( { type : 'commandId' , commandId } ) ;
675+ }
635676 } ;
636677 const enabled = typeof arg3 === 'boolean' ? arg3 : this . windowsMainService . getWindowCount ( ) > 0 ;
637678 const checked = typeof arg4 === 'boolean' ? arg4 : false ;
@@ -704,7 +745,7 @@ export class Menubar {
704745 } ;
705746 }
706747
707- private runActionInRenderer ( id : string ) : void {
748+ private runActionInRenderer ( invocation : IMenuItemInvocation ) : void {
708749 // We make sure to not run actions when the window has no focus, this helps
709750 // for https://github.com/Microsoft/vscode/issues/25907 and specifically for
710751 // https://github.com/Microsoft/vscode/issues/11928
@@ -719,18 +760,21 @@ export class Menubar {
719760 }
720761
721762 if ( activeWindow ) {
722- if ( ! activeWindow . isReady && isMacintosh && id === 'workbench.action.toggleDevTools' && ! this . environmentService . isBuilt ) {
723- // prevent this action from running twice on macOS (https://github.com/Microsoft/vscode/issues/62719)
724- // we already register a keybinding in bootstrap-window.js for opening developer tools in case something
725- // goes wrong and that keybinding is only removed when the application has loaded (= window ready).
726- return ;
763+ if ( invocation . type === 'commandId' ) {
764+ if ( ! activeWindow . isReady && isMacintosh && invocation . commandId === 'workbench.action.toggleDevTools' && ! this . environmentService . isBuilt ) {
765+ // prevent this action from running twice on macOS (https://github.com/Microsoft/vscode/issues/62719)
766+ // we already register a keybinding in bootstrap-window.js for opening developer tools in case something
767+ // goes wrong and that keybinding is only removed when the application has loaded (= window ready).
768+ return ;
769+ }
770+ this . windowsMainService . sendToFocused ( 'vscode:runAction' , { id : invocation . commandId , from : 'menu' } as IRunActionInWindowRequest ) ;
771+ } else {
772+ this . windowsMainService . sendToFocused ( 'vscode:runKeybinding' , { userSettingsLabel : invocation . userSettingsLabel } as IRunKeybindingInWindowRequest ) ;
727773 }
728-
729- this . windowsMainService . sendToFocused ( 'vscode:runAction' , { id, from : 'menu' } as IRunActionInWindowRequest ) ;
730774 }
731775 }
732776
733- private withKeybinding ( commandId : string | undefined , options : Electron . MenuItemConstructorOptions ) : Electron . MenuItemConstructorOptions {
777+ private withKeybinding ( commandId : string | undefined , options : Electron . MenuItemConstructorOptions & IMenuItemWithKeybinding ) : Electron . MenuItemConstructorOptions {
734778 const binding = typeof commandId === 'string' ? this . keybindings [ commandId ] : undefined ;
735779
736780 // Apply binding if there is one
@@ -739,6 +783,7 @@ export class Menubar {
739783 // if the binding is native, we can just apply it
740784 if ( binding . isNative !== false ) {
741785 options . accelerator = binding . label ;
786+ options . userSettingsLabel = binding . userSettingsLabel ;
742787 }
743788
744789 // the keybinding is not native so we cannot show it as part of the accelerator of
@@ -768,6 +813,7 @@ export class Menubar {
768813
769814 const originalClick = options . click ;
770815 options . click = ( item , window , event ) => {
816+ console . log ( `444444` ) ;
771817 this . reportMenuActionTelemetry ( commandId ) ;
772818 if ( originalClick ) {
773819 originalClick ( item , window , event ) ;
0 commit comments