@@ -79,38 +79,52 @@ function getActionShortcutsAsKeys(
7979 modifierNames : Record < string , string > ,
8080) : string [ ] [ ] {
8181 const shortcuts = ShortcutRegistry . registry . getKeyCodesByShortcutName ( action ) ;
82+ if ( shortcuts . length === 0 ) {
83+ return [ ] ;
84+ }
8285 // See ShortcutRegistry.createSerializedKey for the starting format.
83- const named = shortcuts . map ( ( shortcut ) => {
84- return shortcut
85- . split ( '+' )
86- . map ( ( maybeNumeric ) => keyNames [ maybeNumeric ] ?? maybeNumeric )
87- . map ( ( k ) => upperCaseFirst ( modifierNames [ k ] ?? k ) ) ;
88- } ) ;
86+ const shortcutsAsParts = shortcuts . map ( ( shortcut ) => shortcut . split ( '+' ) ) ;
87+
88+ // Prefer e.g. Cmd+Shift to Shift+Cmd.
89+ shortcutsAsParts . forEach ( ( s ) =>
90+ s . sort ( ( a , b ) => {
91+ const aValue = modifierOrder ( a ) ;
92+ const bValue = modifierOrder ( b ) ;
93+ return aValue - bValue ;
94+ } ) ,
95+ ) ;
8996
90- const command = modifierNames [ 'Meta' ] ;
91- const option = modifierNames [ 'Alt' ] ;
92- const control = modifierNames [ 'Control' ] ;
9397 // Needed to prefer Command to Option where we've bound Alt.
94- named . sort ( ( a , b ) => {
95- const aValue = a . includes ( command ) ? 1 : 0 ;
96- const bValue = b . includes ( command ) ? 1 : 0 ;
98+ shortcutsAsParts . sort ( ( a , b ) => {
99+ const aValue = a . includes ( 'Meta' ) ? 1 : 0 ;
100+ const bValue = b . includes ( 'Meta' ) ? 1 : 0 ;
97101 return bValue - aValue ;
98102 } ) ;
99- let currentPlatform = named . filter ( ( shortcut ) => {
100- const isMacShortcut =
101- shortcut . includes ( command ) || shortcut . includes ( option ) ;
103+ let currentPlatform = shortcutsAsParts . filter ( ( shortcut ) => {
104+ const isMacShortcut = shortcut . includes ( 'Meta' ) ;
102105 return isMacShortcut === isMacPlatform ;
103106 } ) ;
104- currentPlatform = currentPlatform . length === 0 ? named : currentPlatform ;
107+ currentPlatform =
108+ currentPlatform . length === 0 ? shortcutsAsParts : currentPlatform ;
109+
110+ // Prefer simpler shortcuts. This promotes Ctrl+Y for redo.
111+ currentPlatform . sort ( ( a , b ) => {
112+ return a . length - b . length ;
113+ } ) ;
105114
106115 // If there are modifiers return only one shortcut on the assumption they are
107116 // intended for different platforms. Otherwise assume they are alternatives.
108117 const hasModifiers = currentPlatform . some ( ( shortcut ) =>
109118 shortcut . some (
110- ( key ) => command === key || option === key || control === key ,
119+ ( key ) => 'Meta' === key || 'Alt' === key || 'Control' === key ,
111120 ) ,
112121 ) ;
113- return hasModifiers ? [ currentPlatform [ 0 ] ] : currentPlatform ;
122+ const chosen = hasModifiers ? [ currentPlatform [ 0 ] ] : currentPlatform ;
123+ return chosen . map ( ( shortcut ) => {
124+ return shortcut
125+ . map ( ( maybeNumeric ) => keyNames [ maybeNumeric ] ?? maybeNumeric )
126+ . map ( ( k ) => upperCaseFirst ( modifierNames [ k ] ?? k ) ) ;
127+ } ) ;
114128}
115129
116130/**
@@ -122,3 +136,14 @@ function getActionShortcutsAsKeys(
122136export function upperCaseFirst ( str : string ) {
123137 return str . charAt ( 0 ) . toUpperCase ( ) + str . substring ( 1 ) ;
124138}
139+
140+ /**
141+ * Preferred listing order of untranslated modifiers.
142+ */
143+ const modifierOrdering : string [ ] = [ 'Meta' , 'Control' , 'Alt' , 'Shift' ] ;
144+
145+ function modifierOrder ( key : string ) : number {
146+ const order = modifierOrdering . indexOf ( key ) ;
147+ // Regular keys at the end.
148+ return order === - 1 ? Number . MAX_VALUE : order ;
149+ }
0 commit comments