@@ -1095,6 +1095,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
|
|||||||
|
|
||||||
this._setup();
|
this._setup();
|
||||||
super.reset();
|
super.reset();
|
||||||
|
this._mouseService?.reset();
|
||||||
this._selectionService?.reset();
|
this._selectionService?.reset();
|
||||||
this._decorationService.reset();
|
this._decorationService.reset();
|
||||||
|
|
||||||
|
|||||||
@@ -393,9 +393,8 @@ export class MockMouseService implements IMouseService {
|
|||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
public bindMouse(): void {
|
public bindMouse(): void { }
|
||||||
throw new Error('Not implemented');
|
public reset(): void { }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MockRenderService implements IRenderService {
|
export class MockRenderService implements IRenderService {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { addDisposableListener } from 'browser/Dom';
|
import { addDisposableListener } from 'browser/Dom';
|
||||||
import { IBufferService, IMouseStateService, ICoreService, ILogService, IOptionsService } from 'common/services/Services';
|
import { IBufferService, IMouseStateService, ICoreService, ILogService, IOptionsService } from 'common/services/Services';
|
||||||
import { CoreMouseAction, CoreMouseButton, CoreMouseEventType, IDisposable } from 'common/Types';
|
import { CoreMouseAction, CoreMouseButton, CoreMouseEventType, ICoreMouseEvent, IDisposable } from 'common/Types';
|
||||||
import { C0 } from 'common/data/EscapeSequences';
|
import { C0 } from 'common/data/EscapeSequences';
|
||||||
import { toDisposable } from 'common/Lifecycle';
|
import { toDisposable } from 'common/Lifecycle';
|
||||||
import { ICoreBrowserService, IMouseCoordsService, IMouseService, IMouseServiceTarget, IRenderService, ISelectionService } from './Services';
|
import { ICoreBrowserService, IMouseCoordsService, IMouseService, IMouseServiceTarget, IRenderService, ISelectionService } from './Services';
|
||||||
@@ -21,6 +21,9 @@ interface IMouseBindContext {
|
|||||||
export class MouseService implements IMouseService {
|
export class MouseService implements IMouseService {
|
||||||
public serviceBrand: undefined;
|
public serviceBrand: undefined;
|
||||||
|
|
||||||
|
private _lastEvent: ICoreMouseEvent | null = null;
|
||||||
|
private _wheelPartialScroll: number = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IRenderService private readonly _renderService: IRenderService,
|
@IRenderService private readonly _renderService: IRenderService,
|
||||||
@IMouseCoordsService private readonly _mouseCoordsService: IMouseCoordsService,
|
@IMouseCoordsService private readonly _mouseCoordsService: IMouseCoordsService,
|
||||||
@@ -123,7 +126,7 @@ export class MouseService implements IMouseService {
|
|||||||
if (deltaY === 0) {
|
if (deltaY === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const lines = this._mouseStateService.consumeWheelEvent(
|
const lines = this._consumeWheelEvent(
|
||||||
ev as WheelEvent,
|
ev as WheelEvent,
|
||||||
this._renderService?.dimensions?.device?.cell?.height,
|
this._renderService?.dimensions?.device?.cell?.height,
|
||||||
this._coreBrowserService?.dpr
|
this._coreBrowserService?.dpr
|
||||||
@@ -145,7 +148,7 @@ export class MouseService implements IMouseService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._mouseStateService.triggerMouseEvent({
|
return this._triggerMouseEvent({
|
||||||
col: pos.col,
|
col: pos.col,
|
||||||
row: pos.row,
|
row: pos.row,
|
||||||
x: pos.x,
|
x: pos.x,
|
||||||
@@ -241,7 +244,7 @@ export class MouseService implements IMouseService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines = this._mouseStateService.consumeWheelEvent(
|
const lines = this._consumeWheelEvent(
|
||||||
ev,
|
ev,
|
||||||
this._renderService?.dimensions?.device?.cell?.height,
|
this._renderService?.dimensions?.device?.cell?.height,
|
||||||
this._coreBrowserService?.dpr
|
this._coreBrowserService?.dpr
|
||||||
@@ -261,13 +264,18 @@ export class MouseService implements IMouseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public reset(): void {
|
||||||
|
this._lastEvent = null;
|
||||||
|
this._wheelPartialScroll = 0;
|
||||||
|
}
|
||||||
|
|
||||||
private _handleProtocolChange(ctx: IMouseBindContext, eventListeners: Record<'mouseup' | 'wheel' | 'mousedrag' | 'mousemove', EventListener>, events: CoreMouseEventType): void {
|
private _handleProtocolChange(ctx: IMouseBindContext, eventListeners: Record<'mouseup' | 'wheel' | 'mousedrag' | 'mousemove', EventListener>, events: CoreMouseEventType): void {
|
||||||
const { element, document } = ctx.target;
|
const { element, document } = ctx.target;
|
||||||
const { requestedEvents } = ctx;
|
const { requestedEvents } = ctx;
|
||||||
// apply global changes on events
|
// apply global changes on events
|
||||||
if (events) {
|
if (events) {
|
||||||
if (this._optionsService.rawOptions.logLevel === 'debug') {
|
if (this._optionsService.rawOptions.logLevel === 'debug') {
|
||||||
this._logService.debug('Binding to mouse events:', this._mouseStateService.explainEvents(events));
|
this._logService.debug('Binding to mouse events:', this._explainEvents(events));
|
||||||
}
|
}
|
||||||
element.classList.add('enable-mouse-events');
|
element.classList.add('enable-mouse-events');
|
||||||
this._selectionService.disable();
|
this._selectionService.disable();
|
||||||
@@ -317,4 +325,131 @@ export class MouseService implements IMouseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _applyScrollModifier(amount: number, ev: WheelEvent): number {
|
||||||
|
// Multiply the scroll speed when the modifier key is pressed
|
||||||
|
if (ev.altKey || ev.ctrlKey || ev.shiftKey) {
|
||||||
|
return amount * this._optionsService.rawOptions.fastScrollSensitivity * this._optionsService.rawOptions.scrollSensitivity;
|
||||||
|
}
|
||||||
|
return amount * this._optionsService.rawOptions.scrollSensitivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a wheel event, accounting for partial scrolls for trackpad, mouse scrolls.
|
||||||
|
* This prevents hyper-sensitive scrolling in alt buffer.
|
||||||
|
*/
|
||||||
|
private _consumeWheelEvent(ev: WheelEvent, cellHeight?: number, dpr?: number): number {
|
||||||
|
// Do nothing if it's not a vertical scroll event
|
||||||
|
if (ev.deltaY === 0 || ev.shiftKey) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cellHeight === undefined || dpr === undefined) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetWheelEventPixels = cellHeight / dpr;
|
||||||
|
let amount = this._applyScrollModifier(ev.deltaY, ev);
|
||||||
|
|
||||||
|
if (ev.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
|
||||||
|
amount /= (targetWheelEventPixels + 0.0); // Prevent integer division
|
||||||
|
|
||||||
|
const isLikelyTrackpad = Math.abs(ev.deltaY) < 50;
|
||||||
|
if (isLikelyTrackpad) {
|
||||||
|
amount *= 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._wheelPartialScroll += amount;
|
||||||
|
amount = Math.floor(Math.abs(this._wheelPartialScroll)) * (this._wheelPartialScroll > 0 ? 1 : -1);
|
||||||
|
this._wheelPartialScroll %= 1;
|
||||||
|
} else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
|
||||||
|
amount *= this._bufferService.rows;
|
||||||
|
}
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a mouse event to be sent.
|
||||||
|
*
|
||||||
|
* Returns true if the event passed all protocol restrictions and a report
|
||||||
|
* was sent, otherwise false. The return value may be used to decide whether
|
||||||
|
* the default event action in the browser component should be omitted.
|
||||||
|
*
|
||||||
|
* Note: The method will change values of the given event object
|
||||||
|
* to fulfill protocol and encoding restrictions.
|
||||||
|
*/
|
||||||
|
private _triggerMouseEvent(e: ICoreMouseEvent): boolean {
|
||||||
|
// range check for col/row
|
||||||
|
if (e.col < 0 || e.col >= this._bufferService.cols
|
||||||
|
|| e.row < 0 || e.row >= this._bufferService.rows) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter nonsense combinations of button + action
|
||||||
|
if (e.button === CoreMouseButton.WHEEL && e.action === CoreMouseAction.MOVE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (e.button === CoreMouseButton.NONE && e.action !== CoreMouseAction.MOVE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (e.button !== CoreMouseButton.WHEEL && (e.action === CoreMouseAction.LEFT || e.action === CoreMouseAction.RIGHT)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// report 1-based coords
|
||||||
|
e.col++;
|
||||||
|
e.row++;
|
||||||
|
|
||||||
|
// debounce move events at grid or pixel level
|
||||||
|
if (e.action === CoreMouseAction.MOVE
|
||||||
|
&& this._lastEvent
|
||||||
|
&& this._equalEvents(this._lastEvent, e, this._mouseStateService.isPixelEncoding)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply protocol restrictions
|
||||||
|
if (!this._mouseStateService.restrictMouseEvent(e)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode report and send
|
||||||
|
const report = this._mouseStateService.encodeMouseEvent(e);
|
||||||
|
if (report) {
|
||||||
|
if (this._mouseStateService.isDefaultEncoding) {
|
||||||
|
this._coreService.triggerBinaryEvent(report);
|
||||||
|
} else {
|
||||||
|
this._coreService.triggerDataEvent(report, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._lastEvent = e;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _explainEvents(events: CoreMouseEventType): { [event: string]: boolean } {
|
||||||
|
return {
|
||||||
|
down: !!(events & CoreMouseEventType.DOWN),
|
||||||
|
up: !!(events & CoreMouseEventType.UP),
|
||||||
|
drag: !!(events & CoreMouseEventType.DRAG),
|
||||||
|
move: !!(events & CoreMouseEventType.MOVE),
|
||||||
|
wheel: !!(events & CoreMouseEventType.WHEEL)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private _equalEvents(e1: ICoreMouseEvent, e2: ICoreMouseEvent, pixels: boolean): boolean {
|
||||||
|
if (pixels) {
|
||||||
|
if (e1.x !== e2.x) return false;
|
||||||
|
if (e1.y !== e2.y) return false;
|
||||||
|
} else {
|
||||||
|
if (e1.col !== e2.col) return false;
|
||||||
|
if (e1.row !== e2.row) return false;
|
||||||
|
}
|
||||||
|
if (e1.button !== e2.button) return false;
|
||||||
|
if (e1.action !== e2.action) return false;
|
||||||
|
if (e1.ctrl !== e2.ctrl) return false;
|
||||||
|
if (e1.alt !== e2.alt) return false;
|
||||||
|
if (e1.shift !== e2.shift) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export interface IMouseService {
|
|||||||
serviceBrand: undefined;
|
serviceBrand: undefined;
|
||||||
|
|
||||||
bindMouse(target: IMouseServiceTarget, register: (disposable: IDisposable) => void, focus: () => void): void;
|
bindMouse(target: IMouseServiceTarget, register: (disposable: IDisposable) => void, focus: () => void): void;
|
||||||
|
reset(): void;
|
||||||
}
|
}
|
||||||
export interface IMouseServiceTarget {
|
export interface IMouseServiceTarget {
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
||||||
|
|||||||
@@ -71,17 +71,14 @@ export class MockMouseStateService implements IMouseStateService {
|
|||||||
public areMouseEventsActive: boolean = false;
|
public areMouseEventsActive: boolean = false;
|
||||||
public activeEncoding: string = '';
|
public activeEncoding: string = '';
|
||||||
public activeProtocol: string = '';
|
public activeProtocol: string = '';
|
||||||
|
public isDefaultEncoding: boolean = true;
|
||||||
|
public isPixelEncoding: boolean = false;
|
||||||
public addEncoding(name: string): void { }
|
public addEncoding(name: string): void { }
|
||||||
public addProtocol(name: string): void { }
|
public addProtocol(name: string): void { }
|
||||||
public reset(): void { }
|
public reset(): void { }
|
||||||
public triggerMouseEvent(event: ICoreMouseEvent): boolean { return false; }
|
|
||||||
public onProtocolChange: IEvent<CoreMouseEventType> = new Emitter<CoreMouseEventType>().event;
|
public onProtocolChange: IEvent<CoreMouseEventType> = new Emitter<CoreMouseEventType>().event;
|
||||||
public explainEvents(events: CoreMouseEventType): { [event: string]: boolean } {
|
public restrictMouseEvent(event: ICoreMouseEvent): boolean { return true; }
|
||||||
throw new Error('Method not implemented.');
|
public encodeMouseEvent(event: ICoreMouseEvent): string { return ''; }
|
||||||
}
|
|
||||||
public consumeWheelEvent(ev: WheelEvent, cellHeight: number, dpr: number): number {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
public setCustomWheelEventHandler(customWheelEventHandler: ((event: WheelEvent) => boolean) | undefined): void { }
|
public setCustomWheelEventHandler(customWheelEventHandler: ((event: WheelEvent) => boolean) | undefined): void { }
|
||||||
public allowCustomWheelEvent(ev: WheelEvent): boolean { return true; }
|
public allowCustomWheelEvent(ev: WheelEvent): boolean { return true; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,8 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
import { MouseStateService } from 'common/services/MouseStateService';
|
import { MouseStateService } from 'common/services/MouseStateService';
|
||||||
import { MockCoreService, MockBufferService, MockOptionsService } from 'common/TestUtils.test';
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { ICoreMouseEvent, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from 'common/Types';
|
import { ICoreMouseEvent, CoreMouseEventType } from 'common/Types';
|
||||||
|
|
||||||
// needed mock services
|
|
||||||
const bufferService = new MockBufferService(300, 100);
|
|
||||||
const coreService = new MockCoreService();
|
|
||||||
const optionsService = new MockOptionsService();
|
|
||||||
|
|
||||||
function toBytes(s: string | undefined): number[] {
|
function toBytes(s: string | undefined): number[] {
|
||||||
if (!s) {
|
if (!s) {
|
||||||
@@ -25,20 +19,20 @@ function toBytes(s: string | undefined): number[] {
|
|||||||
|
|
||||||
describe('MouseStateService', () => {
|
describe('MouseStateService', () => {
|
||||||
it('init', () => {
|
it('init', () => {
|
||||||
const cms = new MouseStateService(bufferService, coreService, optionsService);
|
const cms = new MouseStateService();
|
||||||
assert.equal(cms.activeEncoding, 'DEFAULT');
|
assert.equal(cms.activeEncoding, 'DEFAULT');
|
||||||
assert.equal(cms.activeProtocol, 'NONE');
|
assert.equal(cms.activeProtocol, 'NONE');
|
||||||
});
|
});
|
||||||
it('default protocols - NONE, X10, VT200, DRAG, ANY', () => {
|
it('default protocols - NONE, X10, VT200, DRAG, ANY', () => {
|
||||||
const cms = new MouseStateService(bufferService, coreService, optionsService);
|
const cms = new MouseStateService();
|
||||||
assert.deepEqual(Object.keys((cms as any)._protocols), ['NONE', 'X10', 'VT200', 'DRAG', 'ANY']);
|
assert.deepEqual(Object.keys((cms as any)._protocols), ['NONE', 'X10', 'VT200', 'DRAG', 'ANY']);
|
||||||
});
|
});
|
||||||
it('default encodings - DEFAULT, SGR', () => {
|
it('default encodings - DEFAULT, SGR', () => {
|
||||||
const cms = new MouseStateService(bufferService, coreService, optionsService);
|
const cms = new MouseStateService();
|
||||||
assert.deepEqual(Object.keys((cms as any)._encodings), ['DEFAULT', 'SGR', 'SGR_PIXELS']);
|
assert.deepEqual(Object.keys((cms as any)._encodings), ['DEFAULT', 'SGR', 'SGR_PIXELS']);
|
||||||
});
|
});
|
||||||
it('protocol/encoding setter, reset', () => {
|
it('protocol/encoding setter, reset', () => {
|
||||||
const cms = new MouseStateService(bufferService, coreService, optionsService);
|
const cms = new MouseStateService();
|
||||||
cms.activeEncoding = 'SGR';
|
cms.activeEncoding = 'SGR';
|
||||||
cms.activeProtocol = 'ANY';
|
cms.activeProtocol = 'ANY';
|
||||||
assert.equal(cms.activeEncoding, 'SGR');
|
assert.equal(cms.activeEncoding, 'SGR');
|
||||||
@@ -50,19 +44,19 @@ describe('MouseStateService', () => {
|
|||||||
assert.throws(() => { cms.activeProtocol = 'xyz'; }, 'unknown protocol "xyz"');
|
assert.throws(() => { cms.activeProtocol = 'xyz'; }, 'unknown protocol "xyz"');
|
||||||
});
|
});
|
||||||
it('addEncoding', () => {
|
it('addEncoding', () => {
|
||||||
const cms = new MouseStateService(bufferService, coreService, optionsService);
|
const cms = new MouseStateService();
|
||||||
cms.addEncoding('XYZ', (e: ICoreMouseEvent) => '');
|
cms.addEncoding('XYZ', (e: ICoreMouseEvent) => '');
|
||||||
cms.activeEncoding = 'XYZ';
|
cms.activeEncoding = 'XYZ';
|
||||||
assert.equal(cms.activeEncoding, 'XYZ');
|
assert.equal(cms.activeEncoding, 'XYZ');
|
||||||
});
|
});
|
||||||
it('addProtocol', () => {
|
it('addProtocol', () => {
|
||||||
const cms = new MouseStateService(bufferService, coreService, optionsService);
|
const cms = new MouseStateService();
|
||||||
cms.addProtocol('XYZ', { events: CoreMouseEventType.NONE, restrict: (e: ICoreMouseEvent) => false });
|
cms.addProtocol('XYZ', { events: CoreMouseEventType.NONE, restrict: (e: ICoreMouseEvent) => false });
|
||||||
cms.activeProtocol = 'XYZ';
|
cms.activeProtocol = 'XYZ';
|
||||||
assert.equal(cms.activeProtocol, 'XYZ');
|
assert.equal(cms.activeProtocol, 'XYZ');
|
||||||
});
|
});
|
||||||
it('onProtocolChange', () => {
|
it('onProtocolChange', () => {
|
||||||
const cms = new MouseStateService(bufferService, coreService, optionsService);
|
const cms = new MouseStateService();
|
||||||
const wantedEvents: CoreMouseEventType[] = [];
|
const wantedEvents: CoreMouseEventType[] = [];
|
||||||
cms.onProtocolChange(events => wantedEvents.push(events));
|
cms.onProtocolChange(events => wantedEvents.push(events));
|
||||||
cms.activeProtocol = 'NONE';
|
cms.activeProtocol = 'NONE';
|
||||||
@@ -73,140 +67,22 @@ describe('MouseStateService', () => {
|
|||||||
CoreMouseEventType.DOWN | CoreMouseEventType.UP | CoreMouseEventType.WHEEL | CoreMouseEventType.DRAG | CoreMouseEventType.MOVE
|
CoreMouseEventType.DOWN | CoreMouseEventType.UP | CoreMouseEventType.WHEEL | CoreMouseEventType.DRAG | CoreMouseEventType.MOVE
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
describe('triggerMouseEvent', () => {
|
it('restrictMouseEvent/encodeMouseEvent', () => {
|
||||||
let cms: MouseStateService;
|
const cms = new MouseStateService();
|
||||||
let reports: string[];
|
const event: ICoreMouseEvent = {
|
||||||
beforeEach(() => {
|
col: 1,
|
||||||
cms = new MouseStateService(bufferService, coreService, optionsService);
|
row: 1,
|
||||||
reports = [];
|
x: 0,
|
||||||
coreService.triggerDataEvent = (data: string, userInput?: boolean) => reports.push(data);
|
y: 0,
|
||||||
coreService.triggerBinaryEvent = (data: string) => reports.push(data);
|
button: 0,
|
||||||
});
|
action: 1,
|
||||||
it('NONE', () => {
|
ctrl: false,
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), false);
|
alt: false,
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.UP }), false);
|
shift: false
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.MOVE }), false);
|
};
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.MIDDLE, action: CoreMouseAction.DOWN }), false);
|
cms.activeProtocol = 'ANY';
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.RIGHT, action: CoreMouseAction.DOWN }), false);
|
cms.activeEncoding = 'DEFAULT';
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.UP }), false);
|
assert.equal(cms.restrictMouseEvent(event), true);
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE }), false);
|
assert.deepEqual(toBytes(cms.encodeMouseEvent(event)), [0x1b, 0x5b, 0x4d, 0x21, 0x21, 0x21]);
|
||||||
});
|
|
||||||
it('X10', () => {
|
|
||||||
cms.activeProtocol = 'X10';
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.UP }), false);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.MOVE }), false);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.MIDDLE, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.RIGHT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.UP }), false);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE }), false);
|
|
||||||
});
|
|
||||||
it('VT200', () => {
|
|
||||||
cms.activeProtocol = 'VT200';
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.UP }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.MOVE }), false);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.MIDDLE, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.RIGHT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.UP }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE }), false);
|
|
||||||
});
|
|
||||||
it('DRAG', () => {
|
|
||||||
cms.activeProtocol = 'DRAG';
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.UP }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.MOVE }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.MIDDLE, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.RIGHT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.UP }), true);
|
|
||||||
});
|
|
||||||
it('ANY', () => {
|
|
||||||
cms.activeProtocol = 'ANY';
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.UP }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.MOVE }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.MIDDLE, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.RIGHT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.UP }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE }), true);
|
|
||||||
// should not report in any case
|
|
||||||
// invalid button + action combinations
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.MOVE }), false);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.DOWN }), false);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.UP }), false);
|
|
||||||
// invalid coords
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: -1, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), false);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 500, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), false);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: -1, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), false);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 500, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), false);
|
|
||||||
});
|
|
||||||
describe('coords', () => {
|
|
||||||
it('DEFAULT encoding', () => {
|
|
||||||
cms.activeProtocol = 'ANY';
|
|
||||||
for (let i = 0; i < bufferService.cols; ++i) {
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: i, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
if (i > 222) {
|
|
||||||
// supress mouse reports if we are out of addressible range (max. 222)
|
|
||||||
assert.deepEqual(toBytes(reports.pop()), []);
|
|
||||||
} else {
|
|
||||||
assert.deepEqual(toBytes(reports.pop()), [0x1b, 0x5b, 0x4d, 0x20, i + 33, 0x21]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it('SGR encoding', () => {
|
|
||||||
cms.activeProtocol = 'ANY';
|
|
||||||
cms.activeEncoding = 'SGR';
|
|
||||||
for (let i = 0; i < bufferService.cols; ++i) {
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: i, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.deepEqual(reports.pop(), `\x1b[<0;${i + 1};1M`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it('SGR_PIXELS encoding', () => {
|
|
||||||
cms.activeProtocol = 'ANY';
|
|
||||||
cms.activeEncoding = 'SGR_PIXELS';
|
|
||||||
for (let i = 0; i < 500; ++i) {
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: i, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), true);
|
|
||||||
assert.deepEqual(reports.pop(), `\x1b[<0;${i};0M`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('eventCodes with modifiers (DEFAULT encoding)', () => {
|
|
||||||
// TODO: implement AUX button tests
|
|
||||||
cms.activeProtocol = 'ANY';
|
|
||||||
cms.activeEncoding = 'DEFAULT';
|
|
||||||
// all buttons + down + no modifer
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.MIDDLE, action: CoreMouseAction.DOWN, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.RIGHT, action: CoreMouseAction.DOWN, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.DOWN, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.deepEqual(reports, ['\x1b[M !!', '\x1b[M!!!', '\x1b[M"!!', '\x1b[Ma!!']);
|
|
||||||
reports = [];
|
|
||||||
|
|
||||||
// all buttons + up + no modifier
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.UP, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.MIDDLE, action: CoreMouseAction.UP, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.RIGHT, action: CoreMouseAction.UP, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.WHEEL, action: CoreMouseAction.UP, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.deepEqual(reports, ['\x1b[M#!!', '\x1b[M#!!', '\x1b[M#!!', '\x1b[M`!!']);
|
|
||||||
reports = [];
|
|
||||||
|
|
||||||
// all buttons + move + no modifier
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.MOVE, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.MIDDLE, action: CoreMouseAction.MOVE, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.RIGHT, action: CoreMouseAction.MOVE, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE, ctrl: false, alt: false, shift: false }), true);
|
|
||||||
assert.deepEqual(reports, ['\x1b[M@!!', '\x1b[MA!!', '\x1b[MB!!', '\x1b[MC!!']);
|
|
||||||
reports = [];
|
|
||||||
|
|
||||||
// button none + move + modifiers
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE, ctrl: true, alt: false, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE, ctrl: false, alt: true, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE, ctrl: false, alt: false, shift: true }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE, ctrl: true, alt: true, shift: false }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE, ctrl: false, alt: true, shift: true }), true);
|
|
||||||
assert.equal(cms.triggerMouseEvent({ col: 0, row: 0, x: 0, y: 0, button: CoreMouseButton.NONE, action: CoreMouseAction.MOVE, ctrl: true, alt: true, shift: true }), true);
|
|
||||||
assert.deepEqual(reports, ['\x1b[MS!!', '\x1b[MK!!', '\x1b[MG!!', '\x1b[M[!!', '\x1b[MO!!', '\x1b[M_!!']);
|
|
||||||
reports = [];
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
import { IBufferService, ICoreService, IMouseStateService, IOptionsService } from 'common/services/Services';
|
import { IMouseStateService } from 'common/services/Services';
|
||||||
import { ICoreMouseProtocol, ICoreMouseEvent, CoreMouseEncoding, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from 'common/Types';
|
import { ICoreMouseProtocol, ICoreMouseEvent, CoreMouseEncoding, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from 'common/Types';
|
||||||
import { Disposable } from 'common/Lifecycle';
|
import { Disposable } from 'common/Lifecycle';
|
||||||
import { Emitter } from 'common/Event';
|
import { Emitter } from 'common/Event';
|
||||||
@@ -173,19 +173,14 @@ export class MouseStateService extends Disposable implements IMouseStateService
|
|||||||
private _encodings: { [name: string]: CoreMouseEncoding } = {};
|
private _encodings: { [name: string]: CoreMouseEncoding } = {};
|
||||||
private _activeProtocol: string = '';
|
private _activeProtocol: string = '';
|
||||||
private _activeEncoding: string = '';
|
private _activeEncoding: string = '';
|
||||||
private _lastEvent: ICoreMouseEvent | null = null;
|
|
||||||
private _wheelPartialScroll: number = 0;
|
|
||||||
private _customWheelEventHandler: ((event: WheelEvent) => boolean) | undefined;
|
private _customWheelEventHandler: ((event: WheelEvent) => boolean) | undefined;
|
||||||
|
|
||||||
private readonly _onProtocolChange = this._register(new Emitter<CoreMouseEventType>());
|
private readonly _onProtocolChange = this._register(new Emitter<CoreMouseEventType>());
|
||||||
public readonly onProtocolChange = this._onProtocolChange.event;
|
public readonly onProtocolChange = this._onProtocolChange.event;
|
||||||
|
|
||||||
constructor(
|
constructor() {
|
||||||
@IBufferService private readonly _bufferService: IBufferService,
|
|
||||||
@ICoreService private readonly _coreService: ICoreService,
|
|
||||||
@IOptionsService private readonly _optionsService: IOptionsService
|
|
||||||
) {
|
|
||||||
super();
|
super();
|
||||||
|
|
||||||
// register default protocols and encodings
|
// register default protocols and encodings
|
||||||
for (const name of Object.keys(DEFAULT_PROTOCOLS)) this.addProtocol(name, DEFAULT_PROTOCOLS[name]);
|
for (const name of Object.keys(DEFAULT_PROTOCOLS)) this.addProtocol(name, DEFAULT_PROTOCOLS[name]);
|
||||||
for (const name of Object.keys(DEFAULT_ENCODINGS)) this.addEncoding(name, DEFAULT_ENCODINGS[name]);
|
for (const name of Object.keys(DEFAULT_ENCODINGS)) this.addEncoding(name, DEFAULT_ENCODINGS[name]);
|
||||||
@@ -231,42 +226,6 @@ export class MouseStateService extends Disposable implements IMouseStateService
|
|||||||
public reset(): void {
|
public reset(): void {
|
||||||
this.activeProtocol = 'NONE';
|
this.activeProtocol = 'NONE';
|
||||||
this.activeEncoding = 'DEFAULT';
|
this.activeEncoding = 'DEFAULT';
|
||||||
this._lastEvent = null;
|
|
||||||
this._wheelPartialScroll = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes a wheel event, accounting for partial scrolls for trackpad, mouse scrolls.
|
|
||||||
* This prevents hyper-sensitive scrolling in alt buffer.
|
|
||||||
*/
|
|
||||||
public consumeWheelEvent(ev: WheelEvent, cellHeight?: number, dpr?: number): number {
|
|
||||||
// Do nothing if it's not a vertical scroll event
|
|
||||||
if (ev.deltaY === 0 || ev.shiftKey) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cellHeight === undefined || dpr === undefined) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetWheelEventPixels = cellHeight / dpr;
|
|
||||||
let amount = this._applyScrollModifier(ev.deltaY, ev);
|
|
||||||
|
|
||||||
if (ev.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
|
|
||||||
amount /= (targetWheelEventPixels + 0.0); // Prevent integer division
|
|
||||||
|
|
||||||
const isLikelyTrackpad = Math.abs(ev.deltaY) < 50;
|
|
||||||
if (isLikelyTrackpad) {
|
|
||||||
amount *= 0.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._wheelPartialScroll += amount;
|
|
||||||
amount = Math.floor(Math.abs(this._wheelPartialScroll)) * (this._wheelPartialScroll > 0 ? 1 : -1);
|
|
||||||
this._wheelPartialScroll %= 1;
|
|
||||||
} else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
|
|
||||||
amount *= this._bufferService.rows;
|
|
||||||
}
|
|
||||||
return amount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setCustomWheelEventHandler(customWheelEventHandler: ((event: WheelEvent) => boolean) | undefined): void {
|
public setCustomWheelEventHandler(customWheelEventHandler: ((event: WheelEvent) => boolean) | undefined): void {
|
||||||
@@ -277,98 +236,19 @@ export class MouseStateService extends Disposable implements IMouseStateService
|
|||||||
return this._customWheelEventHandler ? this._customWheelEventHandler(ev) !== false : true;
|
return this._customWheelEventHandler ? this._customWheelEventHandler(ev) !== false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _applyScrollModifier(amount: number, ev: WheelEvent): number {
|
public restrictMouseEvent(e: ICoreMouseEvent): boolean {
|
||||||
// Multiply the scroll speed when the modifier key is pressed
|
return this._protocols[this._activeProtocol].restrict(e);
|
||||||
if (ev.altKey || ev.ctrlKey || ev.shiftKey) {
|
|
||||||
return amount * this._optionsService.rawOptions.fastScrollSensitivity * this._optionsService.rawOptions.scrollSensitivity;
|
|
||||||
}
|
|
||||||
return amount * this._optionsService.rawOptions.scrollSensitivity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public encodeMouseEvent(e: ICoreMouseEvent): string {
|
||||||
* Triggers a mouse event to be sent.
|
return this._encodings[this._activeEncoding](e);
|
||||||
*
|
|
||||||
* Returns true if the event passed all protocol restrictions and a report
|
|
||||||
* was sent, otherwise false. The return value may be used to decide whether
|
|
||||||
* the default event action in the bowser component should be omitted.
|
|
||||||
*
|
|
||||||
* Note: The method will change values of the given event object
|
|
||||||
* to fullfill protocol and encoding restrictions.
|
|
||||||
*/
|
|
||||||
public triggerMouseEvent(e: ICoreMouseEvent): boolean {
|
|
||||||
// range check for col/row
|
|
||||||
if (e.col < 0 || e.col >= this._bufferService.cols
|
|
||||||
|| e.row < 0 || e.row >= this._bufferService.rows) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// filter nonsense combinations of button + action
|
|
||||||
if (e.button === CoreMouseButton.WHEEL && e.action === CoreMouseAction.MOVE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (e.button === CoreMouseButton.NONE && e.action !== CoreMouseAction.MOVE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (e.button !== CoreMouseButton.WHEEL && (e.action === CoreMouseAction.LEFT || e.action === CoreMouseAction.RIGHT)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// report 1-based coords
|
|
||||||
e.col++;
|
|
||||||
e.row++;
|
|
||||||
|
|
||||||
// debounce move events at grid or pixel level
|
|
||||||
if (e.action === CoreMouseAction.MOVE
|
|
||||||
&& this._lastEvent
|
|
||||||
&& this._equalEvents(this._lastEvent, e, this._activeEncoding === 'SGR_PIXELS')
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply protocol restrictions
|
|
||||||
if (!this._protocols[this._activeProtocol].restrict(e)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode report and send
|
|
||||||
const report = this._encodings[this._activeEncoding](e);
|
|
||||||
if (report) {
|
|
||||||
// always send DEFAULT as binary data
|
|
||||||
if (this._activeEncoding === 'DEFAULT') {
|
|
||||||
this._coreService.triggerBinaryEvent(report);
|
|
||||||
} else {
|
|
||||||
this._coreService.triggerDataEvent(report, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._lastEvent = e;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public explainEvents(events: CoreMouseEventType): { [event: string]: boolean } {
|
public get isDefaultEncoding(): boolean {
|
||||||
return {
|
return this._activeEncoding === 'DEFAULT';
|
||||||
down: !!(events & CoreMouseEventType.DOWN),
|
|
||||||
up: !!(events & CoreMouseEventType.UP),
|
|
||||||
drag: !!(events & CoreMouseEventType.DRAG),
|
|
||||||
move: !!(events & CoreMouseEventType.MOVE),
|
|
||||||
wheel: !!(events & CoreMouseEventType.WHEEL)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _equalEvents(e1: ICoreMouseEvent, e2: ICoreMouseEvent, pixels: boolean): boolean {
|
public get isPixelEncoding(): boolean {
|
||||||
if (pixels) {
|
return this._activeEncoding === 'SGR_PIXELS';
|
||||||
if (e1.x !== e2.x) return false;
|
|
||||||
if (e1.y !== e2.y) return false;
|
|
||||||
} else {
|
|
||||||
if (e1.col !== e2.col) return false;
|
|
||||||
if (e1.row !== e2.row) return false;
|
|
||||||
}
|
|
||||||
if (e1.button !== e2.button) return false;
|
|
||||||
if (e1.action !== e2.action) return false;
|
|
||||||
if (e1.ctrl !== e2.ctrl) return false;
|
|
||||||
if (e1.alt !== e2.alt) return false;
|
|
||||||
if (e1.shift !== e2.shift) return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,43 +43,17 @@ export interface IMouseStateService {
|
|||||||
addProtocol(name: string, protocol: ICoreMouseProtocol): void;
|
addProtocol(name: string, protocol: ICoreMouseProtocol): void;
|
||||||
addEncoding(name: string, encoding: CoreMouseEncoding): void;
|
addEncoding(name: string, encoding: CoreMouseEncoding): void;
|
||||||
reset(): void;
|
reset(): void;
|
||||||
|
setCustomWheelEventHandler(customWheelEventHandler: ((event: WheelEvent) => boolean) | undefined): void;
|
||||||
/**
|
allowCustomWheelEvent(ev: WheelEvent): boolean;
|
||||||
* Triggers a mouse event to be sent.
|
|
||||||
*
|
|
||||||
* Returns true if the event passed all protocol restrictions and a report
|
|
||||||
* was sent, otherwise false. The return value may be used to decide whether
|
|
||||||
* the default event action in the bowser component should be omitted.
|
|
||||||
*
|
|
||||||
* Note: The method will change values of the given event object
|
|
||||||
* to fullfill protocol and encoding restrictions.
|
|
||||||
*/
|
|
||||||
triggerMouseEvent(event: ICoreMouseEvent): boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event to announce changes in mouse tracking.
|
* Event to announce changes in mouse tracking.
|
||||||
*/
|
*/
|
||||||
onProtocolChange: IEvent<CoreMouseEventType>;
|
onProtocolChange: IEvent<CoreMouseEventType>;
|
||||||
|
restrictMouseEvent(event: ICoreMouseEvent): boolean;
|
||||||
/**
|
encodeMouseEvent(event: ICoreMouseEvent): string;
|
||||||
* Human readable version of mouse events.
|
readonly isDefaultEncoding: boolean;
|
||||||
*/
|
readonly isPixelEncoding: boolean;
|
||||||
explainEvents(events: CoreMouseEventType): { [event: string]: boolean };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process wheel event taking partial scroll into account.
|
|
||||||
*/
|
|
||||||
consumeWheelEvent(ev: WheelEvent, cellHeight?: number, dpr?: number): number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a custom wheel event handler that can veto wheel processing.
|
|
||||||
*/
|
|
||||||
setCustomWheelEventHandler(customWheelEventHandler: ((event: WheelEvent) => boolean) | undefined): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether a wheel event should be processed.
|
|
||||||
*/
|
|
||||||
allowCustomWheelEvent(ev: WheelEvent): boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ICoreService = createDecorator<ICoreService>('CoreService');
|
export const ICoreService = createDecorator<ICoreService>('CoreService');
|
||||||
|
|||||||
Reference in New Issue
Block a user