55 forceTerminalSelectionModifier ,
66 shouldForceBrowserTerminalSelection ,
77 shouldForceTerminalSelectionContext ,
8+ shouldLetBrowserHandleTerminalCopyShortcut ,
89 type TerminalCopyInteractionTerminal ,
10+ type TerminalCopyKeyboardEvent ,
911 type TerminalMouseTrackingMode ,
1012 writeTerminalSelectionToClipboardData
1113} from "../../src/web/terminal-copy-interaction.js"
@@ -27,6 +29,26 @@ const terminalWithSelection = (
2729 modes : { mouseTrackingMode }
2830} )
2931
32+ const keyboardEvent = (
33+ key : string ,
34+ options : Partial < Pick < TerminalCopyKeyboardEvent , "altKey" | "ctrlKey" | "metaKey" | "type" > > = { }
35+ ) : TerminalCopyKeyboardEvent => ( {
36+ altKey : options . altKey ?? false ,
37+ ctrlKey : options . ctrlKey ?? false ,
38+ key,
39+ metaKey : options . metaKey ?? false ,
40+ type : options . type ?? "keydown"
41+ } )
42+
43+ const requireKeyHandler = (
44+ keyHandler : ( ( event : TerminalCopyKeyboardEvent ) => boolean ) | null
45+ ) : ( event : TerminalCopyKeyboardEvent ) => boolean => {
46+ if ( keyHandler === null ) {
47+ return expect . fail ( "Expected terminal copy key handler to be registered." )
48+ }
49+ return keyHandler
50+ }
51+
3052describe ( "terminal copy interaction" , ( ) => {
3153 it ( "forces browser selection for primary mouse input while terminal mouse tracking is active" , ( ) => {
3254 expect ( shouldForceBrowserTerminalSelection ( { button : 0 } , terminalWithSelection ( "any" , "" ) ) ) . toBe ( true )
@@ -42,6 +64,49 @@ describe("terminal copy interaction", () => {
4264 expect ( shouldForceTerminalSelectionContext ( { button : 0 } , terminalWithSelection ( "any" , "selected" ) ) ) . toBe ( false )
4365 } )
4466
67+ it ( "lets browser copy handle Ctrl/Cmd+C only for selected terminal text" , ( ) => {
68+ const selectedTerminal = terminalWithSelection ( "any" , "selected" )
69+ const emptyTerminal = terminalWithSelection ( "any" , "" )
70+
71+ expect ( shouldLetBrowserHandleTerminalCopyShortcut ( keyboardEvent ( "c" , { ctrlKey : true } ) , selectedTerminal ) )
72+ . toBe ( true )
73+ expect ( shouldLetBrowserHandleTerminalCopyShortcut ( keyboardEvent ( "C" , { metaKey : true } ) , selectedTerminal ) )
74+ . toBe ( true )
75+ expect ( shouldLetBrowserHandleTerminalCopyShortcut ( keyboardEvent ( "c" , { ctrlKey : true } ) , emptyTerminal ) )
76+ . toBe ( false )
77+ expect (
78+ shouldLetBrowserHandleTerminalCopyShortcut ( keyboardEvent ( "c" , { altKey : true , ctrlKey : true } ) , selectedTerminal )
79+ )
80+ . toBe ( false )
81+ expect ( shouldLetBrowserHandleTerminalCopyShortcut ( keyboardEvent ( "v" , { ctrlKey : true } ) , selectedTerminal ) )
82+ . toBe ( false )
83+ expect (
84+ shouldLetBrowserHandleTerminalCopyShortcut ( keyboardEvent ( "c" , { ctrlKey : true , type : "keyup" } ) , selectedTerminal )
85+ ) . toBe ( false )
86+ } )
87+
88+ it ( "registers a custom key handler that bypasses xterm input for selected text copy" , ( ) => {
89+ let keyHandler : ( ( event : TerminalCopyKeyboardEvent ) => boolean ) | null = null
90+ const terminal : TerminalCopyInteractionTerminal = {
91+ attachCustomKeyEventHandler : ( handler ) => {
92+ keyHandler = handler
93+ } ,
94+ getSelection : ( ) => "selected" ,
95+ hasSelection : ( ) => true ,
96+ modes : { mouseTrackingMode : "none" }
97+ }
98+ const host = new FakeTerminalCopyHost ( null )
99+
100+ const disposable = attachTerminalCopyInteraction ( { host, terminal } )
101+ const handleKey = requireKeyHandler ( keyHandler )
102+
103+ expect ( handleKey ( keyboardEvent ( "c" , { ctrlKey : true } ) ) ) . toBe ( false )
104+ expect ( handleKey ( keyboardEvent ( "c" , { ctrlKey : true , type : "keyup" } ) ) ) . toBe ( true )
105+ expect ( handleKey ( keyboardEvent ( "c" ) ) ) . toBe ( true )
106+
107+ disposable . dispose ( )
108+ } )
109+
45110 it ( "uses Shift as the forced selection modifier on non-Mac platforms" , ( ) => {
46111 const event = { altKey : false , shiftKey : false }
47112
0 commit comments