Allow Backspace in custom keyboard shortcuts (#5224)

Capture modified Backspace shortcuts in the editor while keeping bare Backspace as the erase-last-combo key. Cover the reported Mac chord, its Windows Ctrl equivalent, and the erase behavior in the desktop renderer suite.

Closes #5215

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
paseo-bot[bot]
2026-09-23 22:39:00 +02:00
committed by GitHub
parent e998e0a082
commit fbe5005aa1
2 changed files with 74 additions and 8 deletions
@@ -377,8 +377,7 @@ export function KeyboardShortcutsSection() {
event.preventDefault();
event.stopPropagation();
const key = event.key ?? "";
if (key === "Backspace") {
if (event.code === "Backspace" && heldModifiersFromEvent(event) === null) {
setCapturedCombos((current) => (current.length > 0 ? current.slice(0, -1) : current));
return;
}
@@ -14,10 +14,13 @@ const SHORTCUTS_ROW = "show-shortcuts";
* daemon is left unmanaged so the app talks to the E2E daemon instead of trying
* to start one of its own.
*/
async function installDesktopBridge(page: Page): Promise<void> {
await page.addInitScript(() => {
async function installDesktopBridge(
page: Page,
platform: "darwin" | "win32" = "darwin",
): Promise<void> {
await page.addInitScript((desktopPlatform) => {
window.paseoDesktop = {
platform: "darwin",
platform: desktopPlatform,
events: { on: () => () => {} },
invoke: async (command: string) => {
if (command === "get_desktop_settings") {
@@ -29,11 +32,11 @@ async function installDesktopBridge(page: Page): Promise<void> {
return null;
},
};
});
}, platform);
}
async function openShortcutsSettings(page: Page) {
await installDesktopBridge(page);
async function openShortcutsSettings(page: Page, platform: "darwin" | "win32" = "darwin") {
await installDesktopBridge(page, platform);
await gotoAppShell(page);
await openSettings(page);
await openSettingsSection(page, "shortcuts");
@@ -67,6 +70,38 @@ async function closeRowMenu(page: Page) {
await expect(page.getByTestId(`shortcut-bind-${SHORTCUTS_ROW}`)).toHaveCount(0);
}
async function clearShortcut(page: Page, label: string, action: string) {
await page.getByRole("button", { name: `Actions for ${label}` }).click();
await page.getByTestId(`shortcut-clear-${action}`).click();
}
async function captureShortcut(page: Page, label: string, action: string, keys: string) {
await page.getByRole("button", { name: `Actions for ${label}` }).click();
await page.getByTestId(`shortcut-bind-${action}`).click();
await page.keyboard.press(keys);
}
async function expectInterruptShortcut(page: Page, chord: string) {
const row = page.getByText("Interrupt agent", { exact: true }).locator("..");
await expect(row.getByText(chord, { exact: true })).toBeVisible();
}
async function finishInterruptCapture(page: Page, action: "Done" | "Cancel") {
const row = page.getByText("Interrupt agent", { exact: true }).locator("..");
await row.getByRole("button", { name: action }).click();
}
async function eraseLastCapturedCombo(page: Page, firstCombo: string, secondCombo: string) {
await captureShortcut(page, "Interrupt agent", "agent-interrupt", "Alt+K");
await page.keyboard.press("Alt+J");
await expectInterruptShortcut(page, firstCombo);
await expectInterruptShortcut(page, secondCombo);
await page.keyboard.press("Backspace");
await expectInterruptShortcut(page, firstCombo);
const row = page.getByText("Interrupt agent", { exact: true }).locator("..");
await expect(row.getByText(secondCombo, { exact: true })).toHaveCount(0);
}
test("unassigning a shortcut leaves it inert until it is reset", async ({ page }) => {
await openShortcutsSettings(page);
@@ -146,3 +181,35 @@ test("unassigning a shortcut leaves it inert until it is reset", async ({ page }
await page.keyboard.press("Escape");
await expect(dialog).not.toBeVisible({ timeout: 10_000 });
});
for (const { platform, keys, label, firstCombo, secondCombo } of [
{
platform: "darwin",
keys: "Meta+Shift+Backspace",
label: "⇧⌘⌫",
firstCombo: "⌥K",
secondCombo: "⌥J",
},
{
platform: "win32",
keys: "Control+Shift+Backspace",
label: "Ctrl+Shift+⌫",
firstCombo: "Alt+K",
secondCombo: "Alt+J",
},
] as const) {
test(`binds modified Backspace and erases a combo with bare Backspace on ${platform}`, async ({
page,
}) => {
await openShortcutsSettings(page, platform);
await clearShortcut(page, "Archive workspace", "archive-workspace");
await captureShortcut(page, "Interrupt agent", "agent-interrupt", keys);
await expectInterruptShortcut(page, label);
await finishInterruptCapture(page, "Done");
await expectInterruptShortcut(page, label);
await eraseLastCapturedCombo(page, firstCombo, secondCombo);
await finishInterruptCapture(page, "Cancel");
await expectInterruptShortcut(page, label);
});
}