Skip to content

Commit 014e0cc

Browse files
authored
🤖 Allow interrupt (Ctrl+C) in ChatInput when no text selected (#405)
## Problem Currently, `Ctrl+C` (or `Cmd+C` on Mac) to interrupt the stream only works when focus is outside editable elements. This means users cannot interrupt while ChatInput is focused, requiring them to click elsewhere first. ## Solution Modified the interrupt handler in `useAIViewKeybinds` to check for text selection: - **No selection** → Interrupt stream (allows interrupting from ChatInput) - **Has selection** → Browser handles copy (preserves existing behavior) The logic now allows interrupt in editable elements as long as there's no active text selection, preventing conflict with the copy keybind. ## Changes - Updated `useAIViewKeybinds.ts` interrupt handler to check `window.getSelection()` - When in editable element with no selection: prevent default and interrupt - When in editable element with selection: let browser handle copy ## Testing Manual testing scenarios: - ChatInput focused, no selection, Ctrl+C → should interrupt ✅ - ChatInput focused, text selected, Ctrl+C → should copy text ✅ - Other input focused, no selection, Ctrl+C → should interrupt ✅ - Not in input, Ctrl+C → should interrupt ✅ _Generated with `cmux`_
1 parent 4c70f5b commit 014e0cc

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

src/hooks/useAIViewKeybinds.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,32 @@ export function useAIViewKeybinds({
6767
}
6868

6969
// Normal stream interrupt (non-compaction)
70-
// Don't intercept if user is typing in an input field
71-
if (!isEditableElement(e.target) && (canInterrupt || showRetryBarrier)) {
70+
// Allow interrupt in editable elements if there's no text selection
71+
// This way Ctrl+C works for both copy (when text is selected) and interrupt (when not)
72+
const inEditableElement = isEditableElement(e.target);
73+
let hasSelection = false;
74+
75+
if (inEditableElement) {
76+
// For input/textarea elements, check selectionStart/selectionEnd
77+
// (window.getSelection() doesn't work for form elements)
78+
const target = e.target as HTMLInputElement | HTMLTextAreaElement;
79+
hasSelection =
80+
typeof target.selectionStart === "number" &&
81+
typeof target.selectionEnd === "number" &&
82+
target.selectionStart !== target.selectionEnd;
83+
} else {
84+
// For contentEditable and other elements, use window.getSelection()
85+
hasSelection = (window.getSelection()?.toString().length ?? 0) > 0;
86+
}
87+
88+
if ((canInterrupt || showRetryBarrier) && (!inEditableElement || !hasSelection)) {
7289
e.preventDefault();
7390
setAutoRetry(false); // User explicitly stopped - don't auto-retry
7491
void window.api.workspace.interruptStream(workspaceId);
7592
return;
7693
}
7794

78-
// Let browser handle Ctrl+C (copy) in editable elements
95+
// Let browser handle Ctrl+C (copy) when there's a selection
7996
return;
8097
}
8198

0 commit comments

Comments
 (0)