11export type TerminalQuerySuppression = { readonly dispose : ( ) => void }
22
3+ export type TerminalQuerySuppressionOptions = {
4+ readonly allowMouseTracking ?: boolean
5+ }
6+
37type Disposable = { readonly dispose : ( ) => void }
48
59type FunctionIdentifier = {
@@ -29,26 +33,29 @@ export type TerminalQuerySuppressionTarget = {
2933 }
3034}
3135
32- // DEC private modes whose `h`/`l` setter causes xterm.js to start emitting
33- // unsolicited reply bytes back through `onData` on later DOM events:
34- // 1000/1002/1003/1006/1015/1016 — mouse tracking (mouse events -> bytes)
35- // 1004 — focus reporting (focus/blur -> CSI I/O)
36- // Suppressing the SET (`h`) leaves xterm.js in the default state (no event
37- // emission); suppressing the RESET (`l`) is harmless and kept for symmetry.
36+ // DEC private modes whose `h`/`l` setter can cause xterm.js to emit event bytes
37+ // back through `onData` on later DOM events.
38+ const MOUSE_TRACKING_PRIVATE_MODES : ReadonlySet < number > = new Set ( [
39+ 1000 ,
40+ 1002 ,
41+ 1003 ,
42+ 1006 ,
43+ 1015 ,
44+ 1016
45+ ] )
46+ const FOCUS_REPORTING_PRIVATE_MODE = 1004
47+
48+ // Suppressing SET leaves xterm.js in the default state (no event emission);
49+ // suppressing RESET is harmless and kept for symmetry.
3850// Modes intentionally left to fall through to xterm's built-in handlers:
3951// 25 — cursor visibility
4052// 1049 — alternate screen buffer
4153// 2004 — bracketed paste
4254// 2026 — synchronized output (Ink uses BSU/ESU around every frame)
4355// 1007 — alternate scroll (only changes wheel semantics, no leak)
4456const SUPPRESSED_PRIVATE_MODES : ReadonlySet < number > = new Set ( [
45- 1000 ,
46- 1002 ,
47- 1003 ,
48- 1004 ,
49- 1006 ,
50- 1015 ,
51- 1016
57+ ...MOUSE_TRACKING_PRIVATE_MODES ,
58+ FOCUS_REPORTING_PRIVATE_MODE
5259] )
5360
5461const isColorQuery = ( data : string ) : boolean => {
@@ -68,10 +75,20 @@ const extractParam = (param: CsiParam): number | null => {
6875 return typeof head === "number" ? head : null
6976}
7077
71- const containsSuppressedPrivateMode = ( params : CsiParams ) : boolean => {
78+ const shouldSuppressPrivateMode = (
79+ mode : number ,
80+ options : TerminalQuerySuppressionOptions
81+ ) : boolean =>
82+ mode === FOCUS_REPORTING_PRIVATE_MODE ||
83+ ( options . allowMouseTracking !== true && MOUSE_TRACKING_PRIVATE_MODES . has ( mode ) )
84+
85+ const containsSuppressedPrivateMode = (
86+ params : CsiParams ,
87+ options : TerminalQuerySuppressionOptions
88+ ) : boolean => {
7289 for ( const param of params ) {
7390 const value = extractParam ( param )
74- if ( value !== null && SUPPRESSED_PRIVATE_MODES . has ( value ) ) {
91+ if ( value !== null && shouldSuppressPrivateMode ( value , options ) ) {
7592 return true
7693 }
7794 }
@@ -95,15 +112,17 @@ const registerDcsSuppressor = (
95112
96113const registerSelectivePrivateModeSuppressor = (
97114 terminal : TerminalQuerySuppressionTarget ,
98- final : "h" | "l"
115+ final : "h" | "l" ,
116+ options : TerminalQuerySuppressionOptions
99117) : Disposable =>
100118 terminal . parser . registerCsiHandler (
101119 { final, prefix : "?" } ,
102- ( params ) => containsSuppressedPrivateMode ( params )
120+ ( params ) => containsSuppressedPrivateMode ( params , options )
103121 )
104122
105123export const installTerminalQuerySuppression = (
106- terminal : TerminalQuerySuppressionTarget
124+ terminal : TerminalQuerySuppressionTarget ,
125+ options : TerminalQuerySuppressionOptions = { }
107126) : TerminalQuerySuppression => {
108127 const disposables : ReadonlyArray < Disposable > = [
109128 // OSC 4/10/11/12 — color queries (`?` payload). Set-color payloads fall through.
@@ -132,11 +151,11 @@ export const installTerminalQuerySuppression = (
132151 // CSI Pm t — window manipulation. Gated by `windowOptions` (off by default);
133152 // suppressed so an accidental future enable does not leak size reports.
134153 registerCsiSuppressor ( terminal , { final : "t" } ) ,
135- // CSI ? h / CSI ? l — block xterm from enabling focus reporting and mouse
136- // tracking modes that would later pump unsolicited bytes back through onData .
154+ // CSI ? h / CSI ? l — block xterm from enabling focus reporting and,
155+ // unless explicitly allowed for tmux project terminals, mouse tracking modes .
137156 // Other DEC private modes fall through to xterm's built-in setters.
138- registerSelectivePrivateModeSuppressor ( terminal , "h" ) ,
139- registerSelectivePrivateModeSuppressor ( terminal , "l" )
157+ registerSelectivePrivateModeSuppressor ( terminal , "h" , options ) ,
158+ registerSelectivePrivateModeSuppressor ( terminal , "l" , options )
140159 ]
141160 return {
142161 dispose : ( ) => {
0 commit comments