Toggle enable-mouse-events cursor while alt is held for mouseEventsRequireAlt.
Extract AltMouseCursorController to bind DOM listeners only when the option and mouse protocol are active. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,7 +7,7 @@ import { addDisposableListener } from 'browser/Dom';
|
||||
import { IBufferService, IMouseStateService, ICoreService, ILogService, IOptionsService } from 'common/services/Services';
|
||||
import { CoreMouseAction, CoreMouseButton, CoreMouseEventType, ICoreMouseEvent, IDisposable } from 'common/Types';
|
||||
import { C0 } from 'common/data/EscapeSequences';
|
||||
import { toDisposable } from 'common/Lifecycle';
|
||||
import { DisposableStore, MutableDisposable, toDisposable } from 'common/Lifecycle';
|
||||
import { ICoreBrowserService, IMouseCoordsService, IMouseService, IMouseServiceTarget, IRenderService, ISelectionService } from './Services';
|
||||
import { Gesture, EventType as GestureEventType, IGestureEvent } from 'browser/scrollable/touch';
|
||||
|
||||
@@ -25,6 +25,7 @@ export class MouseService implements IMouseService {
|
||||
private _lastEvent: ICoreMouseEvent | null = null;
|
||||
private _wheelPartialScroll: number = 0;
|
||||
private _touchScrollAccumulator: number = 0;
|
||||
private _altMouseCursor: AltMouseCursorController | undefined;
|
||||
|
||||
constructor(
|
||||
@IRenderService private readonly _renderService: IRenderService,
|
||||
@@ -63,11 +64,19 @@ export class MouseService implements IMouseService {
|
||||
mousedrag: (ev: Event) => this._handleMouseDrag(ctx, ev as MouseEvent),
|
||||
mousemove: (ev: Event) => this._handleMouseMove(ctx, ev as MouseEvent)
|
||||
};
|
||||
this._altMouseCursor = new AltMouseCursorController(
|
||||
element,
|
||||
document,
|
||||
() => this._mouseStateService.areMouseEventsActive
|
||||
&& !!this._optionsService.rawOptions.mouseEventsRequireAlt
|
||||
);
|
||||
register(this._altMouseCursor);
|
||||
register(this._mouseStateService.onProtocolChange(events => {
|
||||
this._handleProtocolChange(ctx, eventListeners, events);
|
||||
}));
|
||||
register(this._optionsService.onSpecificOptionChange('mouseEventsRequireAlt', () => {
|
||||
this._syncMouseModeState(element);
|
||||
this._altMouseCursor?.sync();
|
||||
}));
|
||||
// force initial onProtocolChange so we dont miss early mouse requests
|
||||
this._mouseStateService.activeProtocol = this._mouseStateService.activeProtocol;
|
||||
@@ -372,7 +381,7 @@ export class MouseService implements IMouseService {
|
||||
private _syncMouseModeState(element: HTMLElement): void {
|
||||
if (this._mouseStateService.areMouseEventsActive) {
|
||||
if (this._optionsService.rawOptions.mouseEventsRequireAlt) {
|
||||
element.classList.remove('enable-mouse-events');
|
||||
this._altMouseCursor?.resetClass();
|
||||
this._selectionService.enable();
|
||||
} else {
|
||||
element.classList.add('enable-mouse-events');
|
||||
@@ -396,6 +405,7 @@ export class MouseService implements IMouseService {
|
||||
this._logService.debug('Unbinding from mouse events.');
|
||||
}
|
||||
this._syncMouseModeState(element);
|
||||
this._altMouseCursor?.sync();
|
||||
|
||||
// add/remove handlers from requestedEvents
|
||||
if (!(events & CoreMouseEventType.MOVE)) {
|
||||
@@ -565,3 +575,64 @@ export class MouseService implements IMouseService {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles `enable-mouse-events` on the terminal element while alt is held when
|
||||
* `mouseEventsRequireAlt` is active. DOM listeners are only registered while active.
|
||||
*/
|
||||
export class AltMouseCursorController implements IDisposable {
|
||||
private readonly _listeners = new MutableDisposable<IDisposable>();
|
||||
|
||||
constructor(
|
||||
private readonly _element: HTMLElement,
|
||||
private readonly _document: Document,
|
||||
private readonly _isActive: () => boolean
|
||||
) {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._listeners.dispose();
|
||||
}
|
||||
|
||||
public sync(): void {
|
||||
this._listeners.clear();
|
||||
|
||||
if (!this._isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const store = new DisposableStore();
|
||||
const syncFromModifier = (ev: KeyboardEvent | MouseEvent) => this.syncFromModifier(ev);
|
||||
store.add(addDisposableListener(this._document, 'keydown', syncFromModifier));
|
||||
store.add(addDisposableListener(this._document, 'keyup', syncFromModifier));
|
||||
store.add(addDisposableListener(this._element, 'mousemove', syncFromModifier));
|
||||
const targetWindow = this._element.ownerDocument?.defaultView;
|
||||
if (targetWindow) {
|
||||
store.add(addDisposableListener(targetWindow, 'blur', () => {
|
||||
if (this._isActive()) {
|
||||
this.resetClass();
|
||||
}
|
||||
}));
|
||||
}
|
||||
this._listeners.value = store;
|
||||
}
|
||||
|
||||
public resetClass(): void {
|
||||
this._updateClass(false);
|
||||
}
|
||||
|
||||
public syncFromModifier(ev: KeyboardEvent | MouseEvent): void {
|
||||
if (!this._isActive()) {
|
||||
return;
|
||||
}
|
||||
this._updateClass(ev.getModifierState('Alt'));
|
||||
}
|
||||
|
||||
private _updateClass(altHeld: boolean): void {
|
||||
if (altHeld) {
|
||||
this._element.classList.add('enable-mouse-events');
|
||||
} else {
|
||||
this._element.classList.remove('enable-mouse-events');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user