From: Daniel Imms Date: Sat, 6 May 2017 00:36:15 +0000 (-0700) Subject: Basic fetching of coordinates X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=70fda994151c803fccaf51f465f6857fb398c18f;p=mirror_xterm.js.git Basic fetching of coordinates --- diff --git a/src/EventEmitter.ts b/src/EventEmitter.ts index 1db8676..a4fd454 100644 --- a/src/EventEmitter.ts +++ b/src/EventEmitter.ts @@ -53,14 +53,11 @@ export class EventEmitter { return this.on(type, on); } - public emit(type): void { + public emit(type: string, ...args: any[]): void { if (!this._events[type]) { return; } - - let args = Array.prototype.slice.call(arguments, 1); let obj = this._events[type]; - for (let i = 0; i < obj.length; i++) { obj[i].apply(this, args); } diff --git a/src/Parser.ts b/src/Parser.ts index 01821a5..92ff159 100644 --- a/src/Parser.ts +++ b/src/Parser.ts @@ -471,6 +471,8 @@ export class Parser { case ParserState.DCS: if (ch === C0.ESC || ch === C0.BEL) { if (ch === C0.ESC) this._position++; + let pt; + let valid; switch (this._terminal.prefix) { // User-Defined Keys (DECUDK). @@ -480,8 +482,8 @@ export class Parser { // Request Status String (DECRQSS). // test: echo -e '\eP$q"p\e\\' case '$q': - let pt = this._terminal.currentParam - , valid = false; + pt = this._terminal.currentParam; + valid = false; switch (pt) { // DECSCA @@ -526,9 +528,8 @@ export class Parser { // This can cause a small glitch in vim. // test: echo -ne '\eP+q6b64\e\\' case '+q': - // TODO: Don't declare pt twice - /*let*/ pt = this._terminal.currentParam - , valid = false; + pt = this._terminal.currentParam; + valid = false; this._terminal.send(C0.ESC + 'P' + +valid + '+r' + pt + C0.ESC + '\\'); break; diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts new file mode 100644 index 0000000..df9294b --- /dev/null +++ b/src/SelectionManager.ts @@ -0,0 +1,65 @@ +/** + * @license MIT + */ + +import { CharMeasure } from './utils/CharMeasure'; +import { CircularList } from './utils/CircularList'; +import * as Mouse from './utils/Mouse'; + +export class SelectionManager { + private _selectionStart: [number, number]; + private _selectionEnd: [number, number]; + + private _buffer: CircularList; + private _rowContainer: HTMLElement; + private _charMeasure: CharMeasure; + + private _mouseMoveListener: EventListener; + + constructor(buffer: CircularList, rowContainer: HTMLElement, charMeasure: CharMeasure) { + this._rowContainer = rowContainer; + this._buffer = buffer; + this._charMeasure = charMeasure; + this._attachListeners(); + } + + private _attachListeners() { + this._mouseMoveListener = event => this._onMouseMove(event); + + this._buffer.on('trim', amount => this._onTrim(amount)); + this._rowContainer.addEventListener('mousedown', event => this._onMouseDown(event)); + this._rowContainer.addEventListener('mouseup', event => this._onMouseUp(event)); + } + + public get selectionText(): string { + if (!this._selectionStart || !this._selectionEnd) { + return null; + } + return ''; + } + + private _onTrim(amount: number) { + console.log('trimmed: ' + amount); + } + + private _onMouseDown(event: MouseEvent) { + this._selectionStart = Mouse.getCoords(event, this._rowContainer, this._charMeasure); + if (this._selectionStart) { + this._rowContainer.addEventListener('mousemove', this._mouseMoveListener); + } + } + + private _onMouseMove(event: MouseEvent) { + this._selectionEnd = Mouse.getCoords(event, this._rowContainer, this._charMeasure); + } + + private _onMouseUp(event: MouseEvent) { + console.log('mouseup'); + console.log('start', this._selectionStart); + console.log('end', this._selectionEnd); + if (!this._selectionStart) { + return; + } + this._rowContainer.removeEventListener('mousemove', this._mouseMoveListener); + } +} diff --git a/src/utils/CircularList.ts b/src/utils/CircularList.ts index b72c667..909df76 100644 --- a/src/utils/CircularList.ts +++ b/src/utils/CircularList.ts @@ -4,12 +4,15 @@ * @module xterm/utils/CircularList * @license MIT */ -export class CircularList { +import { EventEmitter } from '../EventEmitter'; + +export class CircularList extends EventEmitter { private _array: T[]; private _startIndex: number; private _length: number; constructor(maxLength: number) { + super(); this._array = new Array(maxLength); this._startIndex = 0; this._length = 0; @@ -83,6 +86,7 @@ export class CircularList { if (this._startIndex === this.maxLength) { this._startIndex = 0; } + this.emit('trim', 1); } else { this._length++; } @@ -121,8 +125,10 @@ export class CircularList { } if (this._length + items.length > this.maxLength) { - this._startIndex += (this._length + items.length) - this.maxLength; + const countToTrim = (this._length + items.length) - this.maxLength; + this._startIndex += countToTrim; this._length = this.maxLength; + this.emit('trim', countToTrim); } else { this._length += items.length; } @@ -139,6 +145,7 @@ export class CircularList { } this._startIndex += count; this._length -= count; + this.emit('trim', count); } public shiftElements(start: number, count: number, offset: number): void { @@ -162,6 +169,7 @@ export class CircularList { while (this._length > this.maxLength) { this._length--; this._startIndex++; + this.emit('trim', 1); } } } else { diff --git a/src/utils/Mouse.ts b/src/utils/Mouse.ts new file mode 100644 index 0000000..7b18d41 --- /dev/null +++ b/src/utils/Mouse.ts @@ -0,0 +1,30 @@ +/** + * @license MIT + */ + +import { CharMeasure } from './CharMeasure'; + +export function getCoords(event: MouseEvent, rowContainer: HTMLElement, charMeasure: CharMeasure): [number, number] { + // ignore browsers without pageX for now + if (event.pageX == null) { + return null; + } + + let x = event.pageX; + let y = event.pageY; + let el = rowContainer; + + // should probably check offsetParent + // but this is more portable + while (el && el !== self.document.documentElement) { + x -= el.offsetLeft; + y -= el.offsetTop; + el = 'offsetParent' in el ? el.offsetParent : el.parentElement; + } + + // convert to cols/rows + x = Math.ceil(x / charMeasure.width); + y = Math.ceil(y / charMeasure.height); + + return [x, y]; +} diff --git a/src/xterm.css b/src/xterm.css index a67485e..72c1b85 100644 --- a/src/xterm.css +++ b/src/xterm.css @@ -41,6 +41,7 @@ font-family: courier-new, courier, monospace; font-feature-settings: "liga" 0; position: relative; + user-select: none; } .terminal.focus, diff --git a/src/xterm.js b/src/xterm.js index 75d0bc4..dd3a090 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -20,9 +20,10 @@ import { InputHandler } from './InputHandler'; import { Parser } from './Parser'; import { Renderer } from './Renderer'; import { Linkifier } from './Linkifier'; +import { SelectionManager } from './SelectionManager'; import { CharMeasure } from './utils/CharMeasure'; import * as Browser from './utils/Browser'; -import * as Keyboard from './utils/Keyboard'; +import * as Mouse from './utils/Mouse'; import { CHARSETS } from './Charsets'; /** @@ -219,6 +220,7 @@ function Terminal(options) { this.parser = new Parser(this.inputHandler, this); // Reuse renderer if the Terminal is being recreated via a Terminal.reset call. this.renderer = this.renderer || null; + this.selectionManager = this.selectionManager || null; this.linkifier = this.linkifier || new Linkifier(); // user input states @@ -689,6 +691,7 @@ Terminal.prototype.open = function(parent, focus) { this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure); this.renderer = new Renderer(this); + this.selectionManager = new SelectionManager(this.lines, this.rowContainer, this.charMeasure); // Setup loop that draws to screen this.refresh(0, this.rows - 1); @@ -787,7 +790,7 @@ Terminal.prototype.bindMouse = function() { button = getButton(ev); // get mouse coordinates - pos = getCoords(ev); + pos = Mouse.getCoords(ev, this.rowContainer, this.charMeasure); if (!pos) return; sendEvent(button, pos); @@ -815,7 +818,7 @@ Terminal.prototype.bindMouse = function() { var button = pressed , pos; - pos = getCoords(ev); + pos = Mouse.getCoords(ev, this.rowContainer, this.charMeasure); if (!pos) return; // buttons marked as motions @@ -991,48 +994,48 @@ Terminal.prototype.bindMouse = function() { } // mouse coordinates measured in cols/rows - function getCoords(ev) { - var x, y, w, h, el; - - // ignore browsers without pageX for now - if (ev.pageX == null) return; - - x = ev.pageX; - y = ev.pageY; - el = self.element; - - // should probably check offsetParent - // but this is more portable - while (el && el !== self.document.documentElement) { - x -= el.offsetLeft; - y -= el.offsetTop; - el = 'offsetParent' in el - ? el.offsetParent - : el.parentNode; - } + // function getCoords(ev) { + // var x, y, w, h, el; + + // // ignore browsers without pageX for now + // if (ev.pageX == null) return; + + // x = ev.pageX; + // y = ev.pageY; + // el = self.rowContainer; + + // // should probably check offsetParent + // // but this is more portable + // while (el && el !== self.document.documentElement) { + // x -= el.offsetLeft; + // y -= el.offsetTop; + // el = 'offsetParent' in el + // ? el.offsetParent + // : el.parentNode; + // } - // convert to cols/rows - x = Math.ceil(x / self.charMeasure.width); - y = Math.ceil(y / self.charMeasure.height); - - // be sure to avoid sending - // bad positions to the program - if (x < 0) x = 0; - if (x > self.cols) x = self.cols; - if (y < 0) y = 0; - if (y > self.rows) y = self.rows; - - // xterm sends raw bytes and - // starts at 32 (SP) for each. - x += 32; - y += 32; - - return { - x: x, - y: y, - type: 'wheel' - }; - } + // // convert to cols/rows + // x = Math.ceil(x / self.charMeasure.width); + // y = Math.ceil(y / self.charMeasure.height); + + // // be sure to avoid sending + // // bad positions to the program + // if (x < 0) x = 0; + // if (x > self.cols) x = self.cols; + // if (y < 0) y = 0; + // if (y > self.rows) y = self.rows; + + // // xterm sends raw bytes and + // // starts at 32 (SP) for each. + // x += 32; + // y += 32; + + // return { + // x: x, + // y: y, + // type: 'wheel' + // }; + // } on(el, 'mousedown', function(ev) { if (!self.mouseEvents) return;