Files
xterm.js/src/InputHandler.ts
T

490 lines
14 KiB
TypeScript

import { IInputHandler, ITerminal } from './Interfaces';
import { C0 } from './EscapeSequences';
export class InputHandler implements IInputHandler {
// TODO: We want to type _terminal when it's pulled into TS
constructor(private _terminal: any) { }
/**
* BEL
* Bell (Ctrl-G).
*/
public bell(): void {
if (!this._terminal.visualBell) {
return;
}
this._terminal.element.style.borderColor = 'white';
setTimeout(() => this._terminal.element.style.borderColor = '', 10);
if (this._terminal.popOnBell) {
this._terminal.focus();
}
}
/**
* LF
* Line Feed or New Line (NL). (LF is Ctrl-J).
*/
public lineFeed(): void {
if (this._terminal.convertEol) {
this._terminal.x = 0;
}
this._terminal.y++;
if (this._terminal.y > this._terminal.scrollBottom) {
this._terminal.y--;
this._terminal.scroll();
}
}
/**
* CR
* Carriage Return (Ctrl-M).
*/
public carriageReturn(): void {
this._terminal.x = 0;
}
/**
* BS
* Backspace (Ctrl-H).
*/
public backspace(): void {
if (this._terminal.x > 0) {
this._terminal.x--;
}
}
/**
* TAB
* Horizontal Tab (HT) (Ctrl-I).
*/
public tab(): void {
this._terminal.x = this._terminal.nextStop();
}
/**
* SO
* Shift Out (Ctrl-N) -> Switch to Alternate Character Set. This invokes the
* G1 character set.
*/
public shiftOut(): void {
this._terminal.setgLevel(1);
}
/**
* SI
* Shift In (Ctrl-O) -> Switch to Standard Character Set. This invokes the G0
* character set (the default).
*/
public shiftIn(): void {
this._terminal.setgLevel(0);
}
/**
* CSI Ps A
* Cursor Up Ps Times (default = 1) (CUU).
*/
public cursorUp(params: number[]): void {
let param = params[0];
if (param < 1) {
param = 1;
}
this._terminal.y -= param;
if (this._terminal.y < 0) {
this._terminal.y = 0;
}
}
/**
* CSI Ps B
* Cursor Down Ps Times (default = 1) (CUD).
*/
public cursorDown(params: number[]) {
let param = params[0];
if (param < 1) {
param = 1;
}
this._terminal.y += param;
if (this._terminal.y >= this._terminal.rows) {
this._terminal.y = this._terminal.rows - 1;
}
}
/**
* CSI Ps C
* Cursor Forward Ps Times (default = 1) (CUF).
*/
public cursorForward(params: number[]) {
let param = params[0];
if (param < 1) {
param = 1;
}
this._terminal.x += param;
if (this._terminal.x >= this._terminal.cols) {
this._terminal.x = this._terminal.cols - 1;
}
}
/**
* CSI Ps D
* Cursor Backward Ps Times (default = 1) (CUB).
*/
public cursorBackward(params: number[]) {
let param = params[0];
if (param < 1) {
param = 1;
}
this._terminal.x -= param;
if (this._terminal.x < 0) {
this._terminal.x = 0;
}
}
/**
* CSI Ps ; Ps H
* Cursor Position [row;column] (default = [1,1]) (CUP).
*/
public cursorPosition(params: number[]) {
let row, col;
row = params[0] - 1;
if (params.length >= 2) {
col = params[1] - 1;
} else {
col = 0;
}
if (row < 0) {
row = 0;
} else if (row >= this._terminal.rows) {
row = this._terminal.rows - 1;
}
if (col < 0) {
col = 0;
} else if (col >= this._terminal.cols) {
col = this._terminal.cols - 1;
}
this._terminal.x = col;
this._terminal.y = row;
}
/**
* CSI Ps J Erase in Display (ED).
* Ps = 0 -> Erase Below (default).
* Ps = 1 -> Erase Above.
* Ps = 2 -> Erase All.
* Ps = 3 -> Erase Saved Lines (xterm).
* CSI ? Ps J
* Erase in Display (DECSED).
* Ps = 0 -> Selective Erase Below (default).
* Ps = 1 -> Selective Erase Above.
* Ps = 2 -> Selective Erase All.
*/
public eraseInDisplay(params: number[]) {
let j;
switch (params[0]) {
case 0:
this._terminal.eraseRight(this._terminal.x, this._terminal.y);
j = this._terminal.y + 1;
for (; j < this._terminal.rows; j++) {
this._terminal.eraseLine(j);
}
break;
case 1:
this._terminal.eraseLeft(this._terminal.x, this._terminal.y);
j = this._terminal.y;
while (j--) {
this._terminal.eraseLine(j);
}
break;
case 2:
j = this._terminal.rows;
while (j--) this._terminal.eraseLine(j);
break;
case 3:
; // no saved lines
break;
}
}
/**
* CSI Ps K Erase in Line (EL).
* Ps = 0 -> Erase to Right (default).
* Ps = 1 -> Erase to Left.
* Ps = 2 -> Erase All.
* CSI ? Ps K
* Erase in Line (DECSEL).
* Ps = 0 -> Selective Erase to Right (default).
* Ps = 1 -> Selective Erase to Left.
* Ps = 2 -> Selective Erase All.
*/
public eraseInLine(params: number[]) {
switch (params[0]) {
case 0:
this._terminal.eraseRight(this._terminal.x, this._terminal.y);
break;
case 1:
this._terminal.eraseLeft(this._terminal.x, this._terminal.y);
break;
case 2:
this._terminal.eraseLine(this._terminal.y);
break;
}
}
/**
* CSI Pm m Character Attributes (SGR).
* Ps = 0 -> Normal (default).
* Ps = 1 -> Bold.
* Ps = 4 -> Underlined.
* Ps = 5 -> Blink (appears as Bold).
* Ps = 7 -> Inverse.
* Ps = 8 -> Invisible, i.e., hidden (VT300).
* Ps = 2 2 -> Normal (neither bold nor faint).
* Ps = 2 4 -> Not underlined.
* Ps = 2 5 -> Steady (not blinking).
* Ps = 2 7 -> Positive (not inverse).
* Ps = 2 8 -> Visible, i.e., not hidden (VT300).
* Ps = 3 0 -> Set foreground color to Black.
* Ps = 3 1 -> Set foreground color to Red.
* Ps = 3 2 -> Set foreground color to Green.
* Ps = 3 3 -> Set foreground color to Yellow.
* Ps = 3 4 -> Set foreground color to Blue.
* Ps = 3 5 -> Set foreground color to Magenta.
* Ps = 3 6 -> Set foreground color to Cyan.
* Ps = 3 7 -> Set foreground color to White.
* Ps = 3 9 -> Set foreground color to default (original).
* Ps = 4 0 -> Set background color to Black.
* Ps = 4 1 -> Set background color to Red.
* Ps = 4 2 -> Set background color to Green.
* Ps = 4 3 -> Set background color to Yellow.
* Ps = 4 4 -> Set background color to Blue.
* Ps = 4 5 -> Set background color to Magenta.
* Ps = 4 6 -> Set background color to Cyan.
* Ps = 4 7 -> Set background color to White.
* Ps = 4 9 -> Set background color to default (original).
*
* If 16-color support is compiled, the following apply. Assume
* that xterm's resources are set so that the ISO color codes are
* the first 8 of a set of 16. Then the aixterm colors are the
* bright versions of the ISO colors:
* Ps = 9 0 -> Set foreground color to Black.
* Ps = 9 1 -> Set foreground color to Red.
* Ps = 9 2 -> Set foreground color to Green.
* Ps = 9 3 -> Set foreground color to Yellow.
* Ps = 9 4 -> Set foreground color to Blue.
* Ps = 9 5 -> Set foreground color to Magenta.
* Ps = 9 6 -> Set foreground color to Cyan.
* Ps = 9 7 -> Set foreground color to White.
* Ps = 1 0 0 -> Set background color to Black.
* Ps = 1 0 1 -> Set background color to Red.
* Ps = 1 0 2 -> Set background color to Green.
* Ps = 1 0 3 -> Set background color to Yellow.
* Ps = 1 0 4 -> Set background color to Blue.
* Ps = 1 0 5 -> Set background color to Magenta.
* Ps = 1 0 6 -> Set background color to Cyan.
* Ps = 1 0 7 -> Set background color to White.
*
* If xterm is compiled with the 16-color support disabled, it
* supports the following, from rxvt:
* Ps = 1 0 0 -> Set foreground and background color to
* default.
*
* If 88- or 256-color support is compiled, the following apply.
* Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second
* Ps.
* Ps = 4 8 ; 5 ; Ps -> Set background color to the second
* Ps.
*/
public charAttributes(params: number[]) {
// Optimize a single SGR0.
if (params.length === 1 && params[0] === 0) {
this._terminal.curAttr = this._terminal.defAttr;
return;
}
let l = params.length
, i = 0
, flags = this._terminal.curAttr >> 18
, fg = (this._terminal.curAttr >> 9) & 0x1ff
, bg = this._terminal.curAttr & 0x1ff
, p;
for (; i < l; i++) {
p = params[i];
if (p >= 30 && p <= 37) {
// fg color 8
fg = p - 30;
} else if (p >= 40 && p <= 47) {
// bg color 8
bg = p - 40;
} else if (p >= 90 && p <= 97) {
// fg color 16
p += 8;
fg = p - 90;
} else if (p >= 100 && p <= 107) {
// bg color 16
p += 8;
bg = p - 100;
} else if (p === 0) {
// default
flags = this._terminal.defAttr >> 18;
fg = (this._terminal.defAttr >> 9) & 0x1ff;
bg = this._terminal.defAttr & 0x1ff;
// flags = 0;
// fg = 0x1ff;
// bg = 0x1ff;
} else if (p === 1) {
// bold text
flags |= 1;
} else if (p === 4) {
// underlined text
flags |= 2;
} else if (p === 5) {
// blink
flags |= 4;
} else if (p === 7) {
// inverse and positive
// test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
flags |= 8;
} else if (p === 8) {
// invisible
flags |= 16;
} else if (p === 22) {
// not bold
flags &= ~1;
} else if (p === 24) {
// not underlined
flags &= ~2;
} else if (p === 25) {
// not blink
flags &= ~4;
} else if (p === 27) {
// not inverse
flags &= ~8;
} else if (p === 28) {
// not invisible
flags &= ~16;
} else if (p === 39) {
// reset fg
fg = (this._terminal.defAttr >> 9) & 0x1ff;
} else if (p === 49) {
// reset bg
bg = this._terminal.defAttr & 0x1ff;
} else if (p === 38) {
// fg color 256
if (params[i + 1] === 2) {
i += 2;
fg = this._terminal.matchColor(
params[i] & 0xff,
params[i + 1] & 0xff,
params[i + 2] & 0xff);
if (fg === -1) fg = 0x1ff;
i += 2;
} else if (params[i + 1] === 5) {
i += 2;
p = params[i] & 0xff;
fg = p;
}
} else if (p === 48) {
// bg color 256
if (params[i + 1] === 2) {
i += 2;
bg = this._terminal.matchColor(
params[i] & 0xff,
params[i + 1] & 0xff,
params[i + 2] & 0xff);
if (bg === -1) bg = 0x1ff;
i += 2;
} else if (params[i + 1] === 5) {
i += 2;
p = params[i] & 0xff;
bg = p;
}
} else if (p === 100) {
// reset fg/bg
fg = (this._terminal.defAttr >> 9) & 0x1ff;
bg = this._terminal.defAttr & 0x1ff;
} else {
this._terminal.error('Unknown SGR attribute: %d.', p);
}
}
this._terminal.curAttr = (flags << 18) | (fg << 9) | bg;
}
/**
* CSI Ps n Device Status Report (DSR).
* Ps = 5 -> Status Report. Result (``OK'') is
* CSI 0 n
* Ps = 6 -> Report Cursor Position (CPR) [row;column].
* Result is
* CSI r ; c R
* CSI ? Ps n
* Device Status Report (DSR, DEC-specific).
* Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
* ? r ; c R (assumes page is zero).
* Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
* or CSI ? 1 1 n (not ready).
* Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
* or CSI ? 2 1 n (locked).
* Ps = 2 6 -> Report Keyboard status as
* CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
* The last two parameters apply to VT400 & up, and denote key-
* board ready and LK01 respectively.
* Ps = 5 3 -> Report Locator status as
* CSI ? 5 3 n Locator available, if compiled-in, or
* CSI ? 5 0 n No Locator, if not.
*/
public deviceStatus(params: number[]) {
if (!this._terminal.prefix) {
switch (params[0]) {
case 5:
// status report
this._terminal.send(C0.ESC + '[0n');
break;
case 6:
// cursor position
this._terminal.send(C0.ESC + '['
+ (this._terminal.y + 1)
+ ';'
+ (this._terminal.x + 1)
+ 'R');
break;
}
} else if (this._terminal.prefix === '?') {
// modern xterm doesnt seem to
// respond to any of these except ?6, 6, and 5
switch (params[0]) {
case 6:
// cursor position
this._terminal.send(C0.ESC + '[?'
+ (this._terminal.y + 1)
+ ';'
+ (this._terminal.x + 1)
+ 'R');
break;
case 15:
// no printer
// this.send(C0.ESC + '[?11n');
break;
case 25:
// dont support user defined keys
// this.send(C0.ESC + '[?21n');
break;
case 26:
// north american keyboard
// this.send(C0.ESC + '[?27;1;0;0n');
break;
case 53:
// no dec locator/mouse
// this.send(C0.ESC + '[?50n');
break;
}
}
}
}