Skip to content

Commit 42aa296

Browse files
fix: use normal shortcut modifier order and prefer shorter shortcuts (#666)
Behaviour changes: - Sort modifiers so we don't say Shift+Cmd+Z for redo on Mac - Ctrl+Y is the preferred redo shortcut on Windows and not all apps support the more cross-platform Ctrl+Shift+Z Implementation change: - Map to user-facing key names last to keep earlier modifier logic using the shortcut registry representation of the modifiers. This the same point we do translations of modifiers in the equivalent code in MakeCode. Fixes #647
1 parent dc22173 commit 42aa296

File tree

1 file changed

+43
-18
lines changed

1 file changed

+43
-18
lines changed

src/shortcut_formatting.ts

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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(
122136
export 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

Comments
 (0)