mirror of https://github.com/elisescu/tty-server
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
4.4 KiB
TypeScript
116 lines
4.4 KiB
TypeScript
import { Terminal, IEvent, IDisposable } from "xterm";
|
|
|
|
import base64 from './base64';
|
|
|
|
interface IRectSize {
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
class TTYReceiver {
|
|
private xterminal: Terminal;
|
|
private containerElement: HTMLElement;
|
|
|
|
constructor(wsAddress: string, container: HTMLDivElement) {
|
|
const connection = new WebSocket(wsAddress);
|
|
|
|
this.xterminal = new Terminal({
|
|
cursorBlink: true,
|
|
macOptionIsMeta: true,
|
|
scrollback: 0,
|
|
fontSize: 12,
|
|
letterSpacing: 0,
|
|
fontFamily: 'SauceCodePro, courier-new, monospace'
|
|
});
|
|
|
|
this.containerElement = container;
|
|
this.xterminal.open(container);
|
|
|
|
connection.onclose = (evt: CloseEvent) => {
|
|
|
|
this.xterminal.blur();
|
|
this.xterminal.setOption('cursorBlink', false);
|
|
this.xterminal.clear();
|
|
this.xterminal.write('Session closed');
|
|
}
|
|
|
|
this.xterminal.focus();
|
|
|
|
const containerPixSize = this.getElementPixelsSize(container);
|
|
const newFontSize = this.guessNewFontSize(this.xterminal.cols, this.xterminal.rows, containerPixSize.width, containerPixSize.height);
|
|
this.xterminal.setOption('fontSize', newFontSize);
|
|
|
|
connection.onmessage = (ev: MessageEvent) => {
|
|
let message = JSON.parse(ev.data)
|
|
let msgData = base64.decode(message.Data)
|
|
|
|
if (message.Type === "Write") {
|
|
let writeMsg = JSON.parse(msgData)
|
|
this.xterminal.writeUtf8(base64.base64ToArrayBuffer(writeMsg.Data));
|
|
}
|
|
|
|
if (message.Type == "WinSize") {
|
|
let winSizeMsg = JSON.parse(msgData)
|
|
|
|
const containerPixSize = this.getElementPixelsSize(container);
|
|
const newFontSize = this.guessNewFontSize(winSizeMsg.Cols, winSizeMsg.Rows, containerPixSize.width, containerPixSize.height);
|
|
this.xterminal.setOption('fontSize', newFontSize);
|
|
|
|
// Now set the new size.
|
|
this.xterminal.resize(winSizeMsg.Cols, winSizeMsg.Rows)
|
|
}
|
|
}
|
|
|
|
// TODO: .on() is deprecated. Should be replaced.
|
|
this.xterminal.on('data', function (data) {
|
|
let writeMessage = {
|
|
Type: "Write",
|
|
Data: base64.encode(JSON.stringify({ Size: data.length, Data: base64.encode(data)})),
|
|
}
|
|
let dataToSend = JSON.stringify(writeMessage)
|
|
connection.send(dataToSend);
|
|
});
|
|
|
|
}
|
|
|
|
// Get the pixels size of the element, after all CSS was applied. This will be used in an ugly
|
|
// hack to guess what fontSize to set on the xterm object. Horrible hack, but I feel less bad
|
|
// about it seeing that VSV does it too:
|
|
// https://github.com/microsoft/vscode/blob/d14ee7613fcead91c5c3c2bddbf288c0462be876/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts#L363
|
|
private getElementPixelsSize(element: HTMLElement): IRectSize {
|
|
const defView = this.containerElement.ownerDocument.defaultView;
|
|
let width = parseInt(defView.getComputedStyle(element).getPropertyValue('width').replace('px', ''), 10);
|
|
let height = parseInt(defView.getComputedStyle(element).getPropertyValue('height').replace('px', ''), 10);
|
|
|
|
return {
|
|
width,
|
|
height,
|
|
}
|
|
}
|
|
|
|
// Tries to guess the new font size, for the new terminal size, so that the rendered terminal
|
|
// will have the newWidth and newHeight dimensions
|
|
private guessNewFontSize(newCols: number, newRows: number, targetWidth: number, targetHeight: number): number {
|
|
const cols = this.xterminal.cols;
|
|
const rows = this.xterminal.rows;
|
|
const fontSize = this.xterminal.getOption('fontSize');
|
|
const xtermPixelsSize = this.getElementPixelsSize(this.containerElement.querySelector(".xterm-screen"));
|
|
|
|
const newHFontSizeMultiplier = (cols / newCols) * (targetWidth / xtermPixelsSize.width);
|
|
const newVFontSizeMultiplier = (rows / newRows) * (targetHeight / xtermPixelsSize.height);
|
|
|
|
let newFontSize;
|
|
|
|
if (newHFontSizeMultiplier > newVFontSizeMultiplier) {
|
|
newFontSize = Math.floor(fontSize * newVFontSizeMultiplier);
|
|
} else {
|
|
newFontSize = Math.floor(fontSize * newHFontSizeMultiplier);
|
|
}
|
|
return newFontSize;
|
|
}
|
|
}
|
|
|
|
export {
|
|
TTYReceiver
|
|
}
|