Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ export function useRecordHotkeys(
}

const defaultKey = HOTKEYS[recordingId].key;
if (canonicalizeChord(captured) === canonicalizeChord(defaultKey)) {
if (
defaultKey &&
canonicalizeChord(captured) === canonicalizeChord(defaultKey)
) {
resetOverride(recordingId);
} else {
setOverride(recordingId, captured);
Expand Down
46 changes: 18 additions & 28 deletions apps/desktop/src/renderer/hotkeys/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,22 +102,16 @@ export const HOTKEYS_REGISTRY = {
category: "Workspace",
},
PREV_WORKSPACE: {
key: {
mac: "meta+alt+up",
windows: "ctrl+shift+alt+up",
linux: "ctrl+shift+alt+up",
},
key: { mac: null, windows: null, linux: null },
label: "Previous Workspace",
category: "Workspace",
description: "Navigate to the previous workspace in the sidebar",
},
NEXT_WORKSPACE: {
key: {
mac: "meta+alt+down",
windows: "ctrl+shift+alt+down",
linux: "ctrl+shift+alt+down",
},
key: { mac: null, windows: null, linux: null },
label: "Next Workspace",
category: "Workspace",
description: "Navigate to the next workspace in the sidebar",
},
CLOSE_WORKSPACE: {
key: {
Expand Down Expand Up @@ -334,24 +328,6 @@ export const HOTKEYS_REGISTRY = {
category: "Terminal",
description: "Scroll the active terminal to the bottom",
},
PREV_TAB: {
key: {
mac: "meta+alt+left",
windows: "ctrl+shift+alt+left",
linux: "ctrl+shift+alt+left",
},
label: "Previous Tab",
category: "Terminal",
},
NEXT_TAB: {
key: {
mac: "meta+alt+right",
windows: "ctrl+shift+alt+right",
linux: "ctrl+shift+alt+right",
},
label: "Next Tab",
category: "Terminal",
},
PREV_TAB_ALT: {
key: {
mac: "ctrl+shift+tab",
Expand All @@ -366,6 +342,20 @@ export const HOTKEYS_REGISTRY = {
label: "Next Tab (Alt)",
category: "Terminal",
},
PREV_TAB: {
key: { mac: null, windows: null, linux: null },
label: "Previous Tab",
category: "Terminal",
description: "Focus the previous tab in the active workspace",
},
NEXT_TAB: {
key: { mac: null, windows: null, linux: null },
label: "Next Tab",
category: "Terminal",
description: "Focus the next tab in the active workspace",
},
// FORK NOTE: upstream renamed PREV_PANE → FOCUS_PANE_LEFT in #3403 (PR#3).
// Keep PREV_PANE until that cherry-pick is applied.
PREV_PANE: {
key: {
mac: "meta+shift+left",
Expand Down
8 changes: 6 additions & 2 deletions apps/desktop/src/renderer/hotkeys/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
export type Platform = "mac" | "windows" | "linux";

export type PlatformKey = { mac: string; windows: string; linux: string };
export type PlatformKey = {
mac: string | null;
windows: string | null;
linux: string | null;
};

export type HotkeyCategory =
| "Navigation"
Expand All @@ -19,7 +23,7 @@ export interface HotkeyDisplay {
}

export interface HotkeyDefinition {
key: string;
key: string | null;
label: string;
category: HotkeyCategory;
description?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { HOTKEYS } from "../registry";
import { HOTKEYS, type HotkeyId } from "../registry";
import { useHotkeyOverridesStore } from "../stores/hotkeyOverridesStore";
import type { HotkeyDefinition } from "../types";
import {
canonicalizeChord,
eventToChord,
Expand Down Expand Up @@ -148,10 +149,13 @@ describe("resolveHotkeyFromEvent — live override index", () => {
});

// Resolve once so registry reorders / removals surface as a test failure
// here instead of silently skipping the cases below.
const sampleEntry = (
Object.entries(HOTKEYS) as [keyof typeof HOTKEYS, { key: string }][]
).find(([, hotkey]) => !!hotkey.key);
// here instead of silently skipping the cases below. The type predicate
// narrows to a HotkeyDefinition whose .key is guaranteed non-null after
// the filter, so sampleDef.key can be passed to string-only helpers below.
const sampleEntry = Object.entries(HOTKEYS).find(
(entry): entry is [HotkeyId, HotkeyDefinition & { key: string }] =>
entry[1].key !== null,
);
if (!sampleEntry) throw new Error("HOTKEYS has no bound default");
const [sampleId, sampleDef] = sampleEntry;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export function useDashboardSidebarShortcuts(
useHotkey("JUMP_TO_WORKSPACE_8", () => switchToWorkspace(7));
useHotkey("JUMP_TO_WORKSPACE_9", () => switchToWorkspace(8));

// Prev/next workspace navigation (cycles)
const matchRoute = useMatchRoute();
const currentWorkspaceMatch = matchRoute({
to: "/v2-workspace/$workspaceId",
Expand All @@ -62,6 +61,7 @@ export function useDashboardSidebarShortcuts(
const index = flattenedWorkspaces.findIndex(
(w) => w.id === currentWorkspaceId,
);
if (index === -1) return;
const prevIndex = index <= 0 ? flattenedWorkspaces.length - 1 : index - 1;
navigateToV2Workspace(flattenedWorkspaces[prevIndex].id, navigate);
});
Expand All @@ -71,8 +71,8 @@ export function useDashboardSidebarShortcuts(
const index = flattenedWorkspaces.findIndex(
(w) => w.id === currentWorkspaceId,
);
const nextIndex =
index >= flattenedWorkspaces.length - 1 || index === -1 ? 0 : index + 1;
if (index === -1) return;
const nextIndex = index >= flattenedWorkspaces.length - 1 ? 0 : index + 1;
navigateToV2Workspace(flattenedWorkspaces[nextIndex].id, navigate);
});

Expand Down
Loading