Introduce mouse service
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import jsdom = require('jsdom');
|
||||
import { assert } from 'chai';
|
||||
import { getCoords } from 'browser/input/Mouse';
|
||||
|
||||
const CHAR_WIDTH = 10;
|
||||
const CHAR_HEIGHT = 20;
|
||||
|
||||
describe('Mouse getCoords', () => {
|
||||
let document: Document;
|
||||
|
||||
beforeEach(() => {
|
||||
document = new jsdom.JSDOM('').window.document;
|
||||
});
|
||||
|
||||
it('should return the cell that was clicked', () => {
|
||||
let coords: [number, number] | undefined;
|
||||
coords = getCoords({ clientX: CHAR_WIDTH / 2, clientY: CHAR_HEIGHT / 2 }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT);
|
||||
assert.deepEqual(coords, [1, 1]);
|
||||
coords = getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT);
|
||||
assert.deepEqual(coords, [1, 1]);
|
||||
coords = getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT + 1 }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT);
|
||||
assert.deepEqual(coords, [1, 2]);
|
||||
coords = getCoords({ clientX: CHAR_WIDTH + 1, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT);
|
||||
assert.deepEqual(coords, [2, 1]);
|
||||
});
|
||||
|
||||
it('should ensure the coordinates are returned within the terminal bounds', () => {
|
||||
let coords: [number, number] | undefined;
|
||||
coords = getCoords({ clientX: -1, clientY: -1 }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT);
|
||||
assert.deepEqual(coords, [1, 1]);
|
||||
// Event are double the cols/rows
|
||||
coords = getCoords({ clientX: CHAR_WIDTH * 20, clientY: CHAR_HEIGHT * 20 }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT);
|
||||
assert.deepEqual(coords, [10, 10], 'coordinates should never come back as larger than the terminal');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
export function getCoordsRelativeToElement(event: {clientX: number, clientY: number}, element: HTMLElement): [number, number] {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return [event.clientX - rect.left, event.clientY - rect.top];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets coordinates within the terminal for a particular mouse event. The result
|
||||
* is returned as an array in the form [x, y] instead of an object as it's a
|
||||
* little faster and this function is used in some low level code.
|
||||
* @param event The mouse event.
|
||||
* @param element The terminal's container element.
|
||||
* @param colCount The number of columns in the terminal.
|
||||
* @param rowCount The number of rows n the terminal.
|
||||
* @param isSelection Whether the request is for the selection or not. This will
|
||||
* apply an offset to the x value such that the left half of the cell will
|
||||
* select that cell and the right half will select the next cell.
|
||||
*/
|
||||
export function getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, hasValidCharSize: boolean, actualCellWidth: number, actualCellHeight: number, isSelection?: boolean): [number, number] | undefined {
|
||||
// Coordinates cannot be measured if there are no valid
|
||||
if (!hasValidCharSize) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const coords = getCoordsRelativeToElement(event, element);
|
||||
if (!coords) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
coords[0] = Math.ceil((coords[0] + (isSelection ? actualCellWidth / 2 : 0)) / actualCellWidth);
|
||||
coords[1] = Math.ceil(coords[1] / actualCellHeight);
|
||||
|
||||
// Ensure coordinates are within the terminal viewport. Note that selections
|
||||
// need an addition point of precision to cover the end point (as characters
|
||||
// cover half of one char and half of the next).
|
||||
coords[0] = Math.min(Math.max(coords[0], 1), colCount + (isSelection ? 1 : 0));
|
||||
coords[1] = Math.min(Math.max(coords[1], 1), rowCount);
|
||||
|
||||
return coords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets coordinates within the terminal for a particular mouse event, wrapping
|
||||
* them to the bounds of the terminal and adding 32 to both the x and y values
|
||||
* as expected by xterm.
|
||||
*/
|
||||
export function getRawByteCoords(coords: [number, number] | undefined): { x: number, y: number } | undefined {
|
||||
if (!coords) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// xterm sends raw bytes and starts at 32 (SP) for each.
|
||||
return { x: coords[0] + 32, y: coords[1] + 32 };
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import jsdom = require('jsdom');
|
||||
import { assert } from 'chai';
|
||||
import { MouseHelper } from 'browser/input/MouseHelper';
|
||||
import { MockCharSizeService } from 'browser/TestUtils.test';
|
||||
|
||||
const CHAR_WIDTH = 10;
|
||||
const CHAR_HEIGHT = 20;
|
||||
|
||||
describe('MouseHelper.getCoords', () => {
|
||||
let document: Document;
|
||||
let mouseHelper: MouseHelper;
|
||||
|
||||
beforeEach(() => {
|
||||
document = new jsdom.JSDOM('').window.document;
|
||||
const mockRenderService = {
|
||||
dimensions: {
|
||||
actualCellWidth: CHAR_WIDTH,
|
||||
actualCellHeight: CHAR_HEIGHT
|
||||
}
|
||||
};
|
||||
mouseHelper = new MouseHelper(mockRenderService as any, new MockCharSizeService(CHAR_WIDTH, CHAR_HEIGHT));
|
||||
});
|
||||
|
||||
it('should return the cell that was clicked', () => {
|
||||
let coords: [number, number] | undefined;
|
||||
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH / 2, clientY: CHAR_HEIGHT / 2 }, document.createElement('div'), 10, 10);
|
||||
assert.deepEqual(coords, [1, 1]);
|
||||
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10);
|
||||
assert.deepEqual(coords, [1, 1]);
|
||||
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT + 1 }, document.createElement('div'), 10, 10);
|
||||
assert.deepEqual(coords, [1, 2]);
|
||||
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH + 1, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10);
|
||||
assert.deepEqual(coords, [2, 1]);
|
||||
});
|
||||
|
||||
it('should ensure the coordinates are returned within the terminal bounds', () => {
|
||||
let coords: [number, number] | undefined;
|
||||
coords = mouseHelper.getCoords({ clientX: -1, clientY: -1 }, document.createElement('div'), 10, 10);
|
||||
assert.deepEqual(coords, [1, 1]);
|
||||
// Event are double the cols/rows
|
||||
coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH * 20, clientY: CHAR_HEIGHT * 20 }, document.createElement('div'), 10, 10);
|
||||
assert.deepEqual(coords, [10, 10], 'coordinates should never come back as larger than the terminal');
|
||||
});
|
||||
});
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IMouseHelper } from 'browser/Types';
|
||||
import { RenderService } from 'browser/services/RenderService';
|
||||
import { ICharSizeService } from 'browser/services/Services';
|
||||
|
||||
export class MouseHelper implements IMouseHelper {
|
||||
constructor(
|
||||
private _renderService: RenderService,
|
||||
private _charSizeService: ICharSizeService
|
||||
) {
|
||||
}
|
||||
|
||||
public static getCoordsRelativeToElement(event: {clientX: number, clientY: number}, element: HTMLElement): [number, number] {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return [event.clientX - rect.left, event.clientY - rect.top];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets coordinates within the terminal for a particular mouse event. The result
|
||||
* is returned as an array in the form [x, y] instead of an object as it's a
|
||||
* little faster and this function is used in some low level code.
|
||||
* @param event The mouse event.
|
||||
* @param element The terminal's container element.
|
||||
* @param colCount The number of columns in the terminal.
|
||||
* @param rowCount The number of rows n the terminal.
|
||||
* @param isSelection Whether the request is for the selection or not. This will
|
||||
* apply an offset to the x value such that the left half of the cell will
|
||||
* select that cell and the right half will select the next cell.
|
||||
*/
|
||||
public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined {
|
||||
// Coordinates cannot be measured if there are no valid
|
||||
if (!this._charSizeService.hasValidSize) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const coords = MouseHelper.getCoordsRelativeToElement(event, element);
|
||||
if (!coords) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
coords[0] = Math.ceil((coords[0] + (isSelection ? this._renderService.dimensions.actualCellWidth / 2 : 0)) / this._renderService.dimensions.actualCellWidth);
|
||||
coords[1] = Math.ceil(coords[1] / this._renderService.dimensions.actualCellHeight);
|
||||
|
||||
// Ensure coordinates are within the terminal viewport. Note that selections
|
||||
// need an addition point of precision to cover the end point (as characters
|
||||
// cover half of one char and half of the next).
|
||||
coords[0] = Math.min(Math.max(coords[0], 1), colCount + (isSelection ? 1 : 0));
|
||||
coords[1] = Math.min(Math.max(coords[1], 1), rowCount);
|
||||
|
||||
return coords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets coordinates within the terminal for a particular mouse event, wrapping
|
||||
* them to the bounds of the terminal and adding 32 to both the x and y values
|
||||
* as expected by xterm.
|
||||
* @param event The mouse event.
|
||||
* @param element The terminal's container element.
|
||||
* @param colCount The number of columns in the terminal.
|
||||
* @param rowCount The number of rows in the terminal.
|
||||
*/
|
||||
public getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number | undefined, y: number | undefined } {
|
||||
const coords = this.getCoords(event, element, colCount, rowCount);
|
||||
|
||||
// xterm sends raw bytes and starts at 32 (SP) for each.
|
||||
const x = coords ? coords[0] + 32 : undefined;
|
||||
const y = coords ? coords[1] + 32 : undefined;
|
||||
|
||||
return { x, y };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user