diff --git a/lib/input-handler.ts b/lib/input-handler.ts index 83d6f3f..dc90249 100644 --- a/lib/input-handler.ts +++ b/lib/input-handler.ts @@ -894,6 +894,29 @@ export class InputHandler { if (this.isDisposed) return; if (!this.mouseConfig?.hasMouseTracking()) return; + this.sendWheelMouseEvent(event); + + // Prevent default scrolling when mouse tracking is active + event.preventDefault(); + } + + /** + * Send a wheel event as a mouse tracking sequence. + * Public so that Terminal can forward wheel events when mouse tracking is + * active (the Terminal-level capture handler stops propagation to prevent + * browser scrolling, so this method allows explicit forwarding). + */ + handleWheelEvent(event: WheelEvent): void { + if (this.isDisposed) return; + + this.sendWheelMouseEvent(event); + } + + /** + * Encode and send a wheel event as a mouse tracking escape sequence. + * Button 64 = scroll up, button 65 = scroll down, with cell coordinates. + */ + private sendWheelMouseEvent(event: WheelEvent): void { const cell = this.pixelToCell(event); if (!cell) return; @@ -901,9 +924,6 @@ export class InputHandler { const button = event.deltaY < 0 ? 64 : 65; this.sendMouseEvent(button, cell.col, cell.row, false, event); - - // Prevent default scrolling when mouse tracking is active - event.preventDefault(); } /** diff --git a/lib/terminal.ts b/lib/terminal.ts index eeb7acd..1d685e9 100644 --- a/lib/terminal.ts +++ b/lib/terminal.ts @@ -1552,6 +1552,20 @@ export class Terminal implements ITerminalCore { return; } + // When mouse tracking is active, the application wants to receive mouse + // wheel events with coordinates so it can determine which pane/zone the + // cursor is over (critical for TUIs with multiple scroll regions like + // tmux, vim splits, etc.). Delegate to the InputHandler which sends + // proper SGR/X10 mouse sequences with the cell position. + if (this.wasmTerm?.hasMouseTracking()) { + // InputHandler.handleWheel is registered on the same container but in + // the bubbling phase. Since we already called stopPropagation() above + // (to prevent the browser from scrolling the page), we need to forward + // the event explicitly. + this.inputHandler?.handleWheelEvent(e); + return; + } + // Check if in alternate screen mode (vim, less, htop, etc.) const isAltScreen = this.wasmTerm?.isAlternateScreen() ?? false;