@@ -9,6 +9,7 @@ import { CoreMouseAction, CoreMouseButton, CoreMouseEventType, ICoreMouseEvent,
99import { C0 } from 'common/data/EscapeSequences' ;
1010import { toDisposable } from 'common/Lifecycle' ;
1111import { ICoreBrowserService , IMouseCoordsService , IMouseService , IMouseServiceTarget , IRenderService , ISelectionService } from './Services' ;
12+ import { Gesture , EventType as GestureEventType , IGestureEvent } from 'browser/scrollable/touch' ;
1213
1314type RequestedMouseEvents = Record < 'mouseup' | 'wheel' | 'mousedrag' | 'mousemove' , EventListener | null > ;
1415
@@ -23,6 +24,7 @@ export class MouseService implements IMouseService {
2324
2425 private _lastEvent : ICoreMouseEvent | null = null ;
2526 private _wheelPartialScroll : number = 0 ;
27+ private _touchScrollAccumulator : number = 0 ;
2628
2729 constructor (
2830 @IRenderService private readonly _renderService : IRenderService ,
@@ -82,6 +84,9 @@ export class MouseService implements IMouseService {
8284 */
8385 register ( addDisposableListener ( element , 'mousedown' , ( ev : MouseEvent ) => this . _handleMouseDown ( ctx , ev ) ) ) ;
8486 register ( addDisposableListener ( element , 'wheel' , ( ev : WheelEvent ) => this . _handlePassiveWheel ( ctx , ev ) , { passive : false } ) ) ;
87+ register ( Gesture . addTarget ( target . screenElement ) ) ;
88+ register ( addDisposableListener ( target . screenElement , GestureEventType . START , ( ) => this . _handleTouchStart ( ) ) ) ;
89+ register ( addDisposableListener ( target . screenElement , GestureEventType . CHANGE , ( e : IGestureEvent ) => this . _handleTouchChange ( ctx , e ) ) ) ;
8590 }
8691
8792 private _sendEvent ( ctx : IMouseBindContext , ev : MouseEvent | WheelEvent ) : boolean {
@@ -264,9 +269,88 @@ export class MouseService implements IMouseService {
264269 }
265270 }
266271
272+ private _handleTouchStart ( ) : void {
273+ this . _touchScrollAccumulator = 0 ;
274+ }
275+
276+ private _handleTouchChange ( ctx : IMouseBindContext , e : IGestureEvent ) : void {
277+ e . preventDefault ( ) ;
278+ e . stopPropagation ( ) ;
279+
280+ // When mouse protocol has wheel events active, send as mouse wheel events.
281+ if ( ctx . requestedEvents . wheel ) {
282+ this . _handleTouchScrollAsWheel ( ctx , e ) ;
283+ return ;
284+ }
285+
286+ // When in alt buffer (no scrollback), send up/down key sequences.
287+ if ( ! this . _bufferService . buffer . hasScrollback ) {
288+ this . _handleTouchScrollAsKeys ( e ) ;
289+ return ;
290+ }
291+
292+ // Normal scrollback: delegate to viewport scrolling when available.
293+ ctx . target . handleTouchScroll ?.( e . translationY ) ;
294+ }
295+
296+ private _handleTouchScrollAsKeys ( e : IGestureEvent ) : void {
297+ const cellHeight = this . _renderService ?. dimensions . css . cell . height ;
298+ if ( ! cellHeight ) {
299+ return ;
300+ }
301+
302+ this . _touchScrollAccumulator -= e . translationY ;
303+ const lines = Math . trunc ( this . _touchScrollAccumulator / cellHeight ) ;
304+ if ( lines === 0 ) {
305+ return ;
306+ }
307+
308+ this . _touchScrollAccumulator -= lines * cellHeight ;
309+ const sequence = C0 . ESC
310+ + ( this . _coreService . decPrivateModes . applicationCursorKeys ? 'O' : '[' )
311+ + ( lines < 0 ? 'A' : 'B' ) ;
312+ for ( let i = 0 ; i < Math . abs ( lines ) ; i ++ ) {
313+ this . _coreService . triggerDataEvent ( sequence , true ) ;
314+ }
315+ }
316+
317+ private _handleTouchScrollAsWheel ( ctx : IMouseBindContext , e : IGestureEvent ) : void {
318+ const cellHeight = this . _renderService ?. dimensions . css . cell . height ;
319+ if ( ! cellHeight ) {
320+ return ;
321+ }
322+
323+ this . _touchScrollAccumulator -= e . translationY ;
324+ const lines = Math . trunc ( this . _touchScrollAccumulator / cellHeight ) ;
325+ if ( lines === 0 ) {
326+ return ;
327+ }
328+
329+ this . _touchScrollAccumulator -= lines * cellHeight ;
330+ const pos = this . _mouseCoordsService . getMouseReportCoords ( e , ctx . target . screenElement ) ;
331+ if ( ! pos ) {
332+ return ;
333+ }
334+
335+ for ( let i = 0 ; i < Math . abs ( lines ) ; i ++ ) {
336+ this . _triggerMouseEvent ( {
337+ col : pos . col ,
338+ row : pos . row ,
339+ x : pos . x ,
340+ y : pos . y ,
341+ button : CoreMouseButton . WHEEL ,
342+ action : lines < 0 ? CoreMouseAction . UP : CoreMouseAction . DOWN ,
343+ ctrl : false ,
344+ alt : false ,
345+ shift : false
346+ } ) ;
347+ }
348+ }
349+
267350 public reset ( ) : void {
268351 this . _lastEvent = null ;
269352 this . _wheelPartialScroll = 0 ;
353+ this . _touchScrollAccumulator = 0 ;
270354 }
271355
272356 private _handleProtocolChange ( ctx : IMouseBindContext , eventListeners : Record < 'mouseup' | 'wheel' | 'mousedrag' | 'mousemove' , EventListener > , events : CoreMouseEventType ) : void {
0 commit comments