@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.
- package/lib/xterm.js +1 -1
- package/lib/xterm.js.map +1 -1
- package/lib/xterm.mjs +8 -8
- package/lib/xterm.mjs.map +4 -4
- package/package.json +2 -2
- package/src/browser/CoreBrowserTerminal.ts +16 -280
- package/src/browser/Linkifier.ts +8 -8
- package/src/browser/Viewport.ts +3 -3
- package/src/browser/public/Terminal.ts +1 -1
- package/src/browser/services/MouseCoordsService.ts +47 -0
- package/src/browser/services/MouseService.ts +434 -26
- package/src/browser/services/SelectionService.ts +4 -4
- package/src/browser/services/Services.ts +15 -2
- package/src/common/CoreTerminal.ts +7 -7
- package/src/common/InputHandler.ts +12 -12
- package/src/common/Types.ts +6 -6
- package/src/common/Version.ts +1 -1
- package/src/common/services/{CoreMouseService.ts → MouseStateService.ts} +19 -130
- package/src/common/services/Services.ts +8 -24
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xterm/xterm",
|
|
3
3
|
"description": "Full xterm terminal, in your browser",
|
|
4
|
-
"version": "6.1.0-beta.
|
|
4
|
+
"version": "6.1.0-beta.185",
|
|
5
5
|
"main": "lib/xterm.js",
|
|
6
6
|
"module": "lib/xterm.mjs",
|
|
7
7
|
"style": "css/xterm.css",
|
|
@@ -119,5 +119,5 @@
|
|
|
119
119
|
"ws": "^8.2.3",
|
|
120
120
|
"xterm-benchmark": "^0.3.1"
|
|
121
121
|
},
|
|
122
|
-
"commit": "
|
|
122
|
+
"commit": "89980fc565c178d13588e135f8eb975f44a47712"
|
|
123
123
|
}
|
|
@@ -36,16 +36,17 @@ import { CharSizeService } from 'browser/services/CharSizeService';
|
|
|
36
36
|
import { CharacterJoinerService } from 'browser/services/CharacterJoinerService';
|
|
37
37
|
import { CoreBrowserService } from 'browser/services/CoreBrowserService';
|
|
38
38
|
import { LinkProviderService } from 'browser/services/LinkProviderService';
|
|
39
|
+
import { MouseCoordsService } from 'browser/services/MouseCoordsService';
|
|
39
40
|
import { MouseService } from 'browser/services/MouseService';
|
|
40
41
|
import { RenderService } from 'browser/services/RenderService';
|
|
41
42
|
import { SelectionService } from 'browser/services/SelectionService';
|
|
42
|
-
import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IKeyboardService, ILinkProviderService, IMouseService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services';
|
|
43
|
+
import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IKeyboardService, ILinkProviderService, IMouseCoordsService, IMouseService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services';
|
|
43
44
|
import { ThemeService } from 'browser/services/ThemeService';
|
|
44
45
|
import { KeyboardService } from 'browser/services/KeyboardService';
|
|
45
46
|
import { channels, color, rgb } from 'common/Color';
|
|
46
47
|
import { CoreTerminal } from 'common/CoreTerminal';
|
|
47
48
|
import * as Browser from 'common/Platform';
|
|
48
|
-
import { ColorRequestType,
|
|
49
|
+
import { ColorRequestType, IColorEvent, ITerminalOptions, KeyboardResultType, SpecialColorIndex } from 'common/Types';
|
|
49
50
|
import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
|
|
50
51
|
import { IBuffer } from 'common/buffer/Types';
|
|
51
52
|
import { C0, C1ESCAPED } from 'common/data/EscapeSequences';
|
|
@@ -77,7 +78,6 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|
|
77
78
|
public browser: IBrowser = Browser as any;
|
|
78
79
|
|
|
79
80
|
private _customKeyEventHandler: CustomKeyEventHandler | undefined;
|
|
80
|
-
private _customWheelEventHandler: CustomWheelEventHandler | undefined;
|
|
81
81
|
|
|
82
82
|
// Browser services
|
|
83
83
|
private readonly _decorationService: DecorationService;
|
|
@@ -87,6 +87,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|
|
87
87
|
// Optional browser services
|
|
88
88
|
private _charSizeService: ICharSizeService | undefined;
|
|
89
89
|
private _coreBrowserService: ICoreBrowserService | undefined;
|
|
90
|
+
private _mouseCoordsService: IMouseCoordsService | undefined;
|
|
90
91
|
private _mouseService: IMouseService | undefined;
|
|
91
92
|
private _renderService: IRenderService | undefined;
|
|
92
93
|
private _themeService: IThemeService | undefined;
|
|
@@ -543,8 +544,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|
|
543
544
|
this._compositionHelper = this._instantiationService.createInstance(CompositionHelper, this.textarea, this._compositionView);
|
|
544
545
|
this._helperContainer.appendChild(this._compositionView);
|
|
545
546
|
|
|
546
|
-
this.
|
|
547
|
-
this._instantiationService.setService(
|
|
547
|
+
this._mouseCoordsService = this._instantiationService.createInstance(MouseCoordsService);
|
|
548
|
+
this._instantiationService.setService(IMouseCoordsService, this._mouseCoordsService);
|
|
548
549
|
|
|
549
550
|
const linkifier = this._linkifier.value = this._register(this._instantiationService.createInstance(Linkifier, this.screenElement));
|
|
550
551
|
|
|
@@ -579,6 +580,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|
|
579
580
|
linkifier
|
|
580
581
|
));
|
|
581
582
|
this._instantiationService.setService(ISelectionService, this._selectionService);
|
|
583
|
+
this._mouseService = this._instantiationService.createInstance(MouseService);
|
|
584
|
+
this._instantiationService.setService(IMouseService, this._mouseService);
|
|
582
585
|
this._register(this._selectionService.onRequestScrollLines(e => this.scrollLines(e.amount, e.suppressScrollEvent)));
|
|
583
586
|
this._register(this._selectionService.onSelectionChange(() => this._onSelectionChange.fire()));
|
|
584
587
|
this._register(this._selectionService.onRequestRedraw(e => this._renderService!.handleSelectionChanged(e.start, e.end, e.columnSelectMode)));
|
|
@@ -602,7 +605,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|
|
602
605
|
this._register(addDisposableListener(this.element, 'mousedown', (e: MouseEvent) => this._selectionService!.handleMouseDown(e)));
|
|
603
606
|
|
|
604
607
|
// apply mouse event classes set by escape codes before terminal was attached
|
|
605
|
-
if (this.
|
|
608
|
+
if (this.mouseStateService.areMouseEventsActive) {
|
|
606
609
|
this._selectionService.disable();
|
|
607
610
|
this.element.classList.add('enable-mouse-events');
|
|
608
611
|
} else {
|
|
@@ -638,285 +641,17 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|
|
638
641
|
|
|
639
642
|
// Listen for mouse events and translate
|
|
640
643
|
// them into terminal mouse protocols.
|
|
641
|
-
this.bindMouse(
|
|
644
|
+
this._mouseService.bindMouse({
|
|
645
|
+
element: this.element!,
|
|
646
|
+
screenElement: this.screenElement!,
|
|
647
|
+
document: this._document!
|
|
648
|
+
}, disposable => this._register(disposable), () => this.focus());
|
|
642
649
|
}
|
|
643
650
|
|
|
644
651
|
private _createRenderer(): IRenderer {
|
|
645
652
|
return this._instantiationService.createInstance(DomRenderer, this, this._document!, this.element!, this.screenElement!, this._viewportElement!, this._helperContainer!, this.linkifier!);
|
|
646
653
|
}
|
|
647
654
|
|
|
648
|
-
/**
|
|
649
|
-
* Bind certain mouse events to the terminal.
|
|
650
|
-
* By default only 3 button + wheel up/down is ativated. For higher buttons
|
|
651
|
-
* no mouse report will be created. Typically the standard actions will be active.
|
|
652
|
-
*
|
|
653
|
-
* There are several reasons not to enable support for higher buttons/wheel:
|
|
654
|
-
* - Button 4 and 5 are typically used for history back and forward navigation,
|
|
655
|
-
* there is no straight forward way to supress/intercept those standard actions.
|
|
656
|
-
* - Support for higher buttons does not work in some platform/browser combinations.
|
|
657
|
-
* - Left/right wheel was not tested.
|
|
658
|
-
* - Emulators vary in mouse button support, typically only 3 buttons and
|
|
659
|
-
* wheel up/down work reliable.
|
|
660
|
-
*
|
|
661
|
-
* TODO: Move mouse event code into its own file.
|
|
662
|
-
*/
|
|
663
|
-
public bindMouse(): void {
|
|
664
|
-
const self = this;
|
|
665
|
-
const el = this.element!;
|
|
666
|
-
|
|
667
|
-
// send event to CoreMouseService
|
|
668
|
-
function sendEvent(ev: MouseEvent | WheelEvent): boolean {
|
|
669
|
-
// Get mouse coordinates
|
|
670
|
-
const pos = self._mouseService?.getMouseReportCoords(ev, self.screenElement!);
|
|
671
|
-
if (!pos) {
|
|
672
|
-
return false;
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
let but: CoreMouseButton;
|
|
676
|
-
let action: CoreMouseAction | undefined;
|
|
677
|
-
switch ((ev as any).overrideType || ev.type) {
|
|
678
|
-
case 'mousemove':
|
|
679
|
-
action = CoreMouseAction.MOVE;
|
|
680
|
-
if (ev.buttons === undefined) {
|
|
681
|
-
// buttons is not supported on macOS, try to get a value from button instead
|
|
682
|
-
but = CoreMouseButton.NONE;
|
|
683
|
-
if (ev.button !== undefined) {
|
|
684
|
-
but = ev.button < 3 ? ev.button : CoreMouseButton.NONE;
|
|
685
|
-
}
|
|
686
|
-
} else {
|
|
687
|
-
// according to MDN buttons only reports up to button 5 (AUX2)
|
|
688
|
-
but = ev.buttons & 1 ? CoreMouseButton.LEFT :
|
|
689
|
-
ev.buttons & 4 ? CoreMouseButton.MIDDLE :
|
|
690
|
-
ev.buttons & 2 ? CoreMouseButton.RIGHT :
|
|
691
|
-
CoreMouseButton.NONE; // fallback to NONE
|
|
692
|
-
}
|
|
693
|
-
break;
|
|
694
|
-
case 'mouseup':
|
|
695
|
-
action = CoreMouseAction.UP;
|
|
696
|
-
but = ev.button < 3 ? ev.button : CoreMouseButton.NONE;
|
|
697
|
-
break;
|
|
698
|
-
case 'mousedown':
|
|
699
|
-
action = CoreMouseAction.DOWN;
|
|
700
|
-
but = ev.button < 3 ? ev.button : CoreMouseButton.NONE;
|
|
701
|
-
break;
|
|
702
|
-
case 'wheel':
|
|
703
|
-
if (self._customWheelEventHandler && self._customWheelEventHandler(ev as WheelEvent) === false) {
|
|
704
|
-
return false;
|
|
705
|
-
}
|
|
706
|
-
const deltaY = (ev as WheelEvent).deltaY;
|
|
707
|
-
if (deltaY === 0) {
|
|
708
|
-
return false;
|
|
709
|
-
}
|
|
710
|
-
const lines = self.coreMouseService.consumeWheelEvent(
|
|
711
|
-
ev as WheelEvent,
|
|
712
|
-
self._renderService?.dimensions?.device?.cell?.height,
|
|
713
|
-
self._coreBrowserService?.dpr
|
|
714
|
-
);
|
|
715
|
-
if (lines === 0) {
|
|
716
|
-
return false;
|
|
717
|
-
}
|
|
718
|
-
action = deltaY < 0 ? CoreMouseAction.UP : CoreMouseAction.DOWN;
|
|
719
|
-
but = CoreMouseButton.WHEEL;
|
|
720
|
-
break;
|
|
721
|
-
default:
|
|
722
|
-
// dont handle other event types by accident
|
|
723
|
-
return false;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// exit if we cannot determine valid button/action values
|
|
727
|
-
// do nothing for higher buttons than wheel
|
|
728
|
-
if (action === undefined || but === undefined || but > CoreMouseButton.WHEEL) {
|
|
729
|
-
return false;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
return self.coreMouseService.triggerMouseEvent({
|
|
733
|
-
col: pos.col,
|
|
734
|
-
row: pos.row,
|
|
735
|
-
x: pos.x,
|
|
736
|
-
y: pos.y,
|
|
737
|
-
button: but,
|
|
738
|
-
action,
|
|
739
|
-
ctrl: ev.ctrlKey,
|
|
740
|
-
alt: ev.altKey,
|
|
741
|
-
shift: ev.shiftKey
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
/**
|
|
746
|
-
* Event listener state handling.
|
|
747
|
-
* We listen to the onProtocolChange event of CoreMouseService and put
|
|
748
|
-
* requested listeners in `requestedEvents`. With this the listeners
|
|
749
|
-
* have all bits to do the event listener juggling.
|
|
750
|
-
* Note: 'mousedown' currently is "always on" and not managed
|
|
751
|
-
* by onProtocolChange.
|
|
752
|
-
*/
|
|
753
|
-
const requestedEvents: { [key: string]: ((ev: MouseEvent | WheelEvent) => void) | null } = {
|
|
754
|
-
mouseup: null,
|
|
755
|
-
wheel: null,
|
|
756
|
-
mousedrag: null,
|
|
757
|
-
mousemove: null
|
|
758
|
-
};
|
|
759
|
-
const eventListeners: { [key: string]: (ev: any) => void | boolean } = {
|
|
760
|
-
mouseup: (ev: MouseEvent) => {
|
|
761
|
-
sendEvent(ev);
|
|
762
|
-
if (!ev.buttons) {
|
|
763
|
-
// if no other button is held remove global handlers
|
|
764
|
-
this._document!.removeEventListener('mouseup', requestedEvents.mouseup!);
|
|
765
|
-
if (requestedEvents.mousedrag) {
|
|
766
|
-
this._document!.removeEventListener('mousemove', requestedEvents.mousedrag);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
},
|
|
770
|
-
wheel: (ev: WheelEvent) => {
|
|
771
|
-
sendEvent(ev);
|
|
772
|
-
ev.preventDefault();
|
|
773
|
-
ev.stopPropagation();
|
|
774
|
-
return false;
|
|
775
|
-
},
|
|
776
|
-
mousedrag: (ev: MouseEvent) => {
|
|
777
|
-
// deal only with move while a button is held
|
|
778
|
-
if (ev.buttons) {
|
|
779
|
-
sendEvent(ev);
|
|
780
|
-
}
|
|
781
|
-
},
|
|
782
|
-
mousemove: (ev: MouseEvent) => {
|
|
783
|
-
// deal only with move without any button
|
|
784
|
-
if (!ev.buttons) {
|
|
785
|
-
sendEvent(ev);
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
};
|
|
789
|
-
this._register(this.coreMouseService.onProtocolChange(events => {
|
|
790
|
-
// apply global changes on events
|
|
791
|
-
if (events) {
|
|
792
|
-
if (this.optionsService.rawOptions.logLevel === 'debug') {
|
|
793
|
-
this._logService.debug('Binding to mouse events:', this.coreMouseService.explainEvents(events));
|
|
794
|
-
}
|
|
795
|
-
this.element!.classList.add('enable-mouse-events');
|
|
796
|
-
this._selectionService!.disable();
|
|
797
|
-
} else {
|
|
798
|
-
this._logService.debug('Unbinding from mouse events.');
|
|
799
|
-
this.element!.classList.remove('enable-mouse-events');
|
|
800
|
-
this._selectionService!.enable();
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
// add/remove handlers from requestedEvents
|
|
804
|
-
|
|
805
|
-
if (!(events & CoreMouseEventType.MOVE)) {
|
|
806
|
-
el.removeEventListener('mousemove', requestedEvents.mousemove!);
|
|
807
|
-
requestedEvents.mousemove = null;
|
|
808
|
-
} else if (!requestedEvents.mousemove) {
|
|
809
|
-
el.addEventListener('mousemove', eventListeners.mousemove);
|
|
810
|
-
requestedEvents.mousemove = eventListeners.mousemove;
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
if (!(events & CoreMouseEventType.WHEEL)) {
|
|
814
|
-
el.removeEventListener('wheel', requestedEvents.wheel!);
|
|
815
|
-
requestedEvents.wheel = null;
|
|
816
|
-
} else if (!requestedEvents.wheel) {
|
|
817
|
-
el.addEventListener('wheel', eventListeners.wheel, { passive: false });
|
|
818
|
-
requestedEvents.wheel = eventListeners.wheel;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
if (!(events & CoreMouseEventType.UP)) {
|
|
822
|
-
this._document!.removeEventListener('mouseup', requestedEvents.mouseup!);
|
|
823
|
-
requestedEvents.mouseup = null;
|
|
824
|
-
} else {
|
|
825
|
-
requestedEvents.mouseup ??= eventListeners.mouseup;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
if (!(events & CoreMouseEventType.DRAG)) {
|
|
829
|
-
this._document!.removeEventListener('mousemove', requestedEvents.mousedrag!);
|
|
830
|
-
requestedEvents.mousedrag = null;
|
|
831
|
-
} else {
|
|
832
|
-
requestedEvents.mousedrag ??= eventListeners.mousedrag;
|
|
833
|
-
}
|
|
834
|
-
}));
|
|
835
|
-
// force initial onProtocolChange so we dont miss early mouse requests
|
|
836
|
-
this.coreMouseService.activeProtocol = this.coreMouseService.activeProtocol;
|
|
837
|
-
|
|
838
|
-
// Ensure document-level listeners are removed on dispose
|
|
839
|
-
this._register(toDisposable(() => {
|
|
840
|
-
if (requestedEvents.mouseup) {
|
|
841
|
-
this._document!.removeEventListener('mouseup', requestedEvents.mouseup);
|
|
842
|
-
}
|
|
843
|
-
if (requestedEvents.mousedrag) {
|
|
844
|
-
this._document!.removeEventListener('mousemove', requestedEvents.mousedrag);
|
|
845
|
-
}
|
|
846
|
-
}));
|
|
847
|
-
|
|
848
|
-
/**
|
|
849
|
-
* "Always on" event listeners.
|
|
850
|
-
*/
|
|
851
|
-
this._register(addDisposableListener(el, 'mousedown', (ev: MouseEvent) => {
|
|
852
|
-
ev.preventDefault();
|
|
853
|
-
this.focus();
|
|
854
|
-
|
|
855
|
-
// Don't send the mouse button to the pty if mouse events are disabled or
|
|
856
|
-
// if the selection manager is having selection forced (ie. a modifier is
|
|
857
|
-
// held).
|
|
858
|
-
if (!this.coreMouseService.areMouseEventsActive || this._selectionService!.shouldForceSelection(ev)) {
|
|
859
|
-
return;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
sendEvent(ev);
|
|
863
|
-
|
|
864
|
-
// Register additional global handlers which should keep reporting outside
|
|
865
|
-
// of the terminal element.
|
|
866
|
-
// Note: Other emulators also do this for 'mousedown' while a button
|
|
867
|
-
// is held, we currently limit 'mousedown' to the terminal only.
|
|
868
|
-
if (requestedEvents.mouseup) {
|
|
869
|
-
this._document!.addEventListener('mouseup', requestedEvents.mouseup);
|
|
870
|
-
}
|
|
871
|
-
if (requestedEvents.mousedrag) {
|
|
872
|
-
this._document!.addEventListener('mousemove', requestedEvents.mousedrag);
|
|
873
|
-
}
|
|
874
|
-
}));
|
|
875
|
-
|
|
876
|
-
this._register(addDisposableListener(el, 'wheel', (ev: WheelEvent) => {
|
|
877
|
-
// do nothing, if app side handles wheel itself
|
|
878
|
-
if (requestedEvents.wheel) return;
|
|
879
|
-
|
|
880
|
-
if (this._customWheelEventHandler && this._customWheelEventHandler(ev) === false) {
|
|
881
|
-
return false;
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
if (!this.buffer.hasScrollback) {
|
|
885
|
-
// Convert wheel events into up/down events when the buffer does not have scrollback, this
|
|
886
|
-
// enables scrolling in apps hosted in the alt buffer such as vim or tmux even when mouse
|
|
887
|
-
// events are not enabled.
|
|
888
|
-
// This used implementation used get the actual lines/partial lines scrolled from the
|
|
889
|
-
// viewport but since moving to the new viewport implementation has been simplified to
|
|
890
|
-
// simply send a single up or down sequence.
|
|
891
|
-
|
|
892
|
-
// Do nothing if there's no vertical scroll
|
|
893
|
-
const deltaY = (ev as WheelEvent).deltaY;
|
|
894
|
-
if (deltaY === 0) {
|
|
895
|
-
return false;
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
const lines = self.coreMouseService.consumeWheelEvent(
|
|
899
|
-
ev as WheelEvent,
|
|
900
|
-
self._renderService?.dimensions?.device?.cell?.height,
|
|
901
|
-
self._coreBrowserService?.dpr
|
|
902
|
-
);
|
|
903
|
-
if (lines === 0) {
|
|
904
|
-
ev.preventDefault();
|
|
905
|
-
ev.stopPropagation();
|
|
906
|
-
return false;
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
// Construct and send sequences
|
|
910
|
-
const sequence = C0.ESC + (this.coreService.decPrivateModes.applicationCursorKeys ? 'O' : '[') + (ev.deltaY < 0 ? 'A' : 'B');
|
|
911
|
-
this.coreService.triggerDataEvent(sequence, true);
|
|
912
|
-
ev.preventDefault();
|
|
913
|
-
ev.stopPropagation();
|
|
914
|
-
return false;
|
|
915
|
-
}
|
|
916
|
-
}, { passive: false }));
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
|
|
920
655
|
/**
|
|
921
656
|
* Tells the renderer to refresh terminal content between two rows (inclusive) at the next
|
|
922
657
|
* opportunity.
|
|
@@ -990,7 +725,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|
|
990
725
|
}
|
|
991
726
|
|
|
992
727
|
public attachCustomWheelEventHandler(customWheelEventHandler: CustomWheelEventHandler): void {
|
|
993
|
-
this.
|
|
728
|
+
this.mouseStateService.setCustomWheelEventHandler(customWheelEventHandler);
|
|
994
729
|
}
|
|
995
730
|
|
|
996
731
|
public registerLinkProvider(linkProvider: ILinkProvider): IDisposable {
|
|
@@ -1360,6 +1095,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|
|
1360
1095
|
|
|
1361
1096
|
this._setup();
|
|
1362
1097
|
super.reset();
|
|
1098
|
+
this._mouseService?.reset();
|
|
1363
1099
|
this._selectionService?.reset();
|
|
1364
1100
|
this._decorationService.reset();
|
|
1365
1101
|
|
package/src/browser/Linkifier.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { IBufferCellPosition, ILink, ILinkDecorations, ILinkWithState, ILinkifie
|
|
|
7
7
|
import { Disposable, dispose, toDisposable } from 'common/Lifecycle';
|
|
8
8
|
import { IDisposable } from 'common/Types';
|
|
9
9
|
import { IBufferService } from 'common/services/Services';
|
|
10
|
-
import { ILinkProviderService,
|
|
10
|
+
import { ILinkProviderService, IMouseCoordsService, IRenderService } from './services/Services';
|
|
11
11
|
import { Emitter } from 'common/Event';
|
|
12
12
|
import { addDisposableListener } from 'browser/Dom';
|
|
13
13
|
|
|
@@ -30,7 +30,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
30
30
|
|
|
31
31
|
constructor(
|
|
32
32
|
private readonly _element: HTMLElement,
|
|
33
|
-
@
|
|
33
|
+
@IMouseCoordsService private readonly _mouseCoordsService: IMouseCoordsService,
|
|
34
34
|
@IRenderService private readonly _renderService: IRenderService,
|
|
35
35
|
@IBufferService private readonly _bufferService: IBufferService,
|
|
36
36
|
@ILinkProviderService private readonly _linkProviderService: ILinkProviderService
|
|
@@ -60,7 +60,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
60
60
|
private _handleMouseMove(event: MouseEvent): void {
|
|
61
61
|
this._lastMouseEvent = event;
|
|
62
62
|
|
|
63
|
-
const position = this._positionFromMouseEvent(event, this._element
|
|
63
|
+
const position = this._positionFromMouseEvent(event, this._element);
|
|
64
64
|
if (!position) {
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
@@ -222,7 +222,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
222
222
|
return;
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
const position = this._positionFromMouseEvent(event, this._element
|
|
225
|
+
const position = this._positionFromMouseEvent(event, this._element);
|
|
226
226
|
if (!position) {
|
|
227
227
|
return;
|
|
228
228
|
}
|
|
@@ -251,7 +251,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
251
251
|
return;
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
const position = this._positionFromMouseEvent(this._lastMouseEvent, this._element
|
|
254
|
+
const position = this._positionFromMouseEvent(this._lastMouseEvent, this._element);
|
|
255
255
|
|
|
256
256
|
if (!position) {
|
|
257
257
|
return;
|
|
@@ -312,7 +312,7 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
312
312
|
this._clearCurrentLink(start, end);
|
|
313
313
|
if (this._lastMouseEvent) {
|
|
314
314
|
// re-eval previously active link after changes
|
|
315
|
-
const position = this._positionFromMouseEvent(this._lastMouseEvent, this._element
|
|
315
|
+
const position = this._positionFromMouseEvent(this._lastMouseEvent, this._element);
|
|
316
316
|
if (position) {
|
|
317
317
|
this._askForLink(position, false);
|
|
318
318
|
}
|
|
@@ -378,8 +378,8 @@ export class Linkifier extends Disposable implements ILinkifier2 {
|
|
|
378
378
|
* Get the buffer position from a mouse event
|
|
379
379
|
* @param event
|
|
380
380
|
*/
|
|
381
|
-
private _positionFromMouseEvent(event: MouseEvent, element: HTMLElement
|
|
382
|
-
const coords =
|
|
381
|
+
private _positionFromMouseEvent(event: MouseEvent, element: HTMLElement): IBufferCellPosition | undefined {
|
|
382
|
+
const coords = this._mouseCoordsService.getCoords(event, element, this._bufferService.cols, this._bufferService.rows);
|
|
383
383
|
if (!coords) {
|
|
384
384
|
return;
|
|
385
385
|
}
|
package/src/browser/Viewport.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
|
|
7
7
|
import { ViewportConstants } from 'browser/shared/Constants';
|
|
8
8
|
import { Disposable, toDisposable } from 'common/Lifecycle';
|
|
9
|
-
import { IBufferService,
|
|
9
|
+
import { IBufferService, IMouseStateService, IOptionsService } from 'common/services/Services';
|
|
10
10
|
import { CoreMouseEventType } from 'common/Types';
|
|
11
11
|
import { addDisposableListener, scheduleAtNextAnimationFrame } from 'browser/Dom';
|
|
12
12
|
import { SmoothScrollableElement } from 'browser/scrollable/scrollableElement';
|
|
@@ -34,7 +34,7 @@ export class Viewport extends Disposable {
|
|
|
34
34
|
screenElement: HTMLElement,
|
|
35
35
|
@IBufferService private readonly _bufferService: IBufferService,
|
|
36
36
|
@ICoreBrowserService coreBrowserService: ICoreBrowserService,
|
|
37
|
-
@
|
|
37
|
+
@IMouseStateService mouseStateService: IMouseStateService,
|
|
38
38
|
@IThemeService themeService: IThemeService,
|
|
39
39
|
@IOptionsService private readonly _optionsService: IOptionsService,
|
|
40
40
|
@IRenderService private readonly _renderService: IRenderService
|
|
@@ -65,7 +65,7 @@ export class Viewport extends Disposable {
|
|
|
65
65
|
'scrollbar'
|
|
66
66
|
], () => this._scrollableElement.updateOptions(this._getChangeOptions())));
|
|
67
67
|
// Don't handle mouse wheel if wheel events are supported by the current mouse prototcol
|
|
68
|
-
this._register(
|
|
68
|
+
this._register(mouseStateService.onProtocolChange(type => {
|
|
69
69
|
this._scrollableElement.updateOptions({
|
|
70
70
|
handleMouseWheel: !(type & CoreMouseEventType.WHEEL)
|
|
71
71
|
});
|
|
@@ -103,7 +103,7 @@ export class Terminal extends Disposable implements ITerminalApi {
|
|
|
103
103
|
public get modes(): IModes {
|
|
104
104
|
const m = this._core.coreService.decPrivateModes;
|
|
105
105
|
let mouseTrackingMode: 'none' | 'x10' | 'vt200' | 'drag' | 'any' = 'none';
|
|
106
|
-
switch (this._core.
|
|
106
|
+
switch (this._core.mouseStateService.activeProtocol) {
|
|
107
107
|
case 'X10': mouseTrackingMode = 'x10'; break;
|
|
108
108
|
case 'VT200': mouseTrackingMode = 'vt200'; break;
|
|
109
109
|
case 'DRAG': mouseTrackingMode = 'drag'; break;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 The xterm.js authors. All rights reserved.
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getWindow } from 'browser/Dom';
|
|
7
|
+
import { getCoords, getCoordsRelativeToElement } from 'browser/input/Mouse';
|
|
8
|
+
import { ICharSizeService, IMouseCoordsService, IRenderService } from 'browser/services/Services';
|
|
9
|
+
|
|
10
|
+
export class MouseCoordsService implements IMouseCoordsService {
|
|
11
|
+
public serviceBrand: undefined;
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
@ICharSizeService private readonly _charSizeService: ICharSizeService,
|
|
15
|
+
@IRenderService private readonly _renderService: IRenderService
|
|
16
|
+
) {
|
|
17
|
+
}
|
|
18
|
+
|
|
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
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
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;
|
|
37
|
+
}
|
|
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);
|
|
40
|
+
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])
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|