From dc165175cfcff9bfb17e5133aed05869c6f80eb6 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 20 Jun 2017 10:18:29 -0700 Subject: [PATCH] Handle middle click to paste selection This appears to work in Chrome but not Firefox --- src/SelectionManager.ts | 22 ++++++++++------------ src/handlers/Clipboard.ts | 2 +- src/utils/Browser.ts | 1 + src/xterm.js | 20 +++++++++++++++++--- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 63720b86..8c05cd7c 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -2,10 +2,11 @@ * @license MIT */ +import * as Mouse from './utils/Mouse'; +import * as Browser from './utils/Browser'; import { CharMeasure } from './utils/CharMeasure'; import { CircularList } from './utils/CircularList'; import { EventEmitter } from './EventEmitter'; -import * as Mouse from './utils/Mouse'; import { ITerminal } from './Interfaces'; import { SelectionModel } from './SelectionModel'; @@ -299,16 +300,13 @@ export class SelectionManager extends EventEmitter { this._refreshAnimationFrame = window.requestAnimationFrame(() => this._refresh()); } - // If the refresh comes from a mouse event then emit a newselection event - if (!fromMouseEvent) { - return; - } - // TODO: Only do this when the selection has actually changed - // TODO: Ensure we're not doing more work than absolutely necessary, particularly for large selections - // TODO: Only do this on Linux - const selectionText = this.selectionText; - if (selectionText.length) { - this.emit('newselection', this.selectionText); + // If the platform is Linux and the refresh call comes from a mouse event, + // we need to update the selection for middle click to paste selection. + if (Browser.isLinux && fromMouseEvent) { + const selectionText = this.selectionText; + if (selectionText.length) { + this.emit('newselection', this.selectionText); + } } } @@ -560,7 +558,7 @@ export class SelectionManager extends EventEmitter { if (!previousSelectionEnd || previousSelectionEnd[0] !== this._model.selectionEnd[0] || previousSelectionEnd[1] !== this._model.selectionEnd[1]) { - this.refresh(); + this.refresh(true); } } diff --git a/src/handlers/Clipboard.ts b/src/handlers/Clipboard.ts index f22523fd..95945088 100644 --- a/src/handlers/Clipboard.ts +++ b/src/handlers/Clipboard.ts @@ -80,7 +80,7 @@ export function pasteHandler(ev: ClipboardEvent, term: ITerminal) { * @param term The terminal on which to apply the handled paste event * @param selectionManager The terminal's selection manager. */ -export function rightClickHandler(ev: MouseEvent, textarea: HTMLTextAreaElement, selectionManager: ISelectionManager) { +export function moveTextAreaUnderMouseCursor(ev: MouseEvent, textarea: HTMLTextAreaElement, selectionManager: ISelectionManager) { // Bring textarea at the cursor position textarea.style.position = 'fixed'; textarea.style.width = '20px'; diff --git a/src/utils/Browser.ts b/src/utils/Browser.ts index 04da698e..68148aeb 100644 --- a/src/utils/Browser.ts +++ b/src/utils/Browser.ts @@ -20,3 +20,4 @@ export const isMac = contains(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], pla export const isIpad = platform === 'iPad'; export const isIphone = platform === 'iPhone'; export const isMSWindows = contains(['Windows', 'Win16', 'Win32', 'WinCE'], platform); +export const isLinux = platform.indexOf('Linux') >= 0; diff --git a/src/xterm.js b/src/xterm.js index fcd42376..1bcb45d0 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -13,7 +13,7 @@ import { CompositionHelper } from './CompositionHelper'; import { EventEmitter } from './EventEmitter'; import { Viewport } from './Viewport'; -import { rightClickHandler, pasteHandler, copyHandler } from './handlers/Clipboard'; +import { moveTextAreaUnderMouseCursor, pasteHandler, copyHandler } from './handlers/Clipboard'; import { CircularList } from './utils/CircularList'; import { C0 } from './EscapeSequences'; import { InputHandler } from './InputHandler'; @@ -537,15 +537,29 @@ Terminal.prototype.initGlobal = function() { on(this.textarea, 'paste', pasteHandlerWrapper); on(this.element, 'paste', pasteHandlerWrapper); + // Handle right click context menus if (term.browser.isFirefox) { on(this.element, 'mousedown', event => { if (ev.button == 2) { - rightClickHandler(event, this.textarea, this.selectionManager); + moveTextAreaUnderMouseCursor(event, this.textarea, this.selectionManager); } }); } else { on(this.element, 'contextmenu', event => { - rightClickHandler(event, this.textarea, this.selectionManager); + moveTextAreaUnderMouseCursor(event, this.textarea, this.selectionManager); + }); + } + + // Move the textarea under the cursor when middle clicking on Linux to ensure + // middle click to paste selection works. This only appears to work in Chrome + // at the time is writing. + if (term.browser.isLinux) { + // Use auxclick event over mousedown the latter doesn't seem to work. Note + // that the regular click event doesn't fire for the middle mouse button. + on(this.element, 'click', event => { + if (event.button === 1) { + moveTextAreaUnderMouseCursor(event, this.textarea, this.selectionManager); + } }); } };