@xterm/xterm 6.1.0-beta.183 → 6.1.0-beta.185

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,45 +3,453 @@
3
3
  * @license MIT
4
4
  */
5
5
 
6
- import { getWindow } from 'browser/Dom';
7
- import { ICharSizeService, IRenderService, IMouseService } from './Services';
8
- import { getCoords, getCoordsRelativeToElement } from 'browser/input/Mouse';
6
+ import { addDisposableListener } from 'browser/Dom';
7
+ import { IBufferService, IMouseStateService, ICoreService, ILogService, IOptionsService } from 'common/services/Services';
8
+ import { CoreMouseAction, CoreMouseButton, CoreMouseEventType, ICoreMouseEvent, IDisposable } from 'common/Types';
9
+ import { C0 } from 'common/data/EscapeSequences';
10
+ import { toDisposable } from 'common/Lifecycle';
11
+ import { ICoreBrowserService, IMouseCoordsService, IMouseService, IMouseServiceTarget, IRenderService, ISelectionService } from './Services';
12
+
13
+ type RequestedMouseEvents = Record<'mouseup' | 'wheel' | 'mousedrag' | 'mousemove', EventListener | null>;
14
+
15
+ interface IMouseBindContext {
16
+ readonly target: IMouseServiceTarget;
17
+ readonly focus: () => void;
18
+ readonly requestedEvents: RequestedMouseEvents;
19
+ }
9
20
 
10
21
  export class MouseService implements IMouseService {
11
22
  public serviceBrand: undefined;
12
23
 
24
+ private _lastEvent: ICoreMouseEvent | null = null;
25
+ private _wheelPartialScroll: number = 0;
26
+
13
27
  constructor(
14
28
  @IRenderService private readonly _renderService: IRenderService,
15
- @ICharSizeService private readonly _charSizeService: ICharSizeService
29
+ @IMouseCoordsService private readonly _mouseCoordsService: IMouseCoordsService,
30
+ @IMouseStateService private readonly _mouseStateService: IMouseStateService,
31
+ @ICoreService private readonly _coreService: ICoreService,
32
+ @IBufferService private readonly _bufferService: IBufferService,
33
+ @IOptionsService private readonly _optionsService: IOptionsService,
34
+ @ISelectionService private readonly _selectionService: ISelectionService,
35
+ @ILogService private readonly _logService: ILogService,
36
+ @ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService
16
37
  ) {
17
38
  }
18
39
 
19
- public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined {
20
- return getCoords(
21
- window,
22
- event,
23
- element,
24
- colCount,
25
- rowCount,
26
- this._charSizeService.hasValidSize,
27
- this._renderService.dimensions.css.cell.width,
28
- this._renderService.dimensions.css.cell.height,
29
- isSelection
30
- );
40
+ public bindMouse(target: IMouseServiceTarget, register: (disposable: IDisposable) => void, focus: () => void): void {
41
+ const { element, document } = target;
42
+
43
+ /**
44
+ * Event listener state handling.
45
+ * We listen to the onProtocolChange event of MouseStateService and put
46
+ * requested listeners in `requestedEvents`. With this the listeners
47
+ * have all bits to do the event listener juggling.
48
+ * Note: 'mousedown' currently is "always on" and not managed
49
+ * by onProtocolChange.
50
+ */
51
+ const requestedEvents: RequestedMouseEvents = {
52
+ mouseup: null,
53
+ wheel: null,
54
+ mousedrag: null,
55
+ mousemove: null
56
+ };
57
+ const ctx: IMouseBindContext = { target, focus, requestedEvents };
58
+ const eventListeners: Record<'mouseup' | 'wheel' | 'mousedrag' | 'mousemove', EventListener> = {
59
+ mouseup: (ev: Event) => this._handleMouseUp(ctx, ev as MouseEvent),
60
+ wheel: (ev: Event) => this._handleWheel(ctx, ev as WheelEvent),
61
+ mousedrag: (ev: Event) => this._handleMouseDrag(ctx, ev as MouseEvent),
62
+ mousemove: (ev: Event) => this._handleMouseMove(ctx, ev as MouseEvent)
63
+ };
64
+ register(this._mouseStateService.onProtocolChange(events => {
65
+ this._handleProtocolChange(ctx, eventListeners, events);
66
+ }));
67
+ // force initial onProtocolChange so we dont miss early mouse requests
68
+ this._mouseStateService.activeProtocol = this._mouseStateService.activeProtocol;
69
+
70
+ // Ensure document-level listeners are removed on dispose
71
+ register(toDisposable(() => {
72
+ if (requestedEvents.mouseup) {
73
+ document.removeEventListener('mouseup', requestedEvents.mouseup);
74
+ }
75
+ if (requestedEvents.mousedrag) {
76
+ document.removeEventListener('mousemove', requestedEvents.mousedrag);
77
+ }
78
+ }));
79
+
80
+ /**
81
+ * "Always on" event listeners.
82
+ */
83
+ register(addDisposableListener(element, 'mousedown', (ev: MouseEvent) => this._handleMouseDown(ctx, ev)));
84
+ register(addDisposableListener(element, 'wheel', (ev: WheelEvent) => this._handlePassiveWheel(ctx, ev), { passive: false }));
85
+ }
86
+
87
+ private _sendEvent(ctx: IMouseBindContext, ev: MouseEvent | WheelEvent): boolean {
88
+ // Get mouse coordinates
89
+ const pos = this._mouseCoordsService.getMouseReportCoords(ev as MouseEvent, ctx.target.screenElement);
90
+ if (!pos) {
91
+ return false;
92
+ }
93
+
94
+ let but: CoreMouseButton;
95
+ let action: CoreMouseAction | undefined;
96
+ switch ((ev as MouseEvent & { overrideType?: string }).overrideType || ev.type) {
97
+ case 'mousemove':
98
+ action = CoreMouseAction.MOVE;
99
+ if (ev.buttons === undefined) {
100
+ // buttons is not supported on macOS, try to get a value from button instead
101
+ but = CoreMouseButton.NONE;
102
+ if (ev.button !== undefined) {
103
+ but = ev.button < 3 ? ev.button : CoreMouseButton.NONE;
104
+ }
105
+ } else {
106
+ // according to MDN buttons only reports up to button 5 (AUX2)
107
+ but = ev.buttons & 1 ? CoreMouseButton.LEFT :
108
+ ev.buttons & 4 ? CoreMouseButton.MIDDLE :
109
+ ev.buttons & 2 ? CoreMouseButton.RIGHT :
110
+ CoreMouseButton.NONE; // fallback to NONE
111
+ }
112
+ break;
113
+ case 'mouseup':
114
+ action = CoreMouseAction.UP;
115
+ but = ev.button < 3 ? ev.button : CoreMouseButton.NONE;
116
+ break;
117
+ case 'mousedown':
118
+ action = CoreMouseAction.DOWN;
119
+ but = ev.button < 3 ? ev.button : CoreMouseButton.NONE;
120
+ break;
121
+ case 'wheel':
122
+ if (!this._mouseStateService.allowCustomWheelEvent(ev as WheelEvent)) {
123
+ return false;
124
+ }
125
+ const deltaY = (ev as WheelEvent).deltaY;
126
+ if (deltaY === 0) {
127
+ return false;
128
+ }
129
+ const lines = this._consumeWheelEvent(
130
+ ev as WheelEvent,
131
+ this._renderService?.dimensions?.device?.cell?.height,
132
+ this._coreBrowserService?.dpr
133
+ );
134
+ if (lines === 0) {
135
+ return false;
136
+ }
137
+ action = deltaY < 0 ? CoreMouseAction.UP : CoreMouseAction.DOWN;
138
+ but = CoreMouseButton.WHEEL;
139
+ break;
140
+ default:
141
+ // dont handle other event types by accident
142
+ return false;
143
+ }
144
+
145
+ // exit if we cannot determine valid button/action values
146
+ // do nothing for higher buttons than wheel
147
+ if (action === undefined || but === undefined || but > CoreMouseButton.WHEEL) {
148
+ return false;
149
+ }
150
+
151
+ return this._triggerMouseEvent({
152
+ col: pos.col,
153
+ row: pos.row,
154
+ x: pos.x,
155
+ y: pos.y,
156
+ button: but,
157
+ action,
158
+ ctrl: ev.ctrlKey,
159
+ alt: ev.altKey,
160
+ shift: ev.shiftKey
161
+ });
162
+ }
163
+
164
+ private _handleMouseUp(ctx: IMouseBindContext, ev: MouseEvent): void {
165
+ this._sendEvent(ctx, ev);
166
+ if (!ev.buttons) {
167
+ // if no other button is held remove global handlers
168
+ if (ctx.requestedEvents.mouseup) {
169
+ ctx.target.document.removeEventListener('mouseup', ctx.requestedEvents.mouseup);
170
+ }
171
+ if (ctx.requestedEvents.mousedrag) {
172
+ ctx.target.document.removeEventListener('mousemove', ctx.requestedEvents.mousedrag);
173
+ }
174
+ }
175
+ }
176
+
177
+ private _handleWheel(ctx: IMouseBindContext, ev: WheelEvent): false {
178
+ this._sendEvent(ctx, ev);
179
+ ev.preventDefault();
180
+ ev.stopPropagation();
181
+ return false;
182
+ }
183
+
184
+ private _handleMouseDrag(ctx: IMouseBindContext, ev: MouseEvent): void {
185
+ // deal only with move while a button is held
186
+ if (ev.buttons) {
187
+ this._sendEvent(ctx, ev);
188
+ }
189
+ }
190
+
191
+ private _handleMouseMove(ctx: IMouseBindContext, ev: MouseEvent): void {
192
+ // deal only with move without any button
193
+ if (!ev.buttons) {
194
+ this._sendEvent(ctx, ev);
195
+ }
196
+ }
197
+
198
+ private _handleMouseDown(ctx: IMouseBindContext, ev: MouseEvent): void {
199
+ ev.preventDefault();
200
+ ctx.focus();
201
+
202
+ // Don't send the mouse button to the pty if mouse events are disabled or
203
+ // if the selection manager is having selection forced (ie. a modifier is
204
+ // held).
205
+ if (!this._mouseStateService.areMouseEventsActive || this._selectionService.shouldForceSelection(ev)) {
206
+ return;
207
+ }
208
+
209
+ this._sendEvent(ctx, ev);
210
+
211
+ // Register additional global handlers which should keep reporting outside
212
+ // of the terminal element.
213
+ // Note: Other emulators also do this for 'mousedown' while a button
214
+ // is held, we currently limit 'mousedown' to the terminal only.
215
+ if (ctx.requestedEvents.mouseup) {
216
+ ctx.target.document.addEventListener('mouseup', ctx.requestedEvents.mouseup);
217
+ }
218
+ if (ctx.requestedEvents.mousedrag) {
219
+ ctx.target.document.addEventListener('mousemove', ctx.requestedEvents.mousedrag);
220
+ }
221
+ }
222
+
223
+ private _handlePassiveWheel(ctx: IMouseBindContext, ev: WheelEvent): false | void {
224
+ // do nothing, if app side handles wheel itself
225
+ if (ctx.requestedEvents.wheel) {
226
+ return;
227
+ }
228
+
229
+ if (!this._mouseStateService.allowCustomWheelEvent(ev)) {
230
+ return false;
231
+ }
232
+
233
+ if (!this._bufferService.buffer.hasScrollback) {
234
+ // Convert wheel events into up/down events when the buffer does not have scrollback, this
235
+ // enables scrolling in apps hosted in the alt buffer such as vim or tmux even when mouse
236
+ // events are not enabled.
237
+ // This used implementation used get the actual lines/partial lines scrolled from the
238
+ // viewport but since moving to the new viewport implementation has been simplified to
239
+ // simply send a single up or down sequence.
240
+
241
+ // Do nothing if there's no vertical scroll
242
+ const deltaY = ev.deltaY;
243
+ if (deltaY === 0) {
244
+ return false;
245
+ }
246
+
247
+ const lines = this._consumeWheelEvent(
248
+ ev,
249
+ this._renderService?.dimensions?.device?.cell?.height,
250
+ this._coreBrowserService?.dpr
251
+ );
252
+ if (lines === 0) {
253
+ ev.preventDefault();
254
+ ev.stopPropagation();
255
+ return false;
256
+ }
257
+
258
+ // Construct and send sequences
259
+ const sequence = C0.ESC + (this._coreService.decPrivateModes.applicationCursorKeys ? 'O' : '[') + (ev.deltaY < 0 ? 'A' : 'B');
260
+ this._coreService.triggerDataEvent(sequence, true);
261
+ ev.preventDefault();
262
+ ev.stopPropagation();
263
+ return false;
264
+ }
265
+ }
266
+
267
+ public reset(): void {
268
+ this._lastEvent = null;
269
+ this._wheelPartialScroll = 0;
31
270
  }
32
271
 
33
- public getMouseReportCoords(event: MouseEvent, element: HTMLElement): { col: number, row: number, x: number, y: number } | undefined {
34
- const coords = getCoordsRelativeToElement(getWindow(element), event, element);
35
- if (!this._charSizeService.hasValidSize) {
36
- return undefined;
272
+ private _handleProtocolChange(ctx: IMouseBindContext, eventListeners: Record<'mouseup' | 'wheel' | 'mousedrag' | 'mousemove', EventListener>, events: CoreMouseEventType): void {
273
+ const { element, document } = ctx.target;
274
+ const { requestedEvents } = ctx;
275
+ // apply global changes on events
276
+ if (events) {
277
+ if (this._optionsService.rawOptions.logLevel === 'debug') {
278
+ this._logService.debug('Binding to mouse events:', this._explainEvents(events));
279
+ }
280
+ element.classList.add('enable-mouse-events');
281
+ this._selectionService.disable();
282
+ } else {
283
+ this._logService.debug('Unbinding from mouse events.');
284
+ element.classList.remove('enable-mouse-events');
285
+ this._selectionService.enable();
286
+ }
287
+
288
+ // add/remove handlers from requestedEvents
289
+ if (!(events & CoreMouseEventType.MOVE)) {
290
+ if (requestedEvents.mousemove) {
291
+ element.removeEventListener('mousemove', requestedEvents.mousemove);
292
+ }
293
+ requestedEvents.mousemove = null;
294
+ } else if (!requestedEvents.mousemove) {
295
+ element.addEventListener('mousemove', eventListeners.mousemove);
296
+ requestedEvents.mousemove = eventListeners.mousemove;
297
+ }
298
+
299
+ if (!(events & CoreMouseEventType.WHEEL)) {
300
+ if (requestedEvents.wheel) {
301
+ element.removeEventListener('wheel', requestedEvents.wheel);
302
+ }
303
+ requestedEvents.wheel = null;
304
+ } else if (!requestedEvents.wheel) {
305
+ element.addEventListener('wheel', eventListeners.wheel, { passive: false });
306
+ requestedEvents.wheel = eventListeners.wheel;
307
+ }
308
+
309
+ if (!(events & CoreMouseEventType.UP)) {
310
+ if (requestedEvents.mouseup) {
311
+ document.removeEventListener('mouseup', requestedEvents.mouseup);
312
+ }
313
+ requestedEvents.mouseup = null;
314
+ } else {
315
+ requestedEvents.mouseup ??= eventListeners.mouseup;
37
316
  }
38
- coords[0] = Math.min(Math.max(coords[0], 0), this._renderService.dimensions.css.canvas.width - 1);
39
- coords[1] = Math.min(Math.max(coords[1], 0), this._renderService.dimensions.css.canvas.height - 1);
317
+
318
+ if (!(events & CoreMouseEventType.DRAG)) {
319
+ if (requestedEvents.mousedrag) {
320
+ document.removeEventListener('mousemove', requestedEvents.mousedrag);
321
+ }
322
+ requestedEvents.mousedrag = null;
323
+ } else {
324
+ requestedEvents.mousedrag ??= eventListeners.mousedrag;
325
+ }
326
+ }
327
+
328
+ private _applyScrollModifier(amount: number, ev: WheelEvent): number {
329
+ // Multiply the scroll speed when the modifier key is pressed
330
+ if (ev.altKey || ev.ctrlKey || ev.shiftKey) {
331
+ return amount * this._optionsService.rawOptions.fastScrollSensitivity * this._optionsService.rawOptions.scrollSensitivity;
332
+ }
333
+ return amount * this._optionsService.rawOptions.scrollSensitivity;
334
+ }
335
+
336
+ /**
337
+ * Processes a wheel event, accounting for partial scrolls for trackpad, mouse scrolls.
338
+ * This prevents hyper-sensitive scrolling in alt buffer.
339
+ */
340
+ private _consumeWheelEvent(ev: WheelEvent, cellHeight?: number, dpr?: number): number {
341
+ // Do nothing if it's not a vertical scroll event
342
+ if (ev.deltaY === 0 || ev.shiftKey) {
343
+ return 0;
344
+ }
345
+
346
+ if (cellHeight === undefined || dpr === undefined) {
347
+ return 0;
348
+ }
349
+
350
+ const targetWheelEventPixels = cellHeight / dpr;
351
+ let amount = this._applyScrollModifier(ev.deltaY, ev);
352
+
353
+ if (ev.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
354
+ amount /= (targetWheelEventPixels + 0.0); // Prevent integer division
355
+
356
+ const isLikelyTrackpad = Math.abs(ev.deltaY) < 50;
357
+ if (isLikelyTrackpad) {
358
+ amount *= 0.3;
359
+ }
360
+
361
+ this._wheelPartialScroll += amount;
362
+ amount = Math.floor(Math.abs(this._wheelPartialScroll)) * (this._wheelPartialScroll > 0 ? 1 : -1);
363
+ this._wheelPartialScroll %= 1;
364
+ } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
365
+ amount *= this._bufferService.rows;
366
+ }
367
+ return amount;
368
+ }
369
+
370
+ /**
371
+ * Triggers a mouse event to be sent.
372
+ *
373
+ * Returns true if the event passed all protocol restrictions and a report
374
+ * was sent, otherwise false. The return value may be used to decide whether
375
+ * the default event action in the browser component should be omitted.
376
+ *
377
+ * Note: The method will change values of the given event object
378
+ * to fulfill protocol and encoding restrictions.
379
+ */
380
+ private _triggerMouseEvent(e: ICoreMouseEvent): boolean {
381
+ // range check for col/row
382
+ if (e.col < 0 || e.col >= this._bufferService.cols
383
+ || e.row < 0 || e.row >= this._bufferService.rows) {
384
+ return false;
385
+ }
386
+
387
+ // filter nonsense combinations of button + action
388
+ if (e.button === CoreMouseButton.WHEEL && e.action === CoreMouseAction.MOVE) {
389
+ return false;
390
+ }
391
+ if (e.button === CoreMouseButton.NONE && e.action !== CoreMouseAction.MOVE) {
392
+ return false;
393
+ }
394
+ if (e.button !== CoreMouseButton.WHEEL && (e.action === CoreMouseAction.LEFT || e.action === CoreMouseAction.RIGHT)) {
395
+ return false;
396
+ }
397
+
398
+ // report 1-based coords
399
+ e.col++;
400
+ e.row++;
401
+
402
+ // debounce move events at grid or pixel level
403
+ if (e.action === CoreMouseAction.MOVE
404
+ && this._lastEvent
405
+ && this._equalEvents(this._lastEvent, e, this._mouseStateService.isPixelEncoding)
406
+ ) {
407
+ return false;
408
+ }
409
+
410
+ // apply protocol restrictions
411
+ if (!this._mouseStateService.restrictMouseEvent(e)) {
412
+ return false;
413
+ }
414
+
415
+ // encode report and send
416
+ const report = this._mouseStateService.encodeMouseEvent(e);
417
+ if (report) {
418
+ if (this._mouseStateService.isDefaultEncoding) {
419
+ this._coreService.triggerBinaryEvent(report);
420
+ } else {
421
+ this._coreService.triggerDataEvent(report, true);
422
+ }
423
+ }
424
+
425
+ this._lastEvent = e;
426
+ return true;
427
+ }
428
+
429
+ private _explainEvents(events: CoreMouseEventType): { [event: string]: boolean } {
40
430
  return {
41
- col: Math.floor(coords[0] / this._renderService.dimensions.css.cell.width),
42
- row: Math.floor(coords[1] / this._renderService.dimensions.css.cell.height),
43
- x: Math.floor(coords[0]),
44
- y: Math.floor(coords[1])
431
+ down: !!(events & CoreMouseEventType.DOWN),
432
+ up: !!(events & CoreMouseEventType.UP),
433
+ drag: !!(events & CoreMouseEventType.DRAG),
434
+ move: !!(events & CoreMouseEventType.MOVE),
435
+ wheel: !!(events & CoreMouseEventType.WHEEL)
45
436
  };
46
437
  }
438
+
439
+ private _equalEvents(e1: ICoreMouseEvent, e2: ICoreMouseEvent, pixels: boolean): boolean {
440
+ if (pixels) {
441
+ if (e1.x !== e2.x) return false;
442
+ if (e1.y !== e2.y) return false;
443
+ } else {
444
+ if (e1.col !== e2.col) return false;
445
+ if (e1.row !== e2.row) return false;
446
+ }
447
+ if (e1.button !== e2.button) return false;
448
+ if (e1.action !== e2.action) return false;
449
+ if (e1.ctrl !== e2.ctrl) return false;
450
+ if (e1.alt !== e2.alt) return false;
451
+ if (e1.shift !== e2.shift) return false;
452
+ return true;
453
+ }
454
+
47
455
  }
@@ -8,7 +8,7 @@ import { getCoordsRelativeToElement } from 'browser/input/Mouse';
8
8
  import { moveToCellSequence } from 'browser/input/MoveToCell';
9
9
  import { SelectionModel } from 'browser/selection/SelectionModel';
10
10
  import { ISelectionRedrawRequestEvent, ISelectionRequestScrollLinesEvent } from 'browser/selection/Types';
11
- import { ICoreBrowserService, IMouseService, IRenderService, ISelectionService } from 'browser/services/Services';
11
+ import { ICoreBrowserService, IMouseCoordsService, IRenderService, ISelectionService } from 'browser/services/Services';
12
12
  import { Disposable, toDisposable } from 'common/Lifecycle';
13
13
  import * as Browser from 'common/Platform';
14
14
  import { IBufferLine, ICellData, IDisposable } from 'common/Types';
@@ -126,7 +126,7 @@ export class SelectionService extends Disposable implements ISelectionService {
126
126
  private readonly _linkifier: ILinkifier2,
127
127
  @IBufferService private readonly _bufferService: IBufferService,
128
128
  @ICoreService private readonly _coreService: ICoreService,
129
- @IMouseService private readonly _mouseService: IMouseService,
129
+ @IMouseCoordsService private readonly _mouseCoordsService: IMouseCoordsService,
130
130
  @IOptionsService private readonly _optionsService: IOptionsService,
131
131
  @IRenderService private readonly _renderService: IRenderService,
132
132
  @ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService
@@ -395,7 +395,7 @@ export class SelectionService extends Disposable implements ISelectionService {
395
395
  * @param event The mouse event.
396
396
  */
397
397
  private _getMouseBufferCoords(event: MouseEvent): [number, number] | undefined {
398
- const coords = this._mouseService.getCoords(event, this._screenElement, this._bufferService.cols, this._bufferService.rows, true);
398
+ const coords = this._mouseCoordsService.getCoords(event, this._screenElement, this._bufferService.cols, this._bufferService.rows, true);
399
399
  if (!coords) {
400
400
  return undefined;
401
401
  }
@@ -715,7 +715,7 @@ export class SelectionService extends Disposable implements ISelectionService {
715
715
 
716
716
  if (this.selectionText.length <= 1 && timeElapsed < ALT_CLICK_MOVE_CURSOR_TIME && event.altKey && this._optionsService.rawOptions.altClickMovesCursor) {
717
717
  if (this._bufferService.buffer.ybase === this._bufferService.buffer.ydisp) {
718
- const coordinates = this._mouseService.getCoords(
718
+ const coordinates = this._mouseCoordsService.getCoords(
719
719
  event,
720
720
  this._element,
721
721
  this._bufferService.cols,
@@ -49,14 +49,27 @@ export interface ICoreBrowserService {
49
49
  readonly dpr: number;
50
50
  }
51
51
 
52
- export const IMouseService = createDecorator<IMouseService>('MouseService');
53
- export interface IMouseService {
52
+ export const IMouseCoordsService = createDecorator<IMouseCoordsService>('MouseCoordsService');
53
+ export interface IMouseCoordsService {
54
54
  serviceBrand: undefined;
55
55
 
56
56
  getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined;
57
57
  getMouseReportCoords(event: MouseEvent, element: HTMLElement): { col: number, row: number, x: number, y: number } | undefined;
58
58
  }
59
59
 
60
+ export const IMouseService = createDecorator<IMouseService>('MouseService');
61
+ export interface IMouseService {
62
+ serviceBrand: undefined;
63
+
64
+ bindMouse(target: IMouseServiceTarget, register: (disposable: IDisposable) => void, focus: () => void): void;
65
+ reset(): void;
66
+ }
67
+ export interface IMouseServiceTarget {
68
+ element: HTMLElement;
69
+ screenElement: HTMLElement;
70
+ document: Document;
71
+ }
72
+
60
73
  export const IRenderService = createDecorator<IRenderService>('RenderService');
61
74
  export interface IRenderService extends IDisposable {
62
75
  serviceBrand: undefined;
@@ -21,14 +21,14 @@
21
21
  * http://linux.die.net/man/7/urxvt
22
22
  */
23
23
 
24
- import { IInstantiationService, IOptionsService, IBufferService, ILogService, ICharsetService, ICoreService, ICoreMouseService, IUnicodeService, LogLevelEnum, ITerminalOptions, IOscLinkService } from 'common/services/Services';
24
+ import { IInstantiationService, IOptionsService, IBufferService, ILogService, ICharsetService, ICoreService, IMouseStateService, IUnicodeService, LogLevelEnum, ITerminalOptions, IOscLinkService } from 'common/services/Services';
25
25
  import { InstantiationService } from 'common/services/InstantiationService';
26
26
  import { LogService } from 'common/services/LogService';
27
27
  import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService';
28
28
  import { OptionsService } from 'common/services/OptionsService';
29
29
  import { IDisposable, IAttributeData, ICoreTerminal, IScrollEvent } from 'common/Types';
30
30
  import { CoreService } from 'common/services/CoreService';
31
- import { CoreMouseService } from 'common/services/CoreMouseService';
31
+ import { MouseStateService } from 'common/services/MouseStateService';
32
32
  import { UnicodeService } from 'common/services/UnicodeService';
33
33
  import { CharsetService } from 'common/services/CharsetService';
34
34
  import { updateWindowsModeWrappedState } from 'common/WindowsMode';
@@ -50,7 +50,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
50
50
  protected readonly _charsetService: ICharsetService;
51
51
  protected readonly _oscLinkService: IOscLinkService;
52
52
 
53
- public readonly coreMouseService: ICoreMouseService;
53
+ public readonly mouseStateService: IMouseStateService;
54
54
  public readonly coreService: ICoreService;
55
55
  public readonly unicodeService: IUnicodeService;
56
56
  public readonly optionsService: IOptionsService;
@@ -113,8 +113,8 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
113
113
  this._instantiationService.setService(IBufferService, this._bufferService);
114
114
  this.coreService = this._register(this._instantiationService.createInstance(CoreService));
115
115
  this._instantiationService.setService(ICoreService, this.coreService);
116
- this.coreMouseService = this._register(this._instantiationService.createInstance(CoreMouseService));
117
- this._instantiationService.setService(ICoreMouseService, this.coreMouseService);
116
+ this.mouseStateService = this._register(this._instantiationService.createInstance(MouseStateService));
117
+ this._instantiationService.setService(IMouseStateService, this.mouseStateService);
118
118
  this.unicodeService = this._register(this._instantiationService.createInstance(UnicodeService));
119
119
  this._instantiationService.setService(IUnicodeService, this.unicodeService);
120
120
  this._charsetService = this._instantiationService.createInstance(CharsetService);
@@ -124,7 +124,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
124
124
 
125
125
 
126
126
  // Register input handler and handle/forward events
127
- this._inputHandler = this._register(new InputHandler(this._bufferService, this._charsetService, this.coreService, this._logService, this.optionsService, this._oscLinkService, this.coreMouseService, this.unicodeService));
127
+ this._inputHandler = this._register(new InputHandler(this._bufferService, this._charsetService, this.coreService, this._logService, this.optionsService, this._oscLinkService, this.mouseStateService, this.unicodeService));
128
128
  this._register(EventUtils.forward(this._inputHandler.onLineFeed, this._onLineFeed));
129
129
 
130
130
  // Setup listeners
@@ -256,7 +256,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
256
256
  this._bufferService.reset();
257
257
  this._charsetService.reset();
258
258
  this.coreService.reset();
259
- this.coreMouseService.reset();
259
+ this.mouseStateService.reset();
260
260
  }
261
261
 
262
262