]> git.proxmox.com Git - mirror_xterm.js.git/blame - src/xterm.js
Fix emission of terminal focus&blur events
[mirror_xterm.js.git] / src / xterm.js
CommitLineData
8bc844c0 1/**
5af18f8e
PK
2 * xterm.js: xterm, in the browser
3 * Copyright (c) 2014, sourceLair Limited (www.sourcelair.com (MIT License)
6cc8b3cd
CJ
4 * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
5 * https://github.com/chjj/term.js
8bc844c0
CJ
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 *
25 * Originally forked from (with the author's permission):
26 * Fabrice Bellard's javascript vt100 for jslinux:
27 * http://bellard.org/jslinux/
28 * Copyright (c) 2011 Fabrice Bellard
29 * The original design remains. The terminal itself
30 * has been extended to include xterm CSI codes, among
31 * other features.
32 */
33
3f455f90 34(function (xterm) {
6a87253d
AO
35 if (typeof exports === 'object' && typeof module === 'object') {
36 /*
bd215861 37 * CommonJS environment
6a87253d
AO
38 */
39 module.exports = xterm.call(this);
40 } else if (typeof define == 'function') {
3f455f90
PK
41 /*
42 * Require.js is available
43 */
87979aee 44 define([], xterm.bind(window));
3f455f90
PK
45 } else {
46 /*
47 * Plain browser environment
987f09d8 48 */
3f455f90
PK
49 this.Xterm = xterm.call(this);
50 this.Terminal = this.Xterm; /* Backwards compatibility with term.js */
51 }
52})(function() {
53 /**
54 * Terminal Emulation References:
55 * http://vt100.net/
56 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt
57 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
58 * http://invisible-island.net/vttest/
59 * http://www.inwap.com/pdp10/ansicode.txt
60 * http://linux.die.net/man/4/console_codes
61 * http://linux.die.net/man/7/urxvt
62 */
63
64 'use strict';
65
66 /**
67 * Shared
68 */
69
70 var window = this, document = this.document;
71
72 /**
73 * EventEmitter
74 */
75
76 function EventEmitter() {
77 this._events = this._events || {};
78 }
8bc844c0 79
3f455f90
PK
80 EventEmitter.prototype.addListener = function(type, listener) {
81 this._events[type] = this._events[type] || [];
82 this._events[type].push(listener);
83 };
8bc844c0 84
3f455f90 85 EventEmitter.prototype.on = EventEmitter.prototype.addListener;
8bc844c0 86
3f455f90
PK
87 EventEmitter.prototype.removeListener = function(type, listener) {
88 if (!this._events[type]) return;
8bc844c0 89
3f455f90
PK
90 var obj = this._events[type]
91 , i = obj.length;
8bc844c0 92
3f455f90
PK
93 while (i--) {
94 if (obj[i] === listener || obj[i].listener === listener) {
95 obj.splice(i, 1);
96 return;
97 }
98 }
99 };
100
101 EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
8bc844c0 102
3f455f90
PK
103 EventEmitter.prototype.removeAllListeners = function(type) {
104 if (this._events[type]) delete this._events[type];
105 };
8bc844c0 106
3f455f90 107 EventEmitter.prototype.once = function(type, listener) {
6406a88d 108 var self = this;
3f455f90
PK
109 function on() {
110 var args = Array.prototype.slice.call(arguments);
6406a88d
PK
111 self.removeListener(type, on);
112 return listener.apply(self, args);
3f455f90
PK
113 }
114 on.listener = listener;
115 return this.on(type, on);
116 };
8bc844c0 117
3f455f90
PK
118 EventEmitter.prototype.emit = function(type) {
119 if (!this._events[type]) return;
8bc844c0 120
3f455f90
PK
121 var args = Array.prototype.slice.call(arguments, 1)
122 , obj = this._events[type]
123 , l = obj.length
124 , i = 0;
8bc844c0 125
3f455f90
PK
126 for (; i < l; i++) {
127 obj[i].apply(this, args);
128 }
129 };
8bc844c0 130
3f455f90
PK
131 EventEmitter.prototype.listeners = function(type) {
132 return this._events[type] = this._events[type] || [];
133 };
8bc844c0 134
8bc844c0 135
3f455f90
PK
136 /**
137 * States
138 */
139 var normal = 0, escaped = 1, csi = 2, osc = 3, charset = 4, dcs = 5, ignore = 6;
8bc844c0 140
3f455f90
PK
141 /**
142 * Terminal
143 */
8bc844c0 144
3f455f90
PK
145 function Terminal(options) {
146 var self = this;
8bc844c0 147
3f455f90
PK
148 if (!(this instanceof Terminal)) {
149 return new Terminal(arguments[0], arguments[1], arguments[2]);
150 }
8bc844c0 151
3f455f90 152 self.cancel = Terminal.cancel;
8bc844c0 153
3f455f90 154 EventEmitter.call(this);
8bc844c0 155
3f455f90
PK
156 if (typeof options === 'number') {
157 options = {
158 cols: arguments[0],
159 rows: arguments[1],
160 handler: arguments[2]
161 };
162 }
5fd1948b 163
3f455f90 164 options = options || {};
8bc844c0 165
8bc844c0 166
3f455f90
PK
167 Object.keys(Terminal.defaults).forEach(function(key) {
168 if (options[key] == null) {
169 options[key] = Terminal.options[key];
86dad1b0 170
3f455f90
PK
171 if (Terminal[key] !== Terminal.defaults[key]) {
172 options[key] = Terminal[key];
173 }
174 }
175 self[key] = options[key];
176 });
91273161 177
3f455f90
PK
178 if (options.colors.length === 8) {
179 options.colors = options.colors.concat(Terminal._colors.slice(8));
180 } else if (options.colors.length === 16) {
181 options.colors = options.colors.concat(Terminal._colors.slice(16));
182 } else if (options.colors.length === 10) {
183 options.colors = options.colors.slice(0, -2).concat(
184 Terminal._colors.slice(8, -2), options.colors.slice(-2));
185 } else if (options.colors.length === 18) {
186 options.colors = options.colors.concat(
187 Terminal._colors.slice(16, -2), options.colors.slice(-2));
188 }
189 this.colors = options.colors;
8bc844c0 190
3f455f90 191 this.options = options;
91273161 192
3f455f90
PK
193 // this.context = options.context || window;
194 // this.document = options.document || document;
195 this.parent = options.body || options.parent
196 || (document ? document.getElementsByTagName('body')[0] : null);
5fd1948b 197
3f455f90
PK
198 this.cols = options.cols || options.geometry[0];
199 this.rows = options.rows || options.geometry[1];
200
201 if (options.handler) {
202 this.on('data', options.handler);
203 }
204
205 this.ybase = 0;
206 this.ydisp = 0;
207 this.x = 0;
208 this.y = 0;
209 this.cursorState = 0;
210 this.cursorHidden = false;
211 this.convertEol;
212 this.state = 0;
213 this.queue = '';
214 this.scrollTop = 0;
215 this.scrollBottom = this.rows - 1;
216
217 // modes
218 this.applicationKeypad = false;
219 this.applicationCursor = false;
220 this.originMode = false;
221 this.insertMode = false;
222 this.wraparoundMode = false;
223 this.normal = null;
224
225 // charset
226 this.charset = null;
227 this.gcharset = null;
228 this.glevel = 0;
229 this.charsets = [null];
230
231 // mouse properties
232 this.decLocator;
233 this.x10Mouse;
234 this.vt200Mouse;
235 this.vt300Mouse;
236 this.normalMouse;
237 this.mouseEvents;
238 this.sendFocus;
239 this.utfMouse;
240 this.sgrMouse;
241 this.urxvtMouse;
242
243 // misc
244 this.element;
245 this.children;
246 this.refreshStart;
247 this.refreshEnd;
248 this.savedX;
249 this.savedY;
250 this.savedCols;
251
252 // stream
253 this.readable = true;
254 this.writable = true;
255
256 this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
257 this.curAttr = this.defAttr;
258
259 this.params = [];
260 this.currentParam = 0;
261 this.prefix = '';
262 this.postfix = '';
263
264 this.lines = [];
265 var i = this.rows;
266 while (i--) {
267 this.lines.push(this.blankLine());
86dad1b0 268 }
3f455f90
PK
269
270 this.tabs;
271 this.setupStops();
86dad1b0 272 }
8bc844c0 273
3f455f90 274 inherits(Terminal, EventEmitter);
8bc844c0 275
3f455f90
PK
276 // back_color_erase feature for xterm.
277 Terminal.prototype.eraseAttr = function() {
278 // if (this.is('screen')) return this.defAttr;
279 return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff);
280 };
a68c8336 281
3f455f90
PK
282 /**
283 * Colors
284 */
285
286 // Colors 0-15
287 Terminal.tangoColors = [
288 // dark:
289 '#2e3436',
290 '#cc0000',
291 '#4e9a06',
292 '#c4a000',
293 '#3465a4',
294 '#75507b',
295 '#06989a',
296 '#d3d7cf',
297 // bright:
298 '#555753',
299 '#ef2929',
300 '#8ae234',
301 '#fce94f',
302 '#729fcf',
303 '#ad7fa8',
304 '#34e2e2',
305 '#eeeeec'
306 ];
307
308 // Colors 0-15 + 16-255
309 // Much thanks to TooTallNate for writing this.
310 Terminal.colors = (function() {
311 var colors = Terminal.tangoColors.slice()
312 , r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
313 , i;
314
315 // 16-231
316 i = 0;
317 for (; i < 216; i++) {
318 out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]);
319 }
8bc844c0 320
3f455f90
PK
321 // 232-255 (grey)
322 i = 0;
323 for (; i < 24; i++) {
324 r = 8 + i * 10;
325 out(r, r, r);
326 }
8bc844c0 327
3f455f90
PK
328 function out(r, g, b) {
329 colors.push('#' + hex(r) + hex(g) + hex(b));
330 }
8bc844c0 331
3f455f90
PK
332 function hex(c) {
333 c = c.toString(16);
334 return c.length < 2 ? '0' + c : c;
335 }
8bc844c0 336
3f455f90
PK
337 return colors;
338 })();
3b322929 339
3f455f90 340 Terminal._colors = Terminal.colors.slice();
31161ffe 341
3f455f90
PK
342 Terminal.vcolors = (function() {
343 var out = []
344 , colors = Terminal.colors
345 , i = 0
346 , color;
8bc844c0 347
3f455f90
PK
348 for (; i < 256; i++) {
349 color = parseInt(colors[i].substring(1), 16);
350 out.push([
351 (color >> 16) & 0xff,
352 (color >> 8) & 0xff,
353 color & 0xff
354 ]);
355 }
5fd1948b 356
3f455f90
PK
357 return out;
358 })();
359
360 /**
361 * Options
362 */
363
364 Terminal.defaults = {
365 colors: Terminal.colors,
366 theme: 'default',
367 convertEol: false,
368 termName: 'xterm',
369 geometry: [80, 24],
370 cursorBlink: false,
371 visualBell: false,
372 popOnBell: false,
373 scrollback: 1000,
374 screenKeys: false,
375 debug: false,
376 cancelEvents: false
377 // programFeatures: false,
378 // focusKeys: false,
379 };
cc7f4d0d 380
3f455f90 381 Terminal.options = {};
cd956bca 382
7988f634
SS
383 Terminal.focus = null;
384
3f455f90
PK
385 each(keys(Terminal.defaults), function(key) {
386 Terminal[key] = Terminal.defaults[key];
387 Terminal.options[key] = Terminal.defaults[key];
388 });
389
390 /**
391 * Focused Terminal
392 */
393 Terminal.prototype.focus = function() {
58056df2 394 if (document.activeElement === this.element) {
3f455f90 395 return;
8bc844c0 396 }
8bc844c0 397
3f455f90
PK
398 if (this.sendFocus) {
399 this.send('\x1b[I');
400 }
8bc844c0 401
3f455f90 402 this.showCursor();
58056df2 403 this.element.focus();
3f455f90 404 };
8bc844c0 405
3f455f90
PK
406 Terminal.prototype.blur = function() {
407 if (Terminal.focus !== this) {
408 return;
409 }
8bc844c0 410
3f455f90
PK
411 this.cursorState = 0;
412 this.refresh(this.y, this.y);
58056df2 413 this.element.blur();
8bc844c0 414
3f455f90
PK
415 if (this.sendFocus) {
416 this.send('\x1b[O');
417 }
7988f634 418 Terminal.focus = null;
3f455f90 419 };
8bc844c0 420
3f455f90
PK
421 /**
422 * Initialize default behavior
423 */
3f455f90 424 Terminal.prototype.initGlobal = function() {
3f455f90 425 Terminal.bindKeys(this);
c02cc844 426 Terminal.bindPaste(this);
3f455f90 427 Terminal.bindCopy(this);
c02cc844 428 Terminal.bindCut(this);
18b2a1c3 429 Terminal.bindDrop(this);
3f455f90 430 };
8bc844c0 431
64721687
PK
432 /**
433 * Clears all selected text, inside the terminal.
434 */
435 Terminal.prototype.clearSelection = function() {
436 var selectionBaseNode = window.getSelection().baseNode;
437
438 if (selectionBaseNode && (this.element.contains(selectionBaseNode.parentElement))) {
439 window.getSelection().removeAllRanges();
440 }
441 };
442
443 /**
444 * This function temporarily enables (leases) the contentEditable value of the terminal, which
445 * should be set back to false within 5 seconds at most.
446 */
447 Terminal.prototype.leaseContentEditable = function (ms, callback) {
448 var term = this;
449
450 term.element.contentEditable = true;
451 setTimeout(function () {
452 term.element.contentEditable = false;
453 if (typeof callback == 'function') {
454 callback.call(term);
455 }
456 }, ms || 5000);
3f455f90 457 };
8bc844c0 458
3f455f90 459 /**
64721687
PK
460 * Bind to paste event and allow both keyboard and right-click pasting, without having the
461 * contentEditable value set to true.
3f455f90
PK
462 */
463 Terminal.bindPaste = function(term) {
58056df2 464 on(term.element, 'paste', function(ev) {
3f455f90
PK
465 if (ev.clipboardData) {
466 var text = ev.clipboardData.getData('text/plain');
8fa1a465 467 term.emit('paste', text, ev);
3f455f90 468 term.handler(text);
64721687
PK
469 /**
470 * Cancel the paste event, or else things will be pasted twice:
471 * 1. by the terminal handler
472 * 2. by the browser, because of the contentEditable value being true
473 */
474 term.cancel(ev, true);
475
476 /**
477 * After the paste event is completed, always set the contentEditable value to false.
478 */
479 term.element.contentEditable = false;
3f455f90 480 }
3f455f90 481 });
8fa1a465
PK
482
483 /**
64721687
PK
484 * Hack pasting with keyboard, in order to make it work without contentEditable.
485 * When a user types Ctrl + Shift + V or Cmd + V on a Mac, lease the contentEditable value
486 * as true.
8fa1a465 487 */
64721687
PK
488 on(term.element, 'keydown', function (ev) {
489 /**
490 * If on a Mac, lease the contentEditable value temporarily, when the user presses
491 * the Cmd button, in order to cope with some sync issues on Safari.
492 */
493 if (term.isMac && ev.keyCode == 91) {
494 term.leaseContentEditable(1000);
495 }
496
497 if (ev.keyCode == 86) { // keyCode 96 corresponds to "v"
498 if (term.isMac && ev.metaKey) {
499 term.leaseContentEditable();
500 }
3f455f90 501 }
8fa1a465
PK
502 });
503
64721687
PK
504 /**
505 * Hack pasting with right-click in order to allow right-click paste, by leasing the
506 * contentEditable value as true.
507 */
508 on(term.element, 'contextmenu', function (ev) {
509 term.leaseContentEditable();
3f455f90
PK
510 });
511 };
8bc844c0 512
8bc844c0 513
3f455f90
PK
514 /*
515 * Apply key handling to the terminal
516 */
517 Terminal.bindKeys = function(term) {
518 on(term.element, 'keydown', function(ev) {
3f455f90
PK
519 term.keyDown(ev);
520 }, true);
8bc844c0 521
3f455f90 522 on(term.element, 'keypress', function(ev) {
3f455f90
PK
523 term.keyPress(ev);
524 }, true);
3f455f90 525 };
8bc844c0 526
8bc844c0 527
c02cc844
PK
528 /**
529 * Bind copy event. Stript trailing whitespaces from selection.
3f455f90
PK
530 */
531 Terminal.bindCopy = function(term) {
532 on(term.element, 'copy', function(ev) {
c02cc844
PK
533 var selectedText = window.getSelection().toString(),
534 copiedText = selectedText.split('\n').map(function (element) {
535 return element.replace(/\s+$/g, '');
536 }).join('\n');
537 ev.clipboardData.setData('text/plain', copiedText);
538 ev.preventDefault();
539 });
540 };
8bc844c0 541
c02cc844
PK
542 /**
543 * Cancel the cut event completely
544 */
545 Terminal.bindCut = function(term) {
546 on(term.element, 'cut', function (ev) {
547 ev.preventDefault();
8bc844c0 548 });
3f455f90 549 };
8bc844c0 550
8bc844c0 551
18b2a1c3
PK
552 Terminal.bindDrop = function (term) {
553 /*
554 * Do not perform the "drop" event. Altering the contents of the
555 * terminal with drag n drop is unwanted behavior.
556 */
557 on(term.element, 'drop', function (ev) {
558 term.cancel(ev, true);
559 });
3f455f90 560 };
8bc844c0 561
3f455f90 562
6406a88d
PK
563 Terminal.click = function (term) {
564 /*
565 * Do not perform the "drop" event. Altering the contents of the
566 * terminal with drag n drop is unwanted behavior.
567 */
568 on(term.element, 'click', function (ev) {
569 term.cancel(ev, true);
8bc844c0 570 });
3f455f90 571 };
8bc844c0 572
8bc844c0 573
3f455f90
PK
574 /*
575 * Insert the given row to the terminal or produce a new one
576 * if no row argument is passed. Return the inserted row.
577 */
578 Terminal.prototype.insertRow = function (row) {
579 if (typeof row != 'object') {
580 row = document.createElement('div');
581 }
8bc844c0 582
3f455f90
PK
583 this.rowContainer.appendChild(row);
584 this.children.push(row);
585
586 return row;
f3bd6145 587 };
8bc844c0 588
8bc844c0 589
3f455f90
PK
590 /*
591 * Open Terminal in the DOM
592 */
593 Terminal.prototype.open = function(parent) {
594 var self=this, i=0, div;
8bc844c0 595
3f455f90 596 this.parent = parent || this.parent;
8bc844c0 597
3f455f90
PK
598 if (!this.parent) {
599 throw new Error('Terminal requires a parent element.');
600 }
8bc844c0 601
3f455f90
PK
602 /*
603 * Grab global elements
604 */
605 this.context = this.parent.ownerDocument.defaultView;
606 this.document = this.parent.ownerDocument;
607 this.body = this.document.getElementsByTagName('body')[0];
608
609 /*
610 * Parse User-Agent
611 */
612 if (this.context.navigator && this.context.navigator.userAgent) {
613 this.isMac = !!~this.context.navigator.userAgent.indexOf('Mac');
614 this.isIpad = !!~this.context.navigator.userAgent.indexOf('iPad');
615 this.isIphone = !!~this.context.navigator.userAgent.indexOf('iPhone');
616 this.isMSIE = !!~this.context.navigator.userAgent.indexOf('MSIE');
617 }
8bc844c0 618
3f455f90
PK
619 /*
620 * Create main element container
621 */
622 this.element = this.document.createElement('div');
a523803d
AK
623 this.element.classList.add('terminal');
624 this.element.classList.add('xterm');
625 this.element.classList.add('xterm-theme-' + this.theme);
3f455f90 626 this.element.setAttribute('tabindex', 0);
18b2a1c3 627 this.element.spellcheck = 'false';
6bc18817
TD
628 this.element.onfocus = function() {
629 self.emit('focus', {terminal: this});
630 };
631 this.element.onblur = function() {
632 self.emit('blur', {terminal: this});
633 };
3f455f90
PK
634
635 /*
636 * Create the container that will hold the lines of the terminal and then
637 * produce the lines the lines.
638 */
639 this.rowContainer = document.createElement('div');
640 this.rowContainer.classList.add('xterm-rows');
641 this.element.appendChild(this.rowContainer);
642 this.children = [];
643
3f455f90
PK
644 for (; i < this.rows; i++) {
645 this.insertRow();
646 }
647 this.parent.appendChild(this.element);
8bc844c0 648
3f455f90
PK
649 // Draw the screen.
650 this.refresh(0, this.rows - 1);
8bc844c0 651
3f455f90
PK
652 // Initialize global actions that
653 // need to be taken on the document.
654 this.initGlobal();
15f68335 655
3f455f90
PK
656 // Ensure there is a Terminal.focus.
657 this.focus();
15f68335 658
3f455f90
PK
659 // Start blinking the cursor.
660 this.startBlink();
15f68335 661
3f455f90 662 on(this.element, 'mouseup', function() {
f53f5735
TD
663 var selection = document.getSelection(),
664 collapsed = selection.isCollapsed,
665 isRange = typeof collapsed == 'boolean' ? !collapsed : selection.type == 'Range';
666 if (!isRange) {
3f455f90
PK
667 self.focus();
668 }
669 });
8bc844c0 670
3f455f90
PK
671 // Listen for mouse events and translate
672 // them into terminal mouse protocols.
673 this.bindMouse();
8bc844c0 674
3f455f90
PK
675 // Figure out whether boldness affects
676 // the character width of monospace fonts.
677 if (Terminal.brokenBold == null) {
678 Terminal.brokenBold = isBoldBroken(this.document);
8bc844c0
CJ
679 }
680
3f455f90
PK
681 this.emit('open');
682 };
8bc844c0 683
3f455f90
PK
684 // XTerm mouse events
685 // http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
686 // To better understand these
687 // the xterm code is very helpful:
688 // Relevant files:
689 // button.c, charproc.c, misc.c
690 // Relevant functions in xterm/button.c:
691 // BtnCode, EmitButtonCode, EditorButton, SendMousePosition
692 Terminal.prototype.bindMouse = function() {
693 var el = this.element
694 , self = this
695 , pressed = 32;
696
697 var wheelEvent = 'onmousewheel' in this.context
698 ? 'mousewheel'
699 : 'DOMMouseScroll';
8bc844c0 700
3f455f90
PK
701 // mouseup, mousedown, mousewheel
702 // left click: ^[[M 3<^[[M#3<
703 // mousewheel up: ^[[M`3>
704 function sendButton(ev) {
705 var button
706 , pos;
8bc844c0 707
3f455f90
PK
708 // get the xterm-style button
709 button = getButton(ev);
8bc844c0 710
3f455f90
PK
711 // get mouse coordinates
712 pos = getCoords(ev);
713 if (!pos) return;
8bc844c0 714
3f455f90 715 sendEvent(button, pos);
8bc844c0 716
3f455f90
PK
717 switch (ev.type) {
718 case 'mousedown':
719 pressed = button;
8bc844c0 720 break;
3f455f90
PK
721 case 'mouseup':
722 // keep it at the left
723 // button, just in case.
724 pressed = 32;
8bc844c0 725 break;
3f455f90
PK
726 case wheelEvent:
727 // nothing. don't
728 // interfere with
729 // `pressed`.
8bc844c0 730 break;
3f455f90
PK
731 }
732 }
8bc844c0 733
3f455f90
PK
734 // motion example of a left click:
735 // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
736 function sendMove(ev) {
737 var button = pressed
738 , pos;
8bc844c0 739
3f455f90
PK
740 pos = getCoords(ev);
741 if (!pos) return;
a7f50531 742
3f455f90
PK
743 // buttons marked as motions
744 // are incremented by 32
745 button += 32;
a7f50531 746
3f455f90
PK
747 sendEvent(button, pos);
748 }
efa0e3c1 749
3f455f90
PK
750 // encode button and
751 // position to characters
752 function encode(data, ch) {
753 if (!self.utfMouse) {
754 if (ch === 255) return data.push(0);
755 if (ch > 127) ch = 127;
756 data.push(ch);
757 } else {
758 if (ch === 2047) return data.push(0);
759 if (ch < 127) {
760 data.push(ch);
761 } else {
762 if (ch > 2047) ch = 2047;
763 data.push(0xC0 | (ch >> 6));
764 data.push(0x80 | (ch & 0x3F));
765 }
8bc844c0 766 }
3f455f90 767 }
8bc844c0 768
3f455f90
PK
769 // send a mouse event:
770 // regular/utf8: ^[[M Cb Cx Cy
771 // urxvt: ^[[ Cb ; Cx ; Cy M
772 // sgr: ^[[ Cb ; Cx ; Cy M/m
773 // vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r
774 // locator: CSI P e ; P b ; P r ; P c ; P p & w
775 function sendEvent(button, pos) {
776 // self.emit('mouse', {
777 // x: pos.x - 32,
778 // y: pos.x - 32,
779 // button: button
780 // });
781
782 if (self.vt300Mouse) {
783 // NOTE: Unstable.
784 // http://www.vt100.net/docs/vt3xx-gp/chapter15.html
785 button &= 3;
786 pos.x -= 32;
787 pos.y -= 32;
788 var data = '\x1b[24';
789 if (button === 0) data += '1';
790 else if (button === 1) data += '3';
791 else if (button === 2) data += '5';
792 else if (button === 3) return;
793 else data += '0';
794 data += '~[' + pos.x + ',' + pos.y + ']\r';
795 self.send(data);
796 return;
797 }
8bc844c0 798
3f455f90
PK
799 if (self.decLocator) {
800 // NOTE: Unstable.
801 button &= 3;
802 pos.x -= 32;
803 pos.y -= 32;
804 if (button === 0) button = 2;
805 else if (button === 1) button = 4;
806 else if (button === 2) button = 6;
807 else if (button === 3) button = 3;
808 self.send('\x1b['
809 + button
810 + ';'
811 + (button === 3 ? 4 : 0)
812 + ';'
813 + pos.y
814 + ';'
815 + pos.x
816 + ';'
817 + (pos.page || 0)
818 + '&w');
819 return;
820 }
8bc844c0 821
3f455f90
PK
822 if (self.urxvtMouse) {
823 pos.x -= 32;
824 pos.y -= 32;
825 pos.x++;
826 pos.y++;
827 self.send('\x1b[' + button + ';' + pos.x + ';' + pos.y + 'M');
828 return;
829 }
8bc844c0 830
3f455f90
PK
831 if (self.sgrMouse) {
832 pos.x -= 32;
833 pos.y -= 32;
834 self.send('\x1b[<'
835 + ((button & 3) === 3 ? button & ~3 : button)
836 + ';'
837 + pos.x
838 + ';'
839 + pos.y
840 + ((button & 3) === 3 ? 'm' : 'M'));
841 return;
842 }
8bc844c0 843
3f455f90 844 var data = [];
8bc844c0 845
3f455f90
PK
846 encode(data, button);
847 encode(data, pos.x);
848 encode(data, pos.y);
8bc844c0 849
3f455f90
PK
850 self.send('\x1b[M' + String.fromCharCode.apply(String, data));
851 }
8bc844c0 852
3f455f90
PK
853 function getButton(ev) {
854 var button
855 , shift
856 , meta
857 , ctrl
858 , mod;
859
860 // two low bits:
861 // 0 = left
862 // 1 = middle
863 // 2 = right
864 // 3 = release
865 // wheel up/down:
866 // 1, and 2 - with 64 added
867 switch (ev.type) {
868 case 'mousedown':
869 button = ev.button != null
870 ? +ev.button
871 : ev.which != null
872 ? ev.which - 1
873 : null;
874
875 if (self.isMSIE) {
876 button = button === 1 ? 0 : button === 4 ? 1 : button;
8bc844c0 877 }
8bc844c0 878 break;
3f455f90
PK
879 case 'mouseup':
880 button = 3;
8bc844c0 881 break;
3f455f90
PK
882 case 'DOMMouseScroll':
883 button = ev.detail < 0
884 ? 64
885 : 65;
8bc844c0 886 break;
3f455f90
PK
887 case 'mousewheel':
888 button = ev.wheelDeltaY > 0
889 ? 64
890 : 65;
8bc844c0 891 break;
3f455f90 892 }
8bc844c0 893
3f455f90
PK
894 // next three bits are the modifiers:
895 // 4 = shift, 8 = meta, 16 = control
896 shift = ev.shiftKey ? 4 : 0;
897 meta = ev.metaKey ? 8 : 0;
898 ctrl = ev.ctrlKey ? 16 : 0;
899 mod = shift | meta | ctrl;
900
901 // no mods
902 if (self.vt200Mouse) {
903 // ctrl only
904 mod &= ctrl;
905 } else if (!self.normalMouse) {
906 mod = 0;
907 }
8bc844c0 908
3f455f90
PK
909 // increment to SP
910 button = (32 + (mod << 2)) + button;
8bc844c0 911
3f455f90
PK
912 return button;
913 }
8bc844c0 914
3f455f90
PK
915 // mouse coordinates measured in cols/rows
916 function getCoords(ev) {
917 var x, y, w, h, el;
918
919 // ignore browsers without pageX for now
920 if (ev.pageX == null) return;
921
922 x = ev.pageX;
923 y = ev.pageY;
924 el = self.element;
925
926 // should probably check offsetParent
927 // but this is more portable
928 while (el && el !== self.document.documentElement) {
929 x -= el.offsetLeft;
930 y -= el.offsetTop;
931 el = 'offsetParent' in el
932 ? el.offsetParent
933 : el.parentNode;
934 }
8bc844c0 935
3f455f90
PK
936 // convert to cols/rows
937 w = self.element.clientWidth;
938 h = self.element.clientHeight;
939 x = Math.round((x / w) * self.cols);
940 y = Math.round((y / h) * self.rows);
941
942 // be sure to avoid sending
943 // bad positions to the program
944 if (x < 0) x = 0;
945 if (x > self.cols) x = self.cols;
946 if (y < 0) y = 0;
947 if (y > self.rows) y = self.rows;
948
949 // xterm sends raw bytes and
950 // starts at 32 (SP) for each.
951 x += 32;
952 y += 32;
953
954 return {
955 x: x,
956 y: y,
957 type: ev.type === wheelEvent
958 ? 'mousewheel'
959 : ev.type
960 };
961 }
8bc844c0 962
3f455f90
PK
963 on(el, 'mousedown', function(ev) {
964 if (!self.mouseEvents) return;
8bc844c0 965
3f455f90
PK
966 // send the button
967 sendButton(ev);
968
969 // ensure focus
970 self.focus();
971
972 // fix for odd bug
973 //if (self.vt200Mouse && !self.normalMouse) {
974 if (self.vt200Mouse) {
975 sendButton({ __proto__: ev, type: 'mouseup' });
976 return self.cancel(ev);
8bc844c0 977 }
8bc844c0 978
3f455f90
PK
979 // bind events
980 if (self.normalMouse) on(self.document, 'mousemove', sendMove);
981
982 // x10 compatibility mode can't send button releases
983 if (!self.x10Mouse) {
984 on(self.document, 'mouseup', function up(ev) {
985 sendButton(ev);
986 if (self.normalMouse) off(self.document, 'mousemove', sendMove);
987 off(self.document, 'mouseup', up);
988 return self.cancel(ev);
989 });
8bc844c0 990 }
3f455f90
PK
991
992 return self.cancel(ev);
993 });
994
995 //if (self.normalMouse) {
996 // on(self.document, 'mousemove', sendMove);
997 //}
998
999 on(el, wheelEvent, function(ev) {
1000 if (!self.mouseEvents) return;
1001 if (self.x10Mouse
1002 || self.vt300Mouse
1003 || self.decLocator) return;
1004 sendButton(ev);
1005 return self.cancel(ev);
1006 });
1007
1008 // allow mousewheel scrolling in
1009 // the shell for example
1010 on(el, wheelEvent, function(ev) {
1011 if (self.mouseEvents) return;
1012 if (self.applicationKeypad) return;
1013 if (ev.type === 'DOMMouseScroll') {
1014 self.scrollDisp(ev.detail < 0 ? -1 : 1);
1015 } else {
1016 self.scrollDisp(ev.wheelDeltaY > 0 ? -1 : 1);
1017 }
1018 return self.cancel(ev);
1019 });
1020 };
1021
1022 /**
1023 * Destroy Terminal
1024 */
1025
1026 Terminal.prototype.destroy = function() {
1027 this.readable = false;
1028 this.writable = false;
1029 this._events = {};
1030 this.handler = function() {};
1031 this.write = function() {};
1032 if (this.element.parentNode) {
1033 this.element.parentNode.removeChild(this.element);
1034 }
1035 //this.emit('close');
1036 };
1037
1038
1a384616
PK
1039 /**
1040 * Flags used to render terminal text properly
1041 */
1042 Terminal.flags = {
1043 BOLD: 0b00001,
1044 UNDERLINE: 0b00010,
1045 BLINK: 0b00100,
1046 INVERSE: 0b01000,
1047 INVISIBLE: 0b10000
1048 }
1049
3f455f90
PK
1050 /*
1051 * Rendering Engine
1052 *
1053 * In the screen buffer, each character
1054 * is stored as a an array with a character
1055 * and a 32-bit integer.
1056 * First value: a utf-16 character.
1057 * Second value:
1058 * Next 9 bits: background color (0-511).
1059 * Next 9 bits: foreground color (0-511).
1060 * Next 14 bits: a mask for misc. flags:
1061 * 1=bold, 2=underline, 4=blink, 8=inverse, 16=invisible
1062 */
1063 Terminal.prototype.refresh = function(start, end) {
1064 var x, y, i, line, out, ch, width, data, attr, bg, fg, flags, row, parent, focused = document.activeElement;
1065
1066 if (end - start >= this.rows / 2) {
1067 parent = this.element.parentNode;
1068 if (parent) parent.removeChild(this.element);
1069 }
1070
1071 width = this.cols;
1072 y = start;
1073
1074 if (end >= this.lines.length) {
1075 this.log('`end` is too large. Most likely a bad CSR.');
1076 end = this.lines.length - 1;
1077 }
1078
1079 for (; y <= end; y++) {
1080 row = y + this.ydisp;
1081
1082 line = this.lines[row];
1083 out = '';
1084
1085 if (y === this.y
1086 && this.cursorState
1087 && (this.ydisp === this.ybase)
1088 && !this.cursorHidden) {
1089 x = this.x;
1090 } else {
1091 x = -1;
1092 }
1093
1094 attr = this.defAttr;
1095 i = 0;
1096
1097 for (; i < width; i++) {
1098 data = line[i][0];
1099 ch = line[i][1];
1100
1101 if (i === x) data = -1;
1102
1103 if (data !== attr) {
1104 if (attr !== this.defAttr) {
1105 out += '</span>';
1106 }
1107 if (data !== this.defAttr) {
1108 if (data === -1) {
1109 out += '<span class="reverse-video terminal-cursor">';
1110 } else {
ae0f9637 1111 var classNames = [];
3f455f90
PK
1112
1113 bg = data & 0x1ff;
1114 fg = (data >> 9) & 0x1ff;
1115 flags = data >> 18;
1116
1a384616 1117 if (flags & Terminal.flags.BOLD) {
3f455f90 1118 if (!Terminal.brokenBold) {
ae0f9637 1119 classNames.push('xterm-bold');
3f455f90
PK
1120 }
1121 // See: XTerm*boldColors
1122 if (fg < 8) fg += 8;
1123 }
1124
1a384616 1125 if (flags & Terminal.flags.UNDERLINE) {
ae0f9637 1126 classNames.push('xterm-underline');
3f455f90
PK
1127 }
1128
1a384616 1129 if (flags & Terminal.flags.BLINK) {
ae0f9637 1130 classNames.push('xterm-blink');
3f455f90
PK
1131 }
1132
1a384616
PK
1133 /**
1134 * If inverse flag is on, then swap the foreground and background variables.
1135 */
1136 if (flags & Terminal.flags.INVERSE) {
1137 /* One-line variable swap in JavaScript: http://stackoverflow.com/a/16201730 */
1138 bg = [fg, fg = bg][0];
1139 // Should inverse just be before the
1140 // above boldColors effect instead?
1141 if ((flags & 1) && fg < 8) fg += 8;
3f455f90
PK
1142 }
1143
1a384616 1144 if (flags & Terminal.flags.INVISIBLE) {
ae0f9637 1145 classNames.push('xterm-hidden');
3f455f90
PK
1146 }
1147
1a384616
PK
1148 /**
1149 * Weird situation: Invert flag used black foreground and white background results
1150 * in invalid background color, positioned at the 256 index of the 256 terminal
1151 * color map. Pin the colors manually in such a case.
1152 *
1153 * Source: https://github.com/sourcelair/xterm.js/issues/57
1154 */
1155 if (flags & Terminal.flags.INVERSE) {
1156 if (bg == 257) {
1157 bg = 15;
1158 }
1159 if (fg == 256) {
1160 fg = 0;
1161 }
1162 }
1163
1164 if (bg < 256) {
ae0f9637 1165 classNames.push('xterm-bg-color-' + bg);
3f455f90
PK
1166 }
1167
1a384616 1168 if (fg < 256) {
ae0f9637 1169 classNames.push('xterm-color-' + fg);
3f455f90
PK
1170 }
1171
ae0f9637
DI
1172 out += '<span';
1173 if (classNames.length) {
1174 out += ' class="' + classNames.join(' ') + '"';
1175 }
1176 out += '>';
8bc844c0 1177 }
3f455f90
PK
1178 }
1179 }
1180
1181 switch (ch) {
1182 case '&':
1183 out += '&amp;';
8bc844c0 1184 break;
3f455f90
PK
1185 case '<':
1186 out += '&lt;';
8bc844c0 1187 break;
3f455f90
PK
1188 case '>':
1189 out += '&gt;';
8bc844c0 1190 break;
3f455f90
PK
1191 default:
1192 if (ch <= ' ') {
1193 out += '&nbsp;';
1194 } else {
1195 if (isWide(ch)) i++;
1196 out += ch;
1197 }
8bc844c0
CJ
1198 break;
1199 }
1200
3f455f90 1201 attr = data;
8bc844c0 1202 }
8bc844c0 1203
3f455f90
PK
1204 if (attr !== this.defAttr) {
1205 out += '</span>';
8bc844c0
CJ
1206 }
1207
3f455f90
PK
1208 this.children[y].innerHTML = out;
1209 }
8bc844c0 1210
3f455f90
PK
1211 if (parent) {
1212 parent.appendChild(this.element);
1213 }
1214
1215 /*
1216 * Return focus to previously focused element
1217 */
1218 focused.focus();
1219 this.emit('refresh', {element: this.element, start: start, end: end});
1220 };
1221
1222 Terminal.prototype._cursorBlink = function() {
1223 if (Terminal.focus !== this) return;
1224 this.cursorState ^= 1;
1225 this.refresh(this.y, this.y);
1226 };
1227
1228 Terminal.prototype.showCursor = function() {
1229 if (!this.cursorState) {
1230 this.cursorState = 1;
1231 this.refresh(this.y, this.y);
1232 } else {
1233 // Temporarily disabled:
1234 // this.refreshBlink();
1235 }
1236 };
1237
1238 Terminal.prototype.startBlink = function() {
1239 if (!this.cursorBlink) return;
1240 var self = this;
1241 this._blinker = function() {
1242 self._cursorBlink();
1243 };
1244 this._blink = setInterval(this._blinker, 500);
1245 };
1246
1247 Terminal.prototype.refreshBlink = function() {
1248 if (!this.cursorBlink) return;
1249 clearInterval(this._blink);
1250 this._blink = setInterval(this._blinker, 500);
1251 };
1252
1253 Terminal.prototype.scroll = function() {
1254 var row;
1255
1256 if (++this.ybase === this.scrollback) {
1257 this.ybase = this.ybase / 2 | 0;
1258 this.lines = this.lines.slice(-(this.ybase + this.rows) + 1);
1259 }
1260
1261 this.ydisp = this.ybase;
1262
1263 // last line
1264 row = this.ybase + this.rows - 1;
1265
1266 // subtract the bottom scroll region
1267 row -= this.rows - 1 - this.scrollBottom;
1268
1269 if (row === this.lines.length) {
1270 // potential optimization:
1271 // pushing is faster than splicing
1272 // when they amount to the same
1273 // behavior.
1274 this.lines.push(this.blankLine());
1275 } else {
1276 // add our new line
1277 this.lines.splice(row, 0, this.blankLine());
1278 }
1279
1280 if (this.scrollTop !== 0) {
1281 if (this.ybase !== 0) {
1282 this.ybase--;
1283 this.ydisp = this.ybase;
8bc844c0 1284 }
3f455f90
PK
1285 this.lines.splice(this.ybase + this.scrollTop, 1);
1286 }
8bc844c0 1287
3f455f90
PK
1288 // this.maxRange();
1289 this.updateRange(this.scrollTop);
1290 this.updateRange(this.scrollBottom);
1291 };
8bc844c0 1292
3f455f90
PK
1293 Terminal.prototype.scrollDisp = function(disp) {
1294 this.ydisp += disp;
8bc844c0 1295
3f455f90
PK
1296 if (this.ydisp > this.ybase) {
1297 this.ydisp = this.ybase;
1298 } else if (this.ydisp < 0) {
1299 this.ydisp = 0;
1300 }
8bc844c0 1301
3f455f90
PK
1302 this.refresh(0, this.rows - 1);
1303 };
8bc844c0 1304
3f455f90
PK
1305 Terminal.prototype.write = function(data) {
1306 var l = data.length, i = 0, j, cs, ch;
8bc844c0 1307
3f455f90
PK
1308 this.refreshStart = this.y;
1309 this.refreshEnd = this.y;
8bc844c0 1310
3f455f90
PK
1311 if (this.ybase !== this.ydisp) {
1312 this.ydisp = this.ybase;
1313 this.maxRange();
1314 }
8bc844c0 1315
3f455f90
PK
1316 for (; i < l; i++) {
1317 ch = data[i];
1318 switch (this.state) {
1319 case normal:
1320 switch (ch) {
1321 case '\x07':
1322 this.bell();
1323 break;
8bc844c0 1324
3f455f90
PK
1325 // '\n', '\v', '\f'
1326 case '\n':
1327 case '\x0b':
1328 case '\x0c':
1329 if (this.convertEol) {
1330 this.x = 0;
1331 }
1332 this.y++;
1333 if (this.y > this.scrollBottom) {
1334 this.y--;
1335 this.scroll();
1336 }
1337 break;
8bc844c0 1338
3f455f90
PK
1339 // '\r'
1340 case '\r':
1341 this.x = 0;
1342 break;
8bc844c0 1343
3f455f90
PK
1344 // '\b'
1345 case '\x08':
1346 if (this.x > 0) {
1347 this.x--;
1348 }
1349 break;
1350
1351 // '\t'
1352 case '\t':
1353 this.x = this.nextStop();
1354 break;
8bc844c0 1355
3f455f90
PK
1356 // shift out
1357 case '\x0e':
1358 this.setgLevel(1);
1359 break;
1360
1361 // shift in
1362 case '\x0f':
1363 this.setgLevel(0);
1364 break;
1365
1366 // '\e'
1367 case '\x1b':
1368 this.state = escaped;
1369 break;
1370
1371 default:
1372 // ' '
1373 if (ch >= ' ') {
1374 if (this.charset && this.charset[ch]) {
1375 ch = this.charset[ch];
1376 }
1377
1378 if (this.x >= this.cols) {
1379 this.x = 0;
1380 this.y++;
1381 if (this.y > this.scrollBottom) {
1382 this.y--;
1383 this.scroll();
1384 }
1385 }
1386
1387 this.lines[this.y + this.ybase][this.x] = [this.curAttr, ch];
1388 this.x++;
1389 this.updateRange(this.y);
1390
1391 if (isWide(ch)) {
1392 j = this.y + this.ybase;
1393 if (this.cols < 2 || this.x >= this.cols) {
1394 this.lines[j][this.x - 1] = [this.curAttr, ' '];
1395 break;
1396 }
1397 this.lines[j][this.x] = [this.curAttr, ' '];
1398 this.x++;
1399 }
1400 }
1401 break;
a4607f90 1402 }
8bc844c0 1403 break;
3f455f90
PK
1404 case escaped:
1405 switch (ch) {
1406 // ESC [ Control Sequence Introducer ( CSI is 0x9b).
1407 case '[':
1408 this.params = [];
1409 this.currentParam = 0;
1410 this.state = csi;
1411 break;
8bc844c0 1412
3f455f90
PK
1413 // ESC ] Operating System Command ( OSC is 0x9d).
1414 case ']':
1415 this.params = [];
1416 this.currentParam = 0;
1417 this.state = osc;
1418 break;
8bc844c0 1419
3f455f90
PK
1420 // ESC P Device Control String ( DCS is 0x90).
1421 case 'P':
1422 this.params = [];
1423 this.currentParam = 0;
1424 this.state = dcs;
1425 break;
8bc844c0 1426
3f455f90
PK
1427 // ESC _ Application Program Command ( APC is 0x9f).
1428 case '_':
1429 this.state = ignore;
1430 break;
8bc844c0 1431
3f455f90
PK
1432 // ESC ^ Privacy Message ( PM is 0x9e).
1433 case '^':
1434 this.state = ignore;
1435 break;
8bc844c0 1436
3f455f90
PK
1437 // ESC c Full Reset (RIS).
1438 case 'c':
1439 this.reset();
1440 break;
8bc844c0 1441
3f455f90
PK
1442 // ESC E Next Line ( NEL is 0x85).
1443 // ESC D Index ( IND is 0x84).
1444 case 'E':
1445 this.x = 0;
1446 ;
1447 case 'D':
1448 this.index();
1449 break;
8bc844c0 1450
3f455f90
PK
1451 // ESC M Reverse Index ( RI is 0x8d).
1452 case 'M':
1453 this.reverseIndex();
1454 break;
8bc844c0 1455
3f455f90
PK
1456 // ESC % Select default/utf-8 character set.
1457 // @ = default, G = utf-8
1458 case '%':
1459 //this.charset = null;
1460 this.setgLevel(0);
1461 this.setgCharset(0, Terminal.charsets.US);
1462 this.state = normal;
1463 i++;
1464 break;
8bc844c0 1465
3f455f90
PK
1466 // ESC (,),*,+,-,. Designate G0-G2 Character Set.
1467 case '(': // <-- this seems to get all the attention
1468 case ')':
1469 case '*':
1470 case '+':
1471 case '-':
1472 case '.':
1473 switch (ch) {
1474 case '(':
1475 this.gcharset = 0;
1476 break;
1477 case ')':
1478 this.gcharset = 1;
1479 break;
1480 case '*':
1481 this.gcharset = 2;
1482 break;
1483 case '+':
1484 this.gcharset = 3;
1485 break;
1486 case '-':
1487 this.gcharset = 1;
1488 break;
1489 case '.':
1490 this.gcharset = 2;
1491 break;
1492 }
1493 this.state = charset;
1494 break;
8bc844c0 1495
3f455f90
PK
1496 // Designate G3 Character Set (VT300).
1497 // A = ISO Latin-1 Supplemental.
1498 // Not implemented.
1499 case '/':
1500 this.gcharset = 3;
1501 this.state = charset;
1502 i--;
1503 break;
8bc844c0 1504
3f455f90
PK
1505 // ESC N
1506 // Single Shift Select of G2 Character Set
1507 // ( SS2 is 0x8e). This affects next character only.
1508 case 'N':
1509 break;
1510 // ESC O
1511 // Single Shift Select of G3 Character Set
1512 // ( SS3 is 0x8f). This affects next character only.
1513 case 'O':
1514 break;
1515 // ESC n
1516 // Invoke the G2 Character Set as GL (LS2).
1517 case 'n':
1518 this.setgLevel(2);
1519 break;
1520 // ESC o
1521 // Invoke the G3 Character Set as GL (LS3).
1522 case 'o':
1523 this.setgLevel(3);
1524 break;
1525 // ESC |
1526 // Invoke the G3 Character Set as GR (LS3R).
1527 case '|':
1528 this.setgLevel(3);
1529 break;
1530 // ESC }
1531 // Invoke the G2 Character Set as GR (LS2R).
1532 case '}':
1533 this.setgLevel(2);
1534 break;
1535 // ESC ~
1536 // Invoke the G1 Character Set as GR (LS1R).
1537 case '~':
1538 this.setgLevel(1);
1539 break;
8bc844c0 1540
3f455f90
PK
1541 // ESC 7 Save Cursor (DECSC).
1542 case '7':
1543 this.saveCursor();
1544 this.state = normal;
1545 break;
8bc844c0 1546
3f455f90
PK
1547 // ESC 8 Restore Cursor (DECRC).
1548 case '8':
1549 this.restoreCursor();
1550 this.state = normal;
1551 break;
8bc844c0 1552
3f455f90
PK
1553 // ESC # 3 DEC line height/width
1554 case '#':
1555 this.state = normal;
1556 i++;
1557 break;
8bc844c0 1558
3f455f90
PK
1559 // ESC H Tab Set (HTS is 0x88).
1560 case 'H':
1561 this.tabSet();
1562 break;
8bc844c0 1563
3f455f90
PK
1564 // ESC = Application Keypad (DECPAM).
1565 case '=':
1566 this.log('Serial port requested application keypad.');
1567 this.applicationKeypad = true;
1568 this.state = normal;
1569 break;
8bc844c0 1570
3f455f90
PK
1571 // ESC > Normal Keypad (DECPNM).
1572 case '>':
1573 this.log('Switching back to normal keypad.');
1574 this.applicationKeypad = false;
1575 this.state = normal;
1576 break;
8bc844c0 1577
3f455f90
PK
1578 default:
1579 this.state = normal;
1580 this.error('Unknown ESC control: %s.', ch);
1581 break;
1582 }
8bc844c0
CJ
1583 break;
1584
3f455f90
PK
1585 case charset:
1586 switch (ch) {
1587 case '0': // DEC Special Character and Line Drawing Set.
1588 cs = Terminal.charsets.SCLD;
1589 break;
1590 case 'A': // UK
1591 cs = Terminal.charsets.UK;
1592 break;
1593 case 'B': // United States (USASCII).
1594 cs = Terminal.charsets.US;
1595 break;
1596 case '4': // Dutch
1597 cs = Terminal.charsets.Dutch;
1598 break;
1599 case 'C': // Finnish
1600 case '5':
1601 cs = Terminal.charsets.Finnish;
1602 break;
1603 case 'R': // French
1604 cs = Terminal.charsets.French;
1605 break;
1606 case 'Q': // FrenchCanadian
1607 cs = Terminal.charsets.FrenchCanadian;
1608 break;
1609 case 'K': // German
1610 cs = Terminal.charsets.German;
1611 break;
1612 case 'Y': // Italian
1613 cs = Terminal.charsets.Italian;
1614 break;
1615 case 'E': // NorwegianDanish
1616 case '6':
1617 cs = Terminal.charsets.NorwegianDanish;
1618 break;
1619 case 'Z': // Spanish
1620 cs = Terminal.charsets.Spanish;
1621 break;
1622 case 'H': // Swedish
1623 case '7':
1624 cs = Terminal.charsets.Swedish;
1625 break;
1626 case '=': // Swiss
1627 cs = Terminal.charsets.Swiss;
1628 break;
1629 case '/': // ISOLatin (actually /A)
1630 cs = Terminal.charsets.ISOLatin;
1631 i++;
1632 break;
1633 default: // Default
1634 cs = Terminal.charsets.US;
1635 break;
1636 }
1637 this.setgCharset(this.gcharset, cs);
1638 this.gcharset = null;
1639 this.state = normal;
8bc844c0
CJ
1640 break;
1641
3f455f90
PK
1642 case osc:
1643 // OSC Ps ; Pt ST
1644 // OSC Ps ; Pt BEL
1645 // Set Text Parameters.
1646 if (ch === '\x1b' || ch === '\x07') {
1647 if (ch === '\x1b') i++;
8bc844c0 1648
3f455f90 1649 this.params.push(this.currentParam);
8bc844c0 1650
3f455f90
PK
1651 switch (this.params[0]) {
1652 case 0:
1653 case 1:
1654 case 2:
1655 if (this.params[1]) {
1656 this.title = this.params[1];
1657 this.handleTitle(this.title);
1658 }
1659 break;
1660 case 3:
1661 // set X property
1662 break;
1663 case 4:
1664 case 5:
1665 // change dynamic colors
1666 break;
1667 case 10:
1668 case 11:
1669 case 12:
1670 case 13:
1671 case 14:
1672 case 15:
1673 case 16:
1674 case 17:
1675 case 18:
1676 case 19:
1677 // change dynamic ui colors
1678 break;
1679 case 46:
1680 // change log file
1681 break;
1682 case 50:
1683 // dynamic font
1684 break;
1685 case 51:
1686 // emacs shell
1687 break;
1688 case 52:
1689 // manipulate selection data
1690 break;
1691 case 104:
1692 case 105:
1693 case 110:
1694 case 111:
1695 case 112:
1696 case 113:
1697 case 114:
1698 case 115:
1699 case 116:
1700 case 117:
1701 case 118:
1702 // reset colors
1703 break;
1704 }
8bc844c0 1705
3f455f90
PK
1706 this.params = [];
1707 this.currentParam = 0;
1708 this.state = normal;
1709 } else {
1710 if (!this.params.length) {
1711 if (ch >= '0' && ch <= '9') {
1712 this.currentParam =
1713 this.currentParam * 10 + ch.charCodeAt(0) - 48;
1714 } else if (ch === ';') {
1715 this.params.push(this.currentParam);
1716 this.currentParam = '';
1717 }
1718 } else {
1719 this.currentParam += ch;
1720 }
1721 }
8bc844c0
CJ
1722 break;
1723
3f455f90
PK
1724 case csi:
1725 // '?', '>', '!'
1726 if (ch === '?' || ch === '>' || ch === '!') {
1727 this.prefix = ch;
1728 break;
8bc844c0 1729 }
8bc844c0 1730
3f455f90
PK
1731 // 0 - 9
1732 if (ch >= '0' && ch <= '9') {
1733 this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48;
1734 break;
1735 }
8bc844c0 1736
3f455f90
PK
1737 // '$', '"', ' ', '\''
1738 if (ch === '$' || ch === '"' || ch === ' ' || ch === '\'') {
1739 this.postfix = ch;
1740 break;
1741 }
1742
1743 this.params.push(this.currentParam);
1744 this.currentParam = 0;
1745
1746 // ';'
1747 if (ch === ';') break;
1748
1749 this.state = normal;
1750
1751 switch (ch) {
1752 // CSI Ps A
1753 // Cursor Up Ps Times (default = 1) (CUU).
1754 case 'A':
1755 this.cursorUp(this.params);
1756 break;
1757
1758 // CSI Ps B
1759 // Cursor Down Ps Times (default = 1) (CUD).
1760 case 'B':
1761 this.cursorDown(this.params);
1762 break;
1763
1764 // CSI Ps C
1765 // Cursor Forward Ps Times (default = 1) (CUF).
1766 case 'C':
1767 this.cursorForward(this.params);
1768 break;
1769
1770 // CSI Ps D
1771 // Cursor Backward Ps Times (default = 1) (CUB).
1772 case 'D':
1773 this.cursorBackward(this.params);
1774 break;
1775
1776 // CSI Ps ; Ps H
1777 // Cursor Position [row;column] (default = [1,1]) (CUP).
1778 case 'H':
1779 this.cursorPos(this.params);
1780 break;
1781
1782 // CSI Ps J Erase in Display (ED).
1783 case 'J':
1784 this.eraseInDisplay(this.params);
1785 break;
1786
1787 // CSI Ps K Erase in Line (EL).
1788 case 'K':
1789 this.eraseInLine(this.params);
1790 break;
1791
1792 // CSI Pm m Character Attributes (SGR).
1793 case 'm':
1794 if (!this.prefix) {
1795 this.charAttributes(this.params);
1796 }
1797 break;
1798
1799 // CSI Ps n Device Status Report (DSR).
1800 case 'n':
1801 if (!this.prefix) {
1802 this.deviceStatus(this.params);
1803 }
1804 break;
1805
1806 /**
1807 * Additions
1808 */
1809
1810 // CSI Ps @
1811 // Insert Ps (Blank) Character(s) (default = 1) (ICH).
1812 case '@':
1813 this.insertChars(this.params);
1814 break;
1815
1816 // CSI Ps E
1817 // Cursor Next Line Ps Times (default = 1) (CNL).
1818 case 'E':
1819 this.cursorNextLine(this.params);
1820 break;
1821
1822 // CSI Ps F
1823 // Cursor Preceding Line Ps Times (default = 1) (CNL).
1824 case 'F':
1825 this.cursorPrecedingLine(this.params);
1826 break;
1827
1828 // CSI Ps G
1829 // Cursor Character Absolute [column] (default = [row,1]) (CHA).
1830 case 'G':
1831 this.cursorCharAbsolute(this.params);
1832 break;
1833
1834 // CSI Ps L
1835 // Insert Ps Line(s) (default = 1) (IL).
1836 case 'L':
1837 this.insertLines(this.params);
1838 break;
1839
1840 // CSI Ps M
1841 // Delete Ps Line(s) (default = 1) (DL).
1842 case 'M':
1843 this.deleteLines(this.params);
1844 break;
1845
1846 // CSI Ps P
1847 // Delete Ps Character(s) (default = 1) (DCH).
1848 case 'P':
1849 this.deleteChars(this.params);
1850 break;
1851
1852 // CSI Ps X
1853 // Erase Ps Character(s) (default = 1) (ECH).
1854 case 'X':
1855 this.eraseChars(this.params);
1856 break;
1857
1858 // CSI Pm ` Character Position Absolute
1859 // [column] (default = [row,1]) (HPA).
1860 case '`':
1861 this.charPosAbsolute(this.params);
1862 break;
1863
1864 // 141 61 a * HPR -
1865 // Horizontal Position Relative
1866 case 'a':
1867 this.HPositionRelative(this.params);
1868 break;
1869
1870 // CSI P s c
1871 // Send Device Attributes (Primary DA).
1872 // CSI > P s c
1873 // Send Device Attributes (Secondary DA)
1874 case 'c':
1875 this.sendDeviceAttributes(this.params);
1876 break;
1877
1878 // CSI Pm d
1879 // Line Position Absolute [row] (default = [1,column]) (VPA).
1880 case 'd':
1881 this.linePosAbsolute(this.params);
1882 break;
1883
1884 // 145 65 e * VPR - Vertical Position Relative
1885 case 'e':
1886 this.VPositionRelative(this.params);
1887 break;
1888
1889 // CSI Ps ; Ps f
1890 // Horizontal and Vertical Position [row;column] (default =
1891 // [1,1]) (HVP).
1892 case 'f':
1893 this.HVPosition(this.params);
1894 break;
1895
1896 // CSI Pm h Set Mode (SM).
1897 // CSI ? Pm h - mouse escape codes, cursor escape codes
1898 case 'h':
1899 this.setMode(this.params);
1900 break;
1901
1902 // CSI Pm l Reset Mode (RM).
1903 // CSI ? Pm l
1904 case 'l':
1905 this.resetMode(this.params);
1906 break;
1907
1908 // CSI Ps ; Ps r
1909 // Set Scrolling Region [top;bottom] (default = full size of win-
1910 // dow) (DECSTBM).
1911 // CSI ? Pm r
1912 case 'r':
1913 this.setScrollRegion(this.params);
1914 break;
1915
1916 // CSI s
1917 // Save cursor (ANSI.SYS).
1918 case 's':
1919 this.saveCursor(this.params);
1920 break;
1921
1922 // CSI u
1923 // Restore cursor (ANSI.SYS).
1924 case 'u':
1925 this.restoreCursor(this.params);
1926 break;
1927
1928 /**
1929 * Lesser Used
1930 */
1931
1932 // CSI Ps I
1933 // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
1934 case 'I':
1935 this.cursorForwardTab(this.params);
1936 break;
1937
1938 // CSI Ps S Scroll up Ps lines (default = 1) (SU).
1939 case 'S':
1940 this.scrollUp(this.params);
1941 break;
1942
1943 // CSI Ps T Scroll down Ps lines (default = 1) (SD).
1944 // CSI Ps ; Ps ; Ps ; Ps ; Ps T
1945 // CSI > Ps; Ps T
1946 case 'T':
1947 // if (this.prefix === '>') {
1948 // this.resetTitleModes(this.params);
1949 // break;
1950 // }
1951 // if (this.params.length > 2) {
1952 // this.initMouseTracking(this.params);
1953 // break;
1954 // }
1955 if (this.params.length < 2 && !this.prefix) {
1956 this.scrollDown(this.params);
1957 }
1958 break;
1959
1960 // CSI Ps Z
1961 // Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
1962 case 'Z':
1963 this.cursorBackwardTab(this.params);
1964 break;
1965
1966 // CSI Ps b Repeat the preceding graphic character Ps times (REP).
1967 case 'b':
1968 this.repeatPrecedingCharacter(this.params);
1969 break;
1970
1971 // CSI Ps g Tab Clear (TBC).
1972 case 'g':
1973 this.tabClear(this.params);
1974 break;
1975
1976 // CSI Pm i Media Copy (MC).
1977 // CSI ? Pm i
1978 // case 'i':
1979 // this.mediaCopy(this.params);
1980 // break;
1981
1982 // CSI Pm m Character Attributes (SGR).
1983 // CSI > Ps; Ps m
1984 // case 'm': // duplicate
1985 // if (this.prefix === '>') {
1986 // this.setResources(this.params);
1987 // } else {
1988 // this.charAttributes(this.params);
1989 // }
1990 // break;
1991
1992 // CSI Ps n Device Status Report (DSR).
1993 // CSI > Ps n
1994 // case 'n': // duplicate
1995 // if (this.prefix === '>') {
1996 // this.disableModifiers(this.params);
1997 // } else {
1998 // this.deviceStatus(this.params);
1999 // }
2000 // break;
2001
2002 // CSI > Ps p Set pointer mode.
2003 // CSI ! p Soft terminal reset (DECSTR).
2004 // CSI Ps$ p
2005 // Request ANSI mode (DECRQM).
2006 // CSI ? Ps$ p
2007 // Request DEC private mode (DECRQM).
2008 // CSI Ps ; Ps " p
2009 case 'p':
2010 switch (this.prefix) {
2011 // case '>':
2012 // this.setPointerMode(this.params);
2013 // break;
2014 case '!':
2015 this.softReset(this.params);
2016 break;
2017 // case '?':
2018 // if (this.postfix === '$') {
2019 // this.requestPrivateMode(this.params);
2020 // }
2021 // break;
2022 // default:
2023 // if (this.postfix === '"') {
2024 // this.setConformanceLevel(this.params);
2025 // } else if (this.postfix === '$') {
2026 // this.requestAnsiMode(this.params);
2027 // }
2028 // break;
2029 }
2030 break;
2031
2032 // CSI Ps q Load LEDs (DECLL).
2033 // CSI Ps SP q
2034 // CSI Ps " q
2035 // case 'q':
2036 // if (this.postfix === ' ') {
2037 // this.setCursorStyle(this.params);
2038 // break;
2039 // }
2040 // if (this.postfix === '"') {
2041 // this.setCharProtectionAttr(this.params);
2042 // break;
2043 // }
2044 // this.loadLEDs(this.params);
2045 // break;
2046
2047 // CSI Ps ; Ps r
2048 // Set Scrolling Region [top;bottom] (default = full size of win-
2049 // dow) (DECSTBM).
2050 // CSI ? Pm r
2051 // CSI Pt; Pl; Pb; Pr; Ps$ r
2052 // case 'r': // duplicate
2053 // if (this.prefix === '?') {
2054 // this.restorePrivateValues(this.params);
2055 // } else if (this.postfix === '$') {
2056 // this.setAttrInRectangle(this.params);
2057 // } else {
2058 // this.setScrollRegion(this.params);
2059 // }
2060 // break;
2061
2062 // CSI s Save cursor (ANSI.SYS).
2063 // CSI ? Pm s
2064 // case 's': // duplicate
2065 // if (this.prefix === '?') {
2066 // this.savePrivateValues(this.params);
2067 // } else {
2068 // this.saveCursor(this.params);
2069 // }
2070 // break;
2071
2072 // CSI Ps ; Ps ; Ps t
2073 // CSI Pt; Pl; Pb; Pr; Ps$ t
2074 // CSI > Ps; Ps t
2075 // CSI Ps SP t
2076 // case 't':
2077 // if (this.postfix === '$') {
2078 // this.reverseAttrInRectangle(this.params);
2079 // } else if (this.postfix === ' ') {
2080 // this.setWarningBellVolume(this.params);
2081 // } else {
2082 // if (this.prefix === '>') {
2083 // this.setTitleModeFeature(this.params);
2084 // } else {
2085 // this.manipulateWindow(this.params);
2086 // }
2087 // }
2088 // break;
2089
2090 // CSI u Restore cursor (ANSI.SYS).
2091 // CSI Ps SP u
2092 // case 'u': // duplicate
2093 // if (this.postfix === ' ') {
2094 // this.setMarginBellVolume(this.params);
2095 // } else {
2096 // this.restoreCursor(this.params);
2097 // }
2098 // break;
2099
2100 // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
2101 // case 'v':
2102 // if (this.postfix === '$') {
2103 // this.copyRectagle(this.params);
2104 // }
2105 // break;
2106
2107 // CSI Pt ; Pl ; Pb ; Pr ' w
2108 // case 'w':
2109 // if (this.postfix === '\'') {
2110 // this.enableFilterRectangle(this.params);
2111 // }
2112 // break;
2113
2114 // CSI Ps x Request Terminal Parameters (DECREQTPARM).
2115 // CSI Ps x Select Attribute Change Extent (DECSACE).
2116 // CSI Pc; Pt; Pl; Pb; Pr$ x
2117 // case 'x':
2118 // if (this.postfix === '$') {
2119 // this.fillRectangle(this.params);
2120 // } else {
2121 // this.requestParameters(this.params);
2122 // //this.__(this.params);
2123 // }
2124 // break;
2125
2126 // CSI Ps ; Pu ' z
2127 // CSI Pt; Pl; Pb; Pr$ z
2128 // case 'z':
2129 // if (this.postfix === '\'') {
2130 // this.enableLocatorReporting(this.params);
2131 // } else if (this.postfix === '$') {
2132 // this.eraseRectangle(this.params);
2133 // }
2134 // break;
2135
2136 // CSI Pm ' {
2137 // CSI Pt; Pl; Pb; Pr$ {
2138 // case '{':
2139 // if (this.postfix === '\'') {
2140 // this.setLocatorEvents(this.params);
2141 // } else if (this.postfix === '$') {
2142 // this.selectiveEraseRectangle(this.params);
2143 // }
2144 // break;
2145
2146 // CSI Ps ' |
2147 // case '|':
2148 // if (this.postfix === '\'') {
2149 // this.requestLocatorPosition(this.params);
2150 // }
2151 // break;
2152
2153 // CSI P m SP }
2154 // Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
2155 // case '}':
2156 // if (this.postfix === ' ') {
2157 // this.insertColumns(this.params);
2158 // }
2159 // break;
2160
2161 // CSI P m SP ~
2162 // Delete P s Column(s) (default = 1) (DECDC), VT420 and up
2163 // case '~':
2164 // if (this.postfix === ' ') {
2165 // this.deleteColumns(this.params);
2166 // }
2167 // break;
2168
2169 default:
2170 this.error('Unknown CSI code: %s.', ch);
2171 break;
2172 }
2173
2174 this.prefix = '';
2175 this.postfix = '';
2176 break;
2177
2178 case dcs:
2179 if (ch === '\x1b' || ch === '\x07') {
2180 if (ch === '\x1b') i++;
2181
2182 switch (this.prefix) {
2183 // User-Defined Keys (DECUDK).
2184 case '':
2185 break;
2186
2187 // Request Status String (DECRQSS).
2188 // test: echo -e '\eP$q"p\e\\'
2189 case '$q':
2190 var pt = this.currentParam
2191 , valid = false;
2192
2193 switch (pt) {
2194 // DECSCA
2195 case '"q':
2196 pt = '0"q';
2197 break;
2198
2199 // DECSCL
2200 case '"p':
2201 pt = '61"p';
2202 break;
2203
2204 // DECSTBM
2205 case 'r':
2206 pt = ''
2207 + (this.scrollTop + 1)
2208 + ';'
2209 + (this.scrollBottom + 1)
2210 + 'r';
2211 break;
2212
2213 // SGR
2214 case 'm':
2215 pt = '0m';
2216 break;
2217
2218 default:
2219 this.error('Unknown DCS Pt: %s.', pt);
2220 pt = '';
2221 break;
2222 }
2223
2224 this.send('\x1bP' + +valid + '$r' + pt + '\x1b\\');
2225 break;
2226
2227 // Set Termcap/Terminfo Data (xterm, experimental).
2228 case '+p':
2229 break;
2230
2231 // Request Termcap/Terminfo String (xterm, experimental)
2232 // Regular xterm does not even respond to this sequence.
2233 // This can cause a small glitch in vim.
2234 // test: echo -ne '\eP+q6b64\e\\'
2235 case '+q':
2236 var pt = this.currentParam
2237 , valid = false;
2238
2239 this.send('\x1bP' + +valid + '+r' + pt + '\x1b\\');
2240 break;
2241
2242 default:
2243 this.error('Unknown DCS prefix: %s.', this.prefix);
2244 break;
2245 }
2246
2247 this.currentParam = 0;
2248 this.prefix = '';
2249 this.state = normal;
2250 } else if (!this.currentParam) {
2251 if (!this.prefix && ch !== '$' && ch !== '+') {
2252 this.currentParam = ch;
2253 } else if (this.prefix.length === 2) {
2254 this.currentParam = ch;
2255 } else {
2256 this.prefix += ch;
2257 }
2258 } else {
2259 this.currentParam += ch;
2260 }
2261 break;
2262
2263 case ignore:
2264 // For PM and APC.
2265 if (ch === '\x1b' || ch === '\x07') {
2266 if (ch === '\x1b') i++;
2267 this.state = normal;
2268 }
2269 break;
2270 }
2271 }
2272
2273 this.updateRange(this.y);
2274 this.refresh(this.refreshStart, this.refreshEnd);
2275 };
2276
2277 Terminal.prototype.writeln = function(data) {
2278 this.write(data + '\r\n');
2279 };
2280
2281 // Key Resources:
2282 // https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
2283 Terminal.prototype.keyDown = function(ev) {
2284 var self = this, key;
2285
2286 switch (ev.keyCode) {
2287 // backspace
2288 case 8:
2289 if (ev.shiftKey) {
2290 key = '\x08'; // ^H
2291 break;
2292 }
2293 key = '\x7f'; // ^?
2294 break;
2295 // tab
2296 case 9:
2297 if (ev.shiftKey) {
2298 key = '\x1b[Z';
2299 break;
2300 }
2301 key = '\t';
2302 this.cancel(ev, true);
2303 break;
2304 // return/enter
2305 case 13:
2306 key = '\r';
2307 this.cancel(ev, true);
2308 break;
2309 // escape
2310 case 27:
2311 key = '\x1b';
2312 this.cancel(ev, true);
2313 break;
2314 // left-arrow
2315 case 37:
72ed03ad 2316 if (ev.altKey) {
f00d8964 2317 this.cancel(ev, true);
72ed03ad
PK
2318 key = '\x1bb' // Jump a word back
2319 break;
2320 } else if (this.applicationCursor) {
3f455f90 2321 key = '\x1bOD'; // SS3 as ^[O for 7-bit
3f455f90
PK
2322 break;
2323 }
2324 key = '\x1b[D';
2325 break;
2326 // right-arrow
2327 case 39:
72ed03ad 2328 if (ev.altKey) {
f00d8964 2329 this.cancel(ev, true);
72ed03ad
PK
2330 key = '\x1bf' // Jump a word forward
2331 break;
2332 } else if (this.applicationCursor) {
3f455f90
PK
2333 key = '\x1bOC';
2334 break;
2335 }
2336 key = '\x1b[C';
2337 break;
2338 // up-arrow
2339 case 38:
2340 if (this.applicationCursor) {
2341 key = '\x1bOA';
2342 break;
2343 }
2344 if (ev.ctrlKey) {
2345 this.scrollDisp(-1);
2346 return this.cancel(ev);
2347 } else {
2348 key = '\x1b[A';
2349 }
2350 break;
2351 // down-arrow
2352 case 40:
2353 if (this.applicationCursor) {
2354 key = '\x1bOB';
2355 break;
2356 }
2357 if (ev.ctrlKey) {
2358 this.scrollDisp(1);
2359 return this.cancel(ev);
2360 } else {
2361 key = '\x1b[B';
2362 }
2363 break;
2364 // delete
2365 case 46:
2366 key = '\x1b[3~';
2367 break;
2368 // insert
2369 case 45:
2370 key = '\x1b[2~';
2371 break;
2372 // home
2373 case 36:
2374 if (this.applicationKeypad) {
2375 key = '\x1bOH';
2376 break;
2377 }
2378 key = '\x1bOH';
2379 break;
2380 // end
2381 case 35:
2382 if (this.applicationKeypad) {
2383 key = '\x1bOF';
2384 break;
2385 }
2386 key = '\x1bOF';
2387 break;
2388 // page up
2389 case 33:
2390 if (ev.shiftKey) {
2391 this.scrollDisp(-(this.rows - 1));
2392 return this.cancel(ev);
2393 } else {
2394 key = '\x1b[5~';
2395 }
2396 break;
2397 // page down
2398 case 34:
2399 if (ev.shiftKey) {
2400 this.scrollDisp(this.rows - 1);
2401 return this.cancel(ev);
2402 } else {
2403 key = '\x1b[6~';
2404 }
2405 break;
2406 // F1
2407 case 112:
2408 key = '\x1bOP';
2409 break;
2410 // F2
2411 case 113:
2412 key = '\x1bOQ';
2413 break;
2414 // F3
2415 case 114:
2416 key = '\x1bOR';
2417 break;
2418 // F4
2419 case 115:
2420 key = '\x1bOS';
2421 break;
2422 // F5
2423 case 116:
2424 key = '\x1b[15~';
2425 break;
2426 // F6
2427 case 117:
2428 key = '\x1b[17~';
2429 break;
2430 // F7
2431 case 118:
2432 key = '\x1b[18~';
2433 break;
2434 // F8
2435 case 119:
2436 key = '\x1b[19~';
2437 break;
2438 // F9
2439 case 120:
2440 key = '\x1b[20~';
2441 break;
2442 // F10
2443 case 121:
2444 key = '\x1b[21~';
2445 break;
2446 // F11
2447 case 122:
2448 key = '\x1b[23~';
2449 break;
2450 // F12
2451 case 123:
2452 key = '\x1b[24~';
2453 break;
2454 default:
2455 // a-z and space
369e1f4c 2456 if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
3f455f90
PK
2457 if (ev.keyCode >= 65 && ev.keyCode <= 90) {
2458 key = String.fromCharCode(ev.keyCode - 64);
2459 } else if (ev.keyCode === 32) {
2460 // NUL
2461 key = String.fromCharCode(0);
2462 } else if (ev.keyCode >= 51 && ev.keyCode <= 55) {
2463 // escape, file sep, group sep, record sep, unit sep
2464 key = String.fromCharCode(ev.keyCode - 51 + 27);
2465 } else if (ev.keyCode === 56) {
2466 // delete
2467 key = String.fromCharCode(127);
2468 } else if (ev.keyCode === 219) {
2469 // ^[ - escape
2470 key = String.fromCharCode(27);
2471 } else if (ev.keyCode === 221) {
2472 // ^] - group sep
2473 key = String.fromCharCode(29);
2474 }
2475 } else if ((!this.isMac && ev.altKey) || (this.isMac && ev.metaKey)) {
2476 if (ev.keyCode >= 65 && ev.keyCode <= 90) {
2477 key = '\x1b' + String.fromCharCode(ev.keyCode + 32);
2478 } else if (ev.keyCode === 192) {
2479 key = '\x1b`';
2480 } else if (ev.keyCode >= 48 && ev.keyCode <= 57) {
2481 key = '\x1b' + (ev.keyCode - 48);
2482 }
2483 }
2484 break;
2485 }
2486
2487 if (!key || (this.isMac && ev.metaKey)) {
2488 return true;
2489 }
2490
2491 this.emit('keydown', ev);
2492 this.emit('key', key, ev);
987f09d8 2493 this.showCursor();
3f455f90
PK
2494 this.handler(key);
2495
58056df2 2496 return this.cancel(ev, true);
3f455f90
PK
2497 };
2498
2499 Terminal.prototype.setgLevel = function(g) {
2500 this.glevel = g;
2501 this.charset = this.charsets[g];
2502 };
2503
2504 Terminal.prototype.setgCharset = function(g, charset) {
2505 this.charsets[g] = charset;
2506 if (this.glevel === g) {
2507 this.charset = charset;
2508 }
2509 };
2510
2511 Terminal.prototype.keyPress = function(ev) {
2512 var key;
2513
3f455f90
PK
2514 if (ev.charCode) {
2515 key = ev.charCode;
2516 } else if (ev.which == null) {
2517 key = ev.keyCode;
2518 } else if (ev.which !== 0 && ev.charCode !== 0) {
2519 key = ev.which;
2520 } else {
2521 return false;
2522 }
2523
2524 if (!key || ev.ctrlKey || ev.altKey || ev.metaKey) {
2525 return false;
2526 }
2527
2528 key = String.fromCharCode(key);
2529
f3bd6145
PK
2530 /**
2531 * When a key is pressed and a character is sent to the terminal, then clear any text
2532 * selected in the terminal.
2533 */
2534 if (key) {
64721687 2535 this.clearSelection();
f3bd6145
PK
2536 }
2537
3f455f90
PK
2538 this.emit('keypress', key, ev);
2539 this.emit('key', key, ev);
2540 this.showCursor();
2541 this.handler(key);
2542
58056df2
PK
2543 this.cancel(ev, true);
2544
3f455f90
PK
2545 return false;
2546 };
2547
2548 Terminal.prototype.send = function(data) {
2549 var self = this;
2550
2551 if (!this.queue) {
2552 setTimeout(function() {
2553 self.handler(self.queue);
2554 self.queue = '';
2555 }, 1);
2556 }
2557
2558 this.queue += data;
2559 };
2560
2561 Terminal.prototype.bell = function() {
2562 if (!this.visualBell) return;
2563 var self = this;
2564 this.element.style.borderColor = 'white';
2565 setTimeout(function() {
2566 self.element.style.borderColor = '';
2567 }, 10);
2568 if (this.popOnBell) this.focus();
2569 };
2570
2571 Terminal.prototype.log = function() {
2572 if (!this.debug) return;
2573 if (!this.context.console || !this.context.console.log) return;
2574 var args = Array.prototype.slice.call(arguments);
2575 this.context.console.log.apply(this.context.console, args);
2576 };
2577
2578 Terminal.prototype.error = function() {
2579 if (!this.debug) return;
2580 if (!this.context.console || !this.context.console.error) return;
2581 var args = Array.prototype.slice.call(arguments);
2582 this.context.console.error.apply(this.context.console, args);
2583 };
2584
2585 Terminal.prototype.resize = function(x, y) {
2586 var line
2587 , el
2588 , i
2589 , j
2590 , ch;
2591
2592 if (x < 1) x = 1;
2593 if (y < 1) y = 1;
2594
2595 // resize cols
2596 j = this.cols;
2597 if (j < x) {
2598 ch = [this.defAttr, ' ']; // does xterm use the default attr?
2599 i = this.lines.length;
2600 while (i--) {
2601 while (this.lines[i].length < x) {
2602 this.lines[i].push(ch);
2603 }
2604 }
2605 } else if (j > x) {
2606 i = this.lines.length;
2607 while (i--) {
2608 while (this.lines[i].length > x) {
2609 this.lines[i].pop();
2610 }
2611 }
2612 }
2613 this.setupStops(j);
2614 this.cols = x;
2615
2616 // resize rows
2617 j = this.rows;
2618 if (j < y) {
2619 el = this.element;
2620 while (j++ < y) {
2621 if (this.lines.length < y + this.ybase) {
2622 this.lines.push(this.blankLine());
2623 }
2624 if (this.children.length < y) {
2625 this.insertRow();
2626 }
2627 }
2628 } else if (j > y) {
2629 while (j-- > y) {
2630 if (this.lines.length > y + this.ybase) {
685bc54b 2631 this.lines.shift();
3f455f90
PK
2632 }
2633 if (this.children.length > y) {
685bc54b 2634 el = this.children.shift();
3f455f90
PK
2635 if (!el) continue;
2636 el.parentNode.removeChild(el);
2637 }
2638 }
2639 }
2640 this.rows = y;
2641
2642 /*
2643 * Make sure that the cursor stays on screen
2644 */
2645 if (this.y >= y) {
2646 this.y = y - 1;
2647 }
2648
2649 if (this.x >= x) {
2650 this.x = x - 1;
2651 }
2652
2653 this.scrollTop = 0;
2654 this.scrollBottom = y - 1;
2655
2656 this.refresh(0, this.rows - 1);
2657
2658 this.normal = null;
2659
2660 this.emit('resize', {terminal: this, cols: x, rows: y});
2661 };
2662
2663 Terminal.prototype.updateRange = function(y) {
2664 if (y < this.refreshStart) this.refreshStart = y;
2665 if (y > this.refreshEnd) this.refreshEnd = y;
2666 // if (y > this.refreshEnd) {
2667 // this.refreshEnd = y;
2668 // if (y > this.rows - 1) {
2669 // this.refreshEnd = this.rows - 1;
2670 // }
2671 // }
2672 };
2673
2674 Terminal.prototype.maxRange = function() {
2675 this.refreshStart = 0;
2676 this.refreshEnd = this.rows - 1;
2677 };
2678
2679 Terminal.prototype.setupStops = function(i) {
2680 if (i != null) {
2681 if (!this.tabs[i]) {
2682 i = this.prevStop(i);
2683 }
2684 } else {
2685 this.tabs = {};
2686 i = 0;
2687 }
2688
2689 for (; i < this.cols; i += 8) {
2690 this.tabs[i] = true;
2691 }
2692 };
2693
2694 Terminal.prototype.prevStop = function(x) {
2695 if (x == null) x = this.x;
2696 while (!this.tabs[--x] && x > 0);
2697 return x >= this.cols
2698 ? this.cols - 1
2699 : x < 0 ? 0 : x;
2700 };
2701
2702 Terminal.prototype.nextStop = function(x) {
2703 if (x == null) x = this.x;
2704 while (!this.tabs[++x] && x < this.cols);
2705 return x >= this.cols
2706 ? this.cols - 1
2707 : x < 0 ? 0 : x;
2708 };
2709
2710 Terminal.prototype.eraseRight = function(x, y) {
2711 var line = this.lines[this.ybase + y]
2712 , ch = [this.eraseAttr(), ' ']; // xterm
2713
2714
2715 for (; x < this.cols; x++) {
2716 line[x] = ch;
2717 }
2718
2719 this.updateRange(y);
2720 };
2721
2722 Terminal.prototype.eraseLeft = function(x, y) {
2723 var line = this.lines[this.ybase + y]
2724 , ch = [this.eraseAttr(), ' ']; // xterm
2725
2726 x++;
2727 while (x--) line[x] = ch;
2728
2729 this.updateRange(y);
2730 };
2731
2732 Terminal.prototype.eraseLine = function(y) {
2733 this.eraseRight(0, y);
2734 };
2735
2736 Terminal.prototype.blankLine = function(cur) {
2737 var attr = cur
2738 ? this.eraseAttr()
2739 : this.defAttr;
2740
2741 var ch = [attr, ' ']
2742 , line = []
2743 , i = 0;
2744
2745 for (; i < this.cols; i++) {
2746 line[i] = ch;
2747 }
2748
2749 return line;
2750 };
2751
2752 Terminal.prototype.ch = function(cur) {
2753 return cur
2754 ? [this.eraseAttr(), ' ']
2755 : [this.defAttr, ' '];
2756 };
2757
2758 Terminal.prototype.is = function(term) {
2759 var name = this.termName;
2760 return (name + '').indexOf(term) === 0;
2761 };
2762
2763 Terminal.prototype.handler = function(data) {
2764 this.emit('data', data);
2765 };
2766
2767 Terminal.prototype.handleTitle = function(title) {
2768 this.emit('title', title);
2769 };
2770
2771 /**
2772 * ESC
2773 */
2774
2775 // ESC D Index (IND is 0x84).
2776 Terminal.prototype.index = function() {
2777 this.y++;
2778 if (this.y > this.scrollBottom) {
2779 this.y--;
2780 this.scroll();
2781 }
2782 this.state = normal;
2783 };
2784
2785 // ESC M Reverse Index (RI is 0x8d).
2786 Terminal.prototype.reverseIndex = function() {
2787 var j;
2788 this.y--;
2789 if (this.y < this.scrollTop) {
2790 this.y++;
2791 // possibly move the code below to term.reverseScroll();
2792 // test: echo -ne '\e[1;1H\e[44m\eM\e[0m'
2793 // blankLine(true) is xterm/linux behavior
2794 this.lines.splice(this.y + this.ybase, 0, this.blankLine(true));
2795 j = this.rows - 1 - this.scrollBottom;
2796 this.lines.splice(this.rows - 1 + this.ybase - j + 1, 1);
2797 // this.maxRange();
2798 this.updateRange(this.scrollTop);
2799 this.updateRange(this.scrollBottom);
2800 }
2801 this.state = normal;
2802 };
2803
2804 // ESC c Full Reset (RIS).
2805 Terminal.prototype.reset = function() {
2806 this.options.rows = this.rows;
2807 this.options.cols = this.cols;
2808 Terminal.call(this, this.options);
2809 this.refresh(0, this.rows - 1);
2810 };
2811
2812 // ESC H Tab Set (HTS is 0x88).
2813 Terminal.prototype.tabSet = function() {
2814 this.tabs[this.x] = true;
2815 this.state = normal;
2816 };
2817
2818 /**
2819 * CSI
2820 */
2821
2822 // CSI Ps A
2823 // Cursor Up Ps Times (default = 1) (CUU).
2824 Terminal.prototype.cursorUp = function(params) {
2825 var param = params[0];
2826 if (param < 1) param = 1;
2827 this.y -= param;
2828 if (this.y < 0) this.y = 0;
2829 };
2830
2831 // CSI Ps B
2832 // Cursor Down Ps Times (default = 1) (CUD).
2833 Terminal.prototype.cursorDown = function(params) {
2834 var param = params[0];
2835 if (param < 1) param = 1;
2836 this.y += param;
2837 if (this.y >= this.rows) {
2838 this.y = this.rows - 1;
2839 }
2840 };
2841
2842 // CSI Ps C
2843 // Cursor Forward Ps Times (default = 1) (CUF).
2844 Terminal.prototype.cursorForward = function(params) {
2845 var param = params[0];
2846 if (param < 1) param = 1;
2847 this.x += param;
2848 if (this.x >= this.cols) {
2849 this.x = this.cols - 1;
2850 }
2851 };
2852
2853 // CSI Ps D
2854 // Cursor Backward Ps Times (default = 1) (CUB).
2855 Terminal.prototype.cursorBackward = function(params) {
2856 var param = params[0];
2857 if (param < 1) param = 1;
2858 this.x -= param;
2859 if (this.x < 0) this.x = 0;
2860 };
2861
2862 // CSI Ps ; Ps H
2863 // Cursor Position [row;column] (default = [1,1]) (CUP).
2864 Terminal.prototype.cursorPos = function(params) {
2865 var row, col;
2866
2867 row = params[0] - 1;
2868
2869 if (params.length >= 2) {
2870 col = params[1] - 1;
2871 } else {
2872 col = 0;
2873 }
2874
2875 if (row < 0) {
2876 row = 0;
2877 } else if (row >= this.rows) {
2878 row = this.rows - 1;
2879 }
2880
2881 if (col < 0) {
2882 col = 0;
2883 } else if (col >= this.cols) {
2884 col = this.cols - 1;
2885 }
2886
2887 this.x = col;
2888 this.y = row;
2889 };
2890
2891 // CSI Ps J Erase in Display (ED).
2892 // Ps = 0 -> Erase Below (default).
2893 // Ps = 1 -> Erase Above.
2894 // Ps = 2 -> Erase All.
2895 // Ps = 3 -> Erase Saved Lines (xterm).
2896 // CSI ? Ps J
2897 // Erase in Display (DECSED).
2898 // Ps = 0 -> Selective Erase Below (default).
2899 // Ps = 1 -> Selective Erase Above.
2900 // Ps = 2 -> Selective Erase All.
2901 Terminal.prototype.eraseInDisplay = function(params) {
2902 var j;
2903 switch (params[0]) {
2904 case 0:
2905 this.eraseRight(this.x, this.y);
2906 j = this.y + 1;
2907 for (; j < this.rows; j++) {
2908 this.eraseLine(j);
2909 }
2910 break;
2911 case 1:
2912 this.eraseLeft(this.x, this.y);
2913 j = this.y;
2914 while (j--) {
2915 this.eraseLine(j);
2916 }
2917 break;
2918 case 2:
2919 j = this.rows;
2920 while (j--) this.eraseLine(j);
2921 break;
2922 case 3:
2923 ; // no saved lines
2924 break;
2925 }
2926 };
2927
2928 // CSI Ps K Erase in Line (EL).
2929 // Ps = 0 -> Erase to Right (default).
2930 // Ps = 1 -> Erase to Left.
2931 // Ps = 2 -> Erase All.
2932 // CSI ? Ps K
2933 // Erase in Line (DECSEL).
2934 // Ps = 0 -> Selective Erase to Right (default).
2935 // Ps = 1 -> Selective Erase to Left.
2936 // Ps = 2 -> Selective Erase All.
2937 Terminal.prototype.eraseInLine = function(params) {
2938 switch (params[0]) {
2939 case 0:
2940 this.eraseRight(this.x, this.y);
2941 break;
2942 case 1:
2943 this.eraseLeft(this.x, this.y);
2944 break;
2945 case 2:
2946 this.eraseLine(this.y);
2947 break;
2948 }
2949 };
2950
2951 // CSI Pm m Character Attributes (SGR).
2952 // Ps = 0 -> Normal (default).
2953 // Ps = 1 -> Bold.
2954 // Ps = 4 -> Underlined.
2955 // Ps = 5 -> Blink (appears as Bold).
2956 // Ps = 7 -> Inverse.
2957 // Ps = 8 -> Invisible, i.e., hidden (VT300).
2958 // Ps = 2 2 -> Normal (neither bold nor faint).
2959 // Ps = 2 4 -> Not underlined.
2960 // Ps = 2 5 -> Steady (not blinking).
2961 // Ps = 2 7 -> Positive (not inverse).
2962 // Ps = 2 8 -> Visible, i.e., not hidden (VT300).
2963 // Ps = 3 0 -> Set foreground color to Black.
2964 // Ps = 3 1 -> Set foreground color to Red.
2965 // Ps = 3 2 -> Set foreground color to Green.
2966 // Ps = 3 3 -> Set foreground color to Yellow.
2967 // Ps = 3 4 -> Set foreground color to Blue.
2968 // Ps = 3 5 -> Set foreground color to Magenta.
2969 // Ps = 3 6 -> Set foreground color to Cyan.
2970 // Ps = 3 7 -> Set foreground color to White.
2971 // Ps = 3 9 -> Set foreground color to default (original).
2972 // Ps = 4 0 -> Set background color to Black.
2973 // Ps = 4 1 -> Set background color to Red.
2974 // Ps = 4 2 -> Set background color to Green.
2975 // Ps = 4 3 -> Set background color to Yellow.
2976 // Ps = 4 4 -> Set background color to Blue.
2977 // Ps = 4 5 -> Set background color to Magenta.
2978 // Ps = 4 6 -> Set background color to Cyan.
2979 // Ps = 4 7 -> Set background color to White.
2980 // Ps = 4 9 -> Set background color to default (original).
2981
2982 // If 16-color support is compiled, the following apply. Assume
2983 // that xterm's resources are set so that the ISO color codes are
2984 // the first 8 of a set of 16. Then the aixterm colors are the
2985 // bright versions of the ISO colors:
2986 // Ps = 9 0 -> Set foreground color to Black.
2987 // Ps = 9 1 -> Set foreground color to Red.
2988 // Ps = 9 2 -> Set foreground color to Green.
2989 // Ps = 9 3 -> Set foreground color to Yellow.
2990 // Ps = 9 4 -> Set foreground color to Blue.
2991 // Ps = 9 5 -> Set foreground color to Magenta.
2992 // Ps = 9 6 -> Set foreground color to Cyan.
2993 // Ps = 9 7 -> Set foreground color to White.
2994 // Ps = 1 0 0 -> Set background color to Black.
2995 // Ps = 1 0 1 -> Set background color to Red.
2996 // Ps = 1 0 2 -> Set background color to Green.
2997 // Ps = 1 0 3 -> Set background color to Yellow.
2998 // Ps = 1 0 4 -> Set background color to Blue.
2999 // Ps = 1 0 5 -> Set background color to Magenta.
3000 // Ps = 1 0 6 -> Set background color to Cyan.
3001 // Ps = 1 0 7 -> Set background color to White.
3002
3003 // If xterm is compiled with the 16-color support disabled, it
3004 // supports the following, from rxvt:
3005 // Ps = 1 0 0 -> Set foreground and background color to
3006 // default.
3007
3008 // If 88- or 256-color support is compiled, the following apply.
3009 // Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second
3010 // Ps.
3011 // Ps = 4 8 ; 5 ; Ps -> Set background color to the second
3012 // Ps.
3013 Terminal.prototype.charAttributes = function(params) {
3014 // Optimize a single SGR0.
3015 if (params.length === 1 && params[0] === 0) {
3016 this.curAttr = this.defAttr;
3017 return;
3018 }
3019
3020 var l = params.length
3021 , i = 0
3022 , flags = this.curAttr >> 18
3023 , fg = (this.curAttr >> 9) & 0x1ff
3024 , bg = this.curAttr & 0x1ff
3025 , p;
3026
3027 for (; i < l; i++) {
3028 p = params[i];
3029 if (p >= 30 && p <= 37) {
3030 // fg color 8
3031 fg = p - 30;
3032 } else if (p >= 40 && p <= 47) {
3033 // bg color 8
3034 bg = p - 40;
3035 } else if (p >= 90 && p <= 97) {
3036 // fg color 16
3037 p += 8;
3038 fg = p - 90;
3039 } else if (p >= 100 && p <= 107) {
3040 // bg color 16
3041 p += 8;
3042 bg = p - 100;
3043 } else if (p === 0) {
3044 // default
3045 flags = this.defAttr >> 18;
3046 fg = (this.defAttr >> 9) & 0x1ff;
3047 bg = this.defAttr & 0x1ff;
3048 // flags = 0;
3049 // fg = 0x1ff;
3050 // bg = 0x1ff;
3051 } else if (p === 1) {
3052 // bold text
3053 flags |= 1;
3054 } else if (p === 4) {
3055 // underlined text
3056 flags |= 2;
3057 } else if (p === 5) {
3058 // blink
3059 flags |= 4;
3060 } else if (p === 7) {
3061 // inverse and positive
3062 // test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
3063 flags |= 8;
3064 } else if (p === 8) {
3065 // invisible
3066 flags |= 16;
3067 } else if (p === 22) {
3068 // not bold
3069 flags &= ~1;
3070 } else if (p === 24) {
3071 // not underlined
3072 flags &= ~2;
3073 } else if (p === 25) {
3074 // not blink
3075 flags &= ~4;
3076 } else if (p === 27) {
3077 // not inverse
3078 flags &= ~8;
3079 } else if (p === 28) {
3080 // not invisible
3081 flags &= ~16;
3082 } else if (p === 39) {
3083 // reset fg
3084 fg = (this.defAttr >> 9) & 0x1ff;
3085 } else if (p === 49) {
3086 // reset bg
3087 bg = this.defAttr & 0x1ff;
3088 } else if (p === 38) {
3089 // fg color 256
3090 if (params[i + 1] === 2) {
3091 i += 2;
3092 fg = matchColor(
3093 params[i] & 0xff,
3094 params[i + 1] & 0xff,
3095 params[i + 2] & 0xff);
3096 if (fg === -1) fg = 0x1ff;
3097 i += 2;
3098 } else if (params[i + 1] === 5) {
3099 i += 2;
3100 p = params[i] & 0xff;
3101 fg = p;
3102 }
3103 } else if (p === 48) {
3104 // bg color 256
3105 if (params[i + 1] === 2) {
3106 i += 2;
3107 bg = matchColor(
3108 params[i] & 0xff,
3109 params[i + 1] & 0xff,
3110 params[i + 2] & 0xff);
3111 if (bg === -1) bg = 0x1ff;
3112 i += 2;
3113 } else if (params[i + 1] === 5) {
3114 i += 2;
3115 p = params[i] & 0xff;
3116 bg = p;
3117 }
3118 } else if (p === 100) {
3119 // reset fg/bg
3120 fg = (this.defAttr >> 9) & 0x1ff;
3121 bg = this.defAttr & 0x1ff;
3122 } else {
3123 this.error('Unknown SGR attribute: %d.', p);
3124 }
3125 }
3126
3127 this.curAttr = (flags << 18) | (fg << 9) | bg;
3128 };
3129
3130 // CSI Ps n Device Status Report (DSR).
3131 // Ps = 5 -> Status Report. Result (``OK'') is
3132 // CSI 0 n
3133 // Ps = 6 -> Report Cursor Position (CPR) [row;column].
3134 // Result is
3135 // CSI r ; c R
3136 // CSI ? Ps n
3137 // Device Status Report (DSR, DEC-specific).
3138 // Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
3139 // ? r ; c R (assumes page is zero).
3140 // Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
3141 // or CSI ? 1 1 n (not ready).
3142 // Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
3143 // or CSI ? 2 1 n (locked).
3144 // Ps = 2 6 -> Report Keyboard status as
3145 // CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
3146 // The last two parameters apply to VT400 & up, and denote key-
3147 // board ready and LK01 respectively.
3148 // Ps = 5 3 -> Report Locator status as
3149 // CSI ? 5 3 n Locator available, if compiled-in, or
3150 // CSI ? 5 0 n No Locator, if not.
3151 Terminal.prototype.deviceStatus = function(params) {
3152 if (!this.prefix) {
3153 switch (params[0]) {
3154 case 5:
3155 // status report
3156 this.send('\x1b[0n');
3157 break;
3158 case 6:
3159 // cursor position
3160 this.send('\x1b['
3161 + (this.y + 1)
3162 + ';'
3163 + (this.x + 1)
3164 + 'R');
3165 break;
3166 }
3167 } else if (this.prefix === '?') {
3168 // modern xterm doesnt seem to
3169 // respond to any of these except ?6, 6, and 5
3170 switch (params[0]) {
3171 case 6:
3172 // cursor position
3173 this.send('\x1b[?'
3174 + (this.y + 1)
3175 + ';'
3176 + (this.x + 1)
3177 + 'R');
3178 break;
3179 case 15:
3180 // no printer
3181 // this.send('\x1b[?11n');
3182 break;
3183 case 25:
3184 // dont support user defined keys
3185 // this.send('\x1b[?21n');
3186 break;
3187 case 26:
3188 // north american keyboard
3189 // this.send('\x1b[?27;1;0;0n');
3190 break;
3191 case 53:
3192 // no dec locator/mouse
3193 // this.send('\x1b[?50n');
3194 break;
3195 }
3196 }
3197 };
3198
3199 /**
3200 * Additions
3201 */
3202
3203 // CSI Ps @
3204 // Insert Ps (Blank) Character(s) (default = 1) (ICH).
3205 Terminal.prototype.insertChars = function(params) {
3206 var param, row, j, ch;
3207
3208 param = params[0];
3209 if (param < 1) param = 1;
3210
3211 row = this.y + this.ybase;
3212 j = this.x;
3213 ch = [this.eraseAttr(), ' ']; // xterm
3214
3215 while (param-- && j < this.cols) {
3216 this.lines[row].splice(j++, 0, ch);
3217 this.lines[row].pop();
3218 }
3219 };
3220
3221 // CSI Ps E
3222 // Cursor Next Line Ps Times (default = 1) (CNL).
3223 // same as CSI Ps B ?
3224 Terminal.prototype.cursorNextLine = function(params) {
3225 var param = params[0];
3226 if (param < 1) param = 1;
3227 this.y += param;
3228 if (this.y >= this.rows) {
3229 this.y = this.rows - 1;
3230 }
3231 this.x = 0;
3232 };
3233
3234 // CSI Ps F
3235 // Cursor Preceding Line Ps Times (default = 1) (CNL).
3236 // reuse CSI Ps A ?
3237 Terminal.prototype.cursorPrecedingLine = function(params) {
3238 var param = params[0];
3239 if (param < 1) param = 1;
3240 this.y -= param;
3241 if (this.y < 0) this.y = 0;
3242 this.x = 0;
3243 };
3244
3245 // CSI Ps G
3246 // Cursor Character Absolute [column] (default = [row,1]) (CHA).
3247 Terminal.prototype.cursorCharAbsolute = function(params) {
3248 var param = params[0];
3249 if (param < 1) param = 1;
3250 this.x = param - 1;
3251 };
3252
3253 // CSI Ps L
3254 // Insert Ps Line(s) (default = 1) (IL).
3255 Terminal.prototype.insertLines = function(params) {
3256 var param, row, j;
3257
3258 param = params[0];
3259 if (param < 1) param = 1;
3260 row = this.y + this.ybase;
3261
3262 j = this.rows - 1 - this.scrollBottom;
3263 j = this.rows - 1 + this.ybase - j + 1;
3264
3265 while (param--) {
3266 // test: echo -e '\e[44m\e[1L\e[0m'
3267 // blankLine(true) - xterm/linux behavior
3268 this.lines.splice(row, 0, this.blankLine(true));
3269 this.lines.splice(j, 1);
3270 }
3271
3272 // this.maxRange();
3273 this.updateRange(this.y);
3274 this.updateRange(this.scrollBottom);
3275 };
3276
3277 // CSI Ps M
3278 // Delete Ps Line(s) (default = 1) (DL).
3279 Terminal.prototype.deleteLines = function(params) {
3280 var param, row, j;
3281
3282 param = params[0];
3283 if (param < 1) param = 1;
3284 row = this.y + this.ybase;
3285
3286 j = this.rows - 1 - this.scrollBottom;
3287 j = this.rows - 1 + this.ybase - j;
3288
3289 while (param--) {
3290 // test: echo -e '\e[44m\e[1M\e[0m'
3291 // blankLine(true) - xterm/linux behavior
3292 this.lines.splice(j + 1, 0, this.blankLine(true));
3293 this.lines.splice(row, 1);
3294 }
3295
3296 // this.maxRange();
3297 this.updateRange(this.y);
3298 this.updateRange(this.scrollBottom);
3299 };
3300
3301 // CSI Ps P
3302 // Delete Ps Character(s) (default = 1) (DCH).
3303 Terminal.prototype.deleteChars = function(params) {
3304 var param, row, ch;
3305
3306 param = params[0];
3307 if (param < 1) param = 1;
3308
3309 row = this.y + this.ybase;
3310 ch = [this.eraseAttr(), ' ']; // xterm
3311
3312 while (param--) {
3313 this.lines[row].splice(this.x, 1);
3314 this.lines[row].push(ch);
3315 }
3316 };
3317
3318 // CSI Ps X
3319 // Erase Ps Character(s) (default = 1) (ECH).
3320 Terminal.prototype.eraseChars = function(params) {
3321 var param, row, j, ch;
3322
3323 param = params[0];
3324 if (param < 1) param = 1;
3325
3326 row = this.y + this.ybase;
3327 j = this.x;
3328 ch = [this.eraseAttr(), ' ']; // xterm
3329
3330 while (param-- && j < this.cols) {
3331 this.lines[row][j++] = ch;
3332 }
3333 };
3334
3335 // CSI Pm ` Character Position Absolute
3336 // [column] (default = [row,1]) (HPA).
3337 Terminal.prototype.charPosAbsolute = function(params) {
3338 var param = params[0];
3339 if (param < 1) param = 1;
3340 this.x = param - 1;
3341 if (this.x >= this.cols) {
3342 this.x = this.cols - 1;
3343 }
3344 };
3345
3346 // 141 61 a * HPR -
3347 // Horizontal Position Relative
3348 // reuse CSI Ps C ?
3349 Terminal.prototype.HPositionRelative = function(params) {
3350 var param = params[0];
3351 if (param < 1) param = 1;
3352 this.x += param;
3353 if (this.x >= this.cols) {
3354 this.x = this.cols - 1;
3355 }
3356 };
3357
3358 // CSI Ps c Send Device Attributes (Primary DA).
3359 // Ps = 0 or omitted -> request attributes from terminal. The
3360 // response depends on the decTerminalID resource setting.
3361 // -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'')
3362 // -> CSI ? 1 ; 0 c (``VT101 with No Options'')
3363 // -> CSI ? 6 c (``VT102'')
3364 // -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'')
3365 // The VT100-style response parameters do not mean anything by
3366 // themselves. VT220 parameters do, telling the host what fea-
3367 // tures the terminal supports:
3368 // Ps = 1 -> 132-columns.
3369 // Ps = 2 -> Printer.
3370 // Ps = 6 -> Selective erase.
3371 // Ps = 8 -> User-defined keys.
3372 // Ps = 9 -> National replacement character sets.
3373 // Ps = 1 5 -> Technical characters.
3374 // Ps = 2 2 -> ANSI color, e.g., VT525.
3375 // Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode).
3376 // CSI > Ps c
3377 // Send Device Attributes (Secondary DA).
3378 // Ps = 0 or omitted -> request the terminal's identification
3379 // code. The response depends on the decTerminalID resource set-
3380 // ting. It should apply only to VT220 and up, but xterm extends
3381 // this to VT100.
3382 // -> CSI > Pp ; Pv ; Pc c
3383 // where Pp denotes the terminal type
3384 // Pp = 0 -> ``VT100''.
3385 // Pp = 1 -> ``VT220''.
3386 // and Pv is the firmware version (for xterm, this was originally
3387 // the XFree86 patch number, starting with 95). In a DEC termi-
3388 // nal, Pc indicates the ROM cartridge registration number and is
3389 // always zero.
3390 // More information:
3391 // xterm/charproc.c - line 2012, for more information.
3392 // vim responds with ^[[?0c or ^[[?1c after the terminal's response (?)
3393 Terminal.prototype.sendDeviceAttributes = function(params) {
3394 if (params[0] > 0) return;
3395
3396 if (!this.prefix) {
3397 if (this.is('xterm')
3398 || this.is('rxvt-unicode')
3399 || this.is('screen')) {
3400 this.send('\x1b[?1;2c');
3401 } else if (this.is('linux')) {
3402 this.send('\x1b[?6c');
3403 }
3404 } else if (this.prefix === '>') {
3405 // xterm and urxvt
3406 // seem to spit this
3407 // out around ~370 times (?).
3408 if (this.is('xterm')) {
3409 this.send('\x1b[>0;276;0c');
3410 } else if (this.is('rxvt-unicode')) {
3411 this.send('\x1b[>85;95;0c');
3412 } else if (this.is('linux')) {
3413 // not supported by linux console.
3414 // linux console echoes parameters.
3415 this.send(params[0] + 'c');
3416 } else if (this.is('screen')) {
3417 this.send('\x1b[>83;40003;0c');
3418 }
3419 }
3420 };
3421
3422 // CSI Pm d
3423 // Line Position Absolute [row] (default = [1,column]) (VPA).
3424 Terminal.prototype.linePosAbsolute = function(params) {
3425 var param = params[0];
3426 if (param < 1) param = 1;
3427 this.y = param - 1;
3428 if (this.y >= this.rows) {
3429 this.y = this.rows - 1;
3430 }
3431 };
3432
3433 // 145 65 e * VPR - Vertical Position Relative
3434 // reuse CSI Ps B ?
3435 Terminal.prototype.VPositionRelative = function(params) {
3436 var param = params[0];
3437 if (param < 1) param = 1;
3438 this.y += param;
3439 if (this.y >= this.rows) {
3440 this.y = this.rows - 1;
3441 }
3442 };
3443
3444 // CSI Ps ; Ps f
3445 // Horizontal and Vertical Position [row;column] (default =
3446 // [1,1]) (HVP).
3447 Terminal.prototype.HVPosition = function(params) {
3448 if (params[0] < 1) params[0] = 1;
3449 if (params[1] < 1) params[1] = 1;
3450
3451 this.y = params[0] - 1;
3452 if (this.y >= this.rows) {
3453 this.y = this.rows - 1;
3454 }
3455
3456 this.x = params[1] - 1;
3457 if (this.x >= this.cols) {
3458 this.x = this.cols - 1;
3459 }
3460 };
3461
3462 // CSI Pm h Set Mode (SM).
3463 // Ps = 2 -> Keyboard Action Mode (AM).
3464 // Ps = 4 -> Insert Mode (IRM).
3465 // Ps = 1 2 -> Send/receive (SRM).
3466 // Ps = 2 0 -> Automatic Newline (LNM).
3467 // CSI ? Pm h
3468 // DEC Private Mode Set (DECSET).
3469 // Ps = 1 -> Application Cursor Keys (DECCKM).
3470 // Ps = 2 -> Designate USASCII for character sets G0-G3
3471 // (DECANM), and set VT100 mode.
3472 // Ps = 3 -> 132 Column Mode (DECCOLM).
3473 // Ps = 4 -> Smooth (Slow) Scroll (DECSCLM).
3474 // Ps = 5 -> Reverse Video (DECSCNM).
3475 // Ps = 6 -> Origin Mode (DECOM).
3476 // Ps = 7 -> Wraparound Mode (DECAWM).
3477 // Ps = 8 -> Auto-repeat Keys (DECARM).
3478 // Ps = 9 -> Send Mouse X & Y on button press. See the sec-
3479 // tion Mouse Tracking.
3480 // Ps = 1 0 -> Show toolbar (rxvt).
3481 // Ps = 1 2 -> Start Blinking Cursor (att610).
3482 // Ps = 1 8 -> Print form feed (DECPFF).
3483 // Ps = 1 9 -> Set print extent to full screen (DECPEX).
3484 // Ps = 2 5 -> Show Cursor (DECTCEM).
3485 // Ps = 3 0 -> Show scrollbar (rxvt).
3486 // Ps = 3 5 -> Enable font-shifting functions (rxvt).
3487 // Ps = 3 8 -> Enter Tektronix Mode (DECTEK).
3488 // Ps = 4 0 -> Allow 80 -> 132 Mode.
3489 // Ps = 4 1 -> more(1) fix (see curses resource).
3490 // Ps = 4 2 -> Enable Nation Replacement Character sets (DECN-
3491 // RCM).
3492 // Ps = 4 4 -> Turn On Margin Bell.
3493 // Ps = 4 5 -> Reverse-wraparound Mode.
3494 // Ps = 4 6 -> Start Logging. This is normally disabled by a
3495 // compile-time option.
3496 // Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis-
3497 // abled by the titeInhibit resource).
3498 // Ps = 6 6 -> Application keypad (DECNKM).
3499 // Ps = 6 7 -> Backarrow key sends backspace (DECBKM).
3500 // Ps = 1 0 0 0 -> Send Mouse X & Y on button press and
3501 // release. See the section Mouse Tracking.
3502 // Ps = 1 0 0 1 -> Use Hilite Mouse Tracking.
3503 // Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking.
3504 // Ps = 1 0 0 3 -> Use All Motion Mouse Tracking.
3505 // Ps = 1 0 0 4 -> Send FocusIn/FocusOut events.
3506 // Ps = 1 0 0 5 -> Enable Extended Mouse Mode.
3507 // Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt).
3508 // Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt).
3509 // Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
3510 // (enables the eightBitInput resource).
3511 // Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num-
3512 // Lock keys. (This enables the numLock resource).
3513 // Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This
3514 // enables the metaSendsEscape resource).
3515 // Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete
3516 // key.
3517 // Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This
3518 // enables the altSendsEscape resource).
3519 // Ps = 1 0 4 0 -> Keep selection even if not highlighted.
3520 // (This enables the keepSelection resource).
3521 // Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables
3522 // the selectToClipboard resource).
3523 // Ps = 1 0 4 2 -> Enable Urgency window manager hint when
3524 // Control-G is received. (This enables the bellIsUrgent
3525 // resource).
3526 // Ps = 1 0 4 3 -> Enable raising of the window when Control-G
3527 // is received. (enables the popOnBell resource).
3528 // Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be
3529 // disabled by the titeInhibit resource).
3530 // Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis-
3531 // abled by the titeInhibit resource).
3532 // Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate
3533 // Screen Buffer, clearing it first. (This may be disabled by
3534 // the titeInhibit resource). This combines the effects of the 1
3535 // 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based
3536 // applications rather than the 4 7 mode.
3537 // Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode.
3538 // Ps = 1 0 5 1 -> Set Sun function-key mode.
3539 // Ps = 1 0 5 2 -> Set HP function-key mode.
3540 // Ps = 1 0 5 3 -> Set SCO function-key mode.
3541 // Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6).
3542 // Ps = 1 0 6 1 -> Set VT220 keyboard emulation.
3543 // Ps = 2 0 0 4 -> Set bracketed paste mode.
3544 // Modes:
3545 // http://vt100.net/docs/vt220-rm/chapter4.html
3546 Terminal.prototype.setMode = function(params) {
3547 if (typeof params === 'object') {
3548 var l = params.length
3549 , i = 0;
3550
3551 for (; i < l; i++) {
3552 this.setMode(params[i]);
3553 }
3554
3555 return;
3556 }
3557
3558 if (!this.prefix) {
3559 switch (params) {
3560 case 4:
3561 this.insertMode = true;
3562 break;
3563 case 20:
3564 //this.convertEol = true;
3565 break;
3566 }
3567 } else if (this.prefix === '?') {
3568 switch (params) {
3569 case 1:
3570 this.applicationCursor = true;
3571 break;
3572 case 2:
3573 this.setgCharset(0, Terminal.charsets.US);
3574 this.setgCharset(1, Terminal.charsets.US);
3575 this.setgCharset(2, Terminal.charsets.US);
3576 this.setgCharset(3, Terminal.charsets.US);
3577 // set VT100 mode here
3578 break;
3579 case 3: // 132 col mode
3580 this.savedCols = this.cols;
3581 this.resize(132, this.rows);
3582 break;
3583 case 6:
3584 this.originMode = true;
3585 break;
3586 case 7:
3587 this.wraparoundMode = true;
3588 break;
3589 case 12:
3590 // this.cursorBlink = true;
3591 break;
3592 case 66:
3593 this.log('Serial port requested application keypad.');
3594 this.applicationKeypad = true;
3595 break;
3596 case 9: // X10 Mouse
3597 // no release, no motion, no wheel, no modifiers.
3598 case 1000: // vt200 mouse
3599 // no motion.
3600 // no modifiers, except control on the wheel.
3601 case 1002: // button event mouse
3602 case 1003: // any event mouse
3603 // any event - sends motion events,
3604 // even if there is no button held down.
3605 this.x10Mouse = params === 9;
3606 this.vt200Mouse = params === 1000;
3607 this.normalMouse = params > 1000;
3608 this.mouseEvents = true;
3609 this.element.style.cursor = 'default';
3610 this.log('Binding to mouse events.');
3611 break;
3612 case 1004: // send focusin/focusout events
3613 // focusin: ^[[I
3614 // focusout: ^[[O
3615 this.sendFocus = true;
3616 break;
3617 case 1005: // utf8 ext mode mouse
3618 this.utfMouse = true;
3619 // for wide terminals
3620 // simply encodes large values as utf8 characters
3621 break;
3622 case 1006: // sgr ext mode mouse
3623 this.sgrMouse = true;
3624 // for wide terminals
3625 // does not add 32 to fields
3626 // press: ^[[<b;x;yM
3627 // release: ^[[<b;x;ym
3628 break;
3629 case 1015: // urxvt ext mode mouse
3630 this.urxvtMouse = true;
3631 // for wide terminals
3632 // numbers for fields
3633 // press: ^[[b;x;yM
3634 // motion: ^[[b;x;yT
3635 break;
3636 case 25: // show cursor
3637 this.cursorHidden = false;
3638 break;
3639 case 1049: // alt screen buffer cursor
3640 //this.saveCursor();
3641 ; // FALL-THROUGH
3642 case 47: // alt screen buffer
3643 case 1047: // alt screen buffer
3644 if (!this.normal) {
3645 var normal = {
3646 lines: this.lines,
3647 ybase: this.ybase,
3648 ydisp: this.ydisp,
3649 x: this.x,
3650 y: this.y,
3651 scrollTop: this.scrollTop,
3652 scrollBottom: this.scrollBottom,
3653 tabs: this.tabs
3654 // XXX save charset(s) here?
3655 // charset: this.charset,
3656 // glevel: this.glevel,
3657 // charsets: this.charsets
3658 };
3659 this.reset();
3660 this.normal = normal;
3661 this.showCursor();
3662 }
3663 break;
3664 }
3665 }
3666 };
3667
3668 // CSI Pm l Reset Mode (RM).
3669 // Ps = 2 -> Keyboard Action Mode (AM).
3670 // Ps = 4 -> Replace Mode (IRM).
3671 // Ps = 1 2 -> Send/receive (SRM).
3672 // Ps = 2 0 -> Normal Linefeed (LNM).
3673 // CSI ? Pm l
3674 // DEC Private Mode Reset (DECRST).
3675 // Ps = 1 -> Normal Cursor Keys (DECCKM).
3676 // Ps = 2 -> Designate VT52 mode (DECANM).
3677 // Ps = 3 -> 80 Column Mode (DECCOLM).
3678 // Ps = 4 -> Jump (Fast) Scroll (DECSCLM).
3679 // Ps = 5 -> Normal Video (DECSCNM).
3680 // Ps = 6 -> Normal Cursor Mode (DECOM).
3681 // Ps = 7 -> No Wraparound Mode (DECAWM).
3682 // Ps = 8 -> No Auto-repeat Keys (DECARM).
3683 // Ps = 9 -> Don't send Mouse X & Y on button press.
3684 // Ps = 1 0 -> Hide toolbar (rxvt).
3685 // Ps = 1 2 -> Stop Blinking Cursor (att610).
3686 // Ps = 1 8 -> Don't print form feed (DECPFF).
3687 // Ps = 1 9 -> Limit print to scrolling region (DECPEX).
3688 // Ps = 2 5 -> Hide Cursor (DECTCEM).
3689 // Ps = 3 0 -> Don't show scrollbar (rxvt).
3690 // Ps = 3 5 -> Disable font-shifting functions (rxvt).
3691 // Ps = 4 0 -> Disallow 80 -> 132 Mode.
3692 // Ps = 4 1 -> No more(1) fix (see curses resource).
3693 // Ps = 4 2 -> Disable Nation Replacement Character sets (DEC-
3694 // NRCM).
3695 // Ps = 4 4 -> Turn Off Margin Bell.
3696 // Ps = 4 5 -> No Reverse-wraparound Mode.
3697 // Ps = 4 6 -> Stop Logging. (This is normally disabled by a
3698 // compile-time option).
3699 // Ps = 4 7 -> Use Normal Screen Buffer.
3700 // Ps = 6 6 -> Numeric keypad (DECNKM).
3701 // Ps = 6 7 -> Backarrow key sends delete (DECBKM).
3702 // Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and
3703 // release. See the section Mouse Tracking.
3704 // Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking.
3705 // Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking.
3706 // Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking.
3707 // Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events.
3708 // Ps = 1 0 0 5 -> Disable Extended Mouse Mode.
3709 // Ps = 1 0 1 0 -> Don't scroll to bottom on tty output
3710 // (rxvt).
3711 // Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt).
3712 // Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables
3713 // the eightBitInput resource).
3714 // Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num-
3715 // Lock keys. (This disables the numLock resource).
3716 // Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key.
3717 // (This disables the metaSendsEscape resource).
3718 // Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad
3719 // Delete key.
3720 // Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key.
3721 // (This disables the altSendsEscape resource).
3722 // Ps = 1 0 4 0 -> Do not keep selection when not highlighted.
3723 // (This disables the keepSelection resource).
3724 // Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables
3725 // the selectToClipboard resource).
3726 // Ps = 1 0 4 2 -> Disable Urgency window manager hint when
3727 // Control-G is received. (This disables the bellIsUrgent
3728 // resource).
3729 // Ps = 1 0 4 3 -> Disable raising of the window when Control-
3730 // G is received. (This disables the popOnBell resource).
3731 // Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen
3732 // first if in the Alternate Screen. (This may be disabled by
3733 // the titeInhibit resource).
3734 // Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be
3735 // disabled by the titeInhibit resource).
3736 // Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor
3737 // as in DECRC. (This may be disabled by the titeInhibit
3738 // resource). This combines the effects of the 1 0 4 7 and 1 0
3739 // 4 8 modes. Use this with terminfo-based applications rather
3740 // than the 4 7 mode.
3741 // Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode.
3742 // Ps = 1 0 5 1 -> Reset Sun function-key mode.
3743 // Ps = 1 0 5 2 -> Reset HP function-key mode.
3744 // Ps = 1 0 5 3 -> Reset SCO function-key mode.
3745 // Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6).
3746 // Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style.
3747 // Ps = 2 0 0 4 -> Reset bracketed paste mode.
3748 Terminal.prototype.resetMode = function(params) {
3749 if (typeof params === 'object') {
3750 var l = params.length
3751 , i = 0;
3752
3753 for (; i < l; i++) {
3754 this.resetMode(params[i]);
3755 }
3756
3757 return;
3758 }
3759
3760 if (!this.prefix) {
3761 switch (params) {
3762 case 4:
3763 this.insertMode = false;
3764 break;
3765 case 20:
3766 //this.convertEol = false;
3767 break;
3768 }
3769 } else if (this.prefix === '?') {
3770 switch (params) {
3771 case 1:
3772 this.applicationCursor = false;
3773 break;
3774 case 3:
3775 if (this.cols === 132 && this.savedCols) {
3776 this.resize(this.savedCols, this.rows);
3777 }
3778 delete this.savedCols;
3779 break;
3780 case 6:
3781 this.originMode = false;
3782 break;
3783 case 7:
3784 this.wraparoundMode = false;
3785 break;
3786 case 12:
3787 // this.cursorBlink = false;
3788 break;
3789 case 66:
3790 this.log('Switching back to normal keypad.');
3791 this.applicationKeypad = false;
3792 break;
3793 case 9: // X10 Mouse
3794 case 1000: // vt200 mouse
3795 case 1002: // button event mouse
3796 case 1003: // any event mouse
3797 this.x10Mouse = false;
3798 this.vt200Mouse = false;
3799 this.normalMouse = false;
3800 this.mouseEvents = false;
3801 this.element.style.cursor = '';
3802 break;
3803 case 1004: // send focusin/focusout events
3804 this.sendFocus = false;
3805 break;
3806 case 1005: // utf8 ext mode mouse
3807 this.utfMouse = false;
3808 break;
3809 case 1006: // sgr ext mode mouse
3810 this.sgrMouse = false;
3811 break;
3812 case 1015: // urxvt ext mode mouse
3813 this.urxvtMouse = false;
3814 break;
3815 case 25: // hide cursor
3816 this.cursorHidden = true;
3817 break;
3818 case 1049: // alt screen buffer cursor
3819 ; // FALL-THROUGH
3820 case 47: // normal screen buffer
3821 case 1047: // normal screen buffer - clearing it first
3822 if (this.normal) {
3823 this.lines = this.normal.lines;
3824 this.ybase = this.normal.ybase;
3825 this.ydisp = this.normal.ydisp;
3826 this.x = this.normal.x;
3827 this.y = this.normal.y;
3828 this.scrollTop = this.normal.scrollTop;
3829 this.scrollBottom = this.normal.scrollBottom;
3830 this.tabs = this.normal.tabs;
3831 this.normal = null;
3832 // if (params === 1049) {
3833 // this.x = this.savedX;
3834 // this.y = this.savedY;
3835 // }
3836 this.refresh(0, this.rows - 1);
3837 this.showCursor();
3838 }
3839 break;
3840 }
3841 }
3842 };
3843
3844 // CSI Ps ; Ps r
3845 // Set Scrolling Region [top;bottom] (default = full size of win-
3846 // dow) (DECSTBM).
3847 // CSI ? Pm r
3848 Terminal.prototype.setScrollRegion = function(params) {
3849 if (this.prefix) return;
3850 this.scrollTop = (params[0] || 1) - 1;
3851 this.scrollBottom = (params[1] || this.rows) - 1;
3852 this.x = 0;
3853 this.y = 0;
3854 };
3855
3856 // CSI s
3857 // Save cursor (ANSI.SYS).
3858 Terminal.prototype.saveCursor = function(params) {
3859 this.savedX = this.x;
3860 this.savedY = this.y;
3861 };
3862
3863 // CSI u
3864 // Restore cursor (ANSI.SYS).
3865 Terminal.prototype.restoreCursor = function(params) {
3866 this.x = this.savedX || 0;
3867 this.y = this.savedY || 0;
3868 };
3869
3870 /**
3871 * Lesser Used
3872 */
3873
3874 // CSI Ps I
3875 // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
3876 Terminal.prototype.cursorForwardTab = function(params) {
3877 var param = params[0] || 1;
3878 while (param--) {
3879 this.x = this.nextStop();
3880 }
3881 };
3882
3883 // CSI Ps S Scroll up Ps lines (default = 1) (SU).
3884 Terminal.prototype.scrollUp = function(params) {
3885 var param = params[0] || 1;
3886 while (param--) {
3887 this.lines.splice(this.ybase + this.scrollTop, 1);
3888 this.lines.splice(this.ybase + this.scrollBottom, 0, this.blankLine());
3889 }
3890 // this.maxRange();
3891 this.updateRange(this.scrollTop);
3892 this.updateRange(this.scrollBottom);
3893 };
3894
3895 // CSI Ps T Scroll down Ps lines (default = 1) (SD).
3896 Terminal.prototype.scrollDown = function(params) {
3897 var param = params[0] || 1;
3898 while (param--) {
3899 this.lines.splice(this.ybase + this.scrollBottom, 1);
3900 this.lines.splice(this.ybase + this.scrollTop, 0, this.blankLine());
3901 }
3902 // this.maxRange();
3903 this.updateRange(this.scrollTop);
3904 this.updateRange(this.scrollBottom);
3905 };
3906
3907 // CSI Ps ; Ps ; Ps ; Ps ; Ps T
3908 // Initiate highlight mouse tracking. Parameters are
3909 // [func;startx;starty;firstrow;lastrow]. See the section Mouse
3910 // Tracking.
3911 Terminal.prototype.initMouseTracking = function(params) {
3912 // Relevant: DECSET 1001
3913 };
3914
3915 // CSI > Ps; Ps T
3916 // Reset one or more features of the title modes to the default
3917 // value. Normally, "reset" disables the feature. It is possi-
3918 // ble to disable the ability to reset features by compiling a
3919 // different default for the title modes into xterm.
3920 // Ps = 0 -> Do not set window/icon labels using hexadecimal.
3921 // Ps = 1 -> Do not query window/icon labels using hexadeci-
3922 // mal.
3923 // Ps = 2 -> Do not set window/icon labels using UTF-8.
3924 // Ps = 3 -> Do not query window/icon labels using UTF-8.
3925 // (See discussion of "Title Modes").
3926 Terminal.prototype.resetTitleModes = function(params) {
3927 ;
3928 };
3929
3930 // CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
3931 Terminal.prototype.cursorBackwardTab = function(params) {
3932 var param = params[0] || 1;
3933 while (param--) {
3934 this.x = this.prevStop();
3935 }
3936 };
3937
3938 // CSI Ps b Repeat the preceding graphic character Ps times (REP).
3939 Terminal.prototype.repeatPrecedingCharacter = function(params) {
3940 var param = params[0] || 1
3941 , line = this.lines[this.ybase + this.y]
3942 , ch = line[this.x - 1] || [this.defAttr, ' '];
3943
3944 while (param--) line[this.x++] = ch;
3945 };
3946
3947 // CSI Ps g Tab Clear (TBC).
3948 // Ps = 0 -> Clear Current Column (default).
3949 // Ps = 3 -> Clear All.
3950 // Potentially:
3951 // Ps = 2 -> Clear Stops on Line.
3952 // http://vt100.net/annarbor/aaa-ug/section6.html
3953 Terminal.prototype.tabClear = function(params) {
3954 var param = params[0];
3955 if (param <= 0) {
3956 delete this.tabs[this.x];
3957 } else if (param === 3) {
3958 this.tabs = {};
3959 }
3960 };
3961
3962 // CSI Pm i Media Copy (MC).
3963 // Ps = 0 -> Print screen (default).
3964 // Ps = 4 -> Turn off printer controller mode.
3965 // Ps = 5 -> Turn on printer controller mode.
3966 // CSI ? Pm i
3967 // Media Copy (MC, DEC-specific).
3968 // Ps = 1 -> Print line containing cursor.
3969 // Ps = 4 -> Turn off autoprint mode.
3970 // Ps = 5 -> Turn on autoprint mode.
3971 // Ps = 1 0 -> Print composed display, ignores DECPEX.
3972 // Ps = 1 1 -> Print all pages.
3973 Terminal.prototype.mediaCopy = function(params) {
3974 ;
3975 };
3976
3977 // CSI > Ps; Ps m
3978 // Set or reset resource-values used by xterm to decide whether
3979 // to construct escape sequences holding information about the
3980 // modifiers pressed with a given key. The first parameter iden-
3981 // tifies the resource to set/reset. The second parameter is the
3982 // value to assign to the resource. If the second parameter is
3983 // omitted, the resource is reset to its initial value.
3984 // Ps = 1 -> modifyCursorKeys.
3985 // Ps = 2 -> modifyFunctionKeys.
3986 // Ps = 4 -> modifyOtherKeys.
3987 // If no parameters are given, all resources are reset to their
3988 // initial values.
3989 Terminal.prototype.setResources = function(params) {
3990 ;
3991 };
3992
3993 // CSI > Ps n
3994 // Disable modifiers which may be enabled via the CSI > Ps; Ps m
3995 // sequence. This corresponds to a resource value of "-1", which
3996 // cannot be set with the other sequence. The parameter identi-
3997 // fies the resource to be disabled:
3998 // Ps = 1 -> modifyCursorKeys.
3999 // Ps = 2 -> modifyFunctionKeys.
4000 // Ps = 4 -> modifyOtherKeys.
4001 // If the parameter is omitted, modifyFunctionKeys is disabled.
4002 // When modifyFunctionKeys is disabled, xterm uses the modifier
4003 // keys to make an extended sequence of functions rather than
4004 // adding a parameter to each function key to denote the modi-
4005 // fiers.
4006 Terminal.prototype.disableModifiers = function(params) {
4007 ;
4008 };
4009
4010 // CSI > Ps p
4011 // Set resource value pointerMode. This is used by xterm to
4012 // decide whether to hide the pointer cursor as the user types.
4013 // Valid values for the parameter:
4014 // Ps = 0 -> never hide the pointer.
4015 // Ps = 1 -> hide if the mouse tracking mode is not enabled.
4016 // Ps = 2 -> always hide the pointer. If no parameter is
4017 // given, xterm uses the default, which is 1 .
4018 Terminal.prototype.setPointerMode = function(params) {
4019 ;
4020 };
4021
4022 // CSI ! p Soft terminal reset (DECSTR).
4023 // http://vt100.net/docs/vt220-rm/table4-10.html
4024 Terminal.prototype.softReset = function(params) {
4025 this.cursorHidden = false;
4026 this.insertMode = false;
4027 this.originMode = false;
4028 this.wraparoundMode = false; // autowrap
4029 this.applicationKeypad = false; // ?
4030 this.applicationCursor = false;
4031 this.scrollTop = 0;
4032 this.scrollBottom = this.rows - 1;
4033 this.curAttr = this.defAttr;
4034 this.x = this.y = 0; // ?
4035 this.charset = null;
4036 this.glevel = 0; // ??
4037 this.charsets = [null]; // ??
4038 };
4039
4040 // CSI Ps$ p
4041 // Request ANSI mode (DECRQM). For VT300 and up, reply is
4042 // CSI Ps; Pm$ y
4043 // where Ps is the mode number as in RM, and Pm is the mode
4044 // value:
4045 // 0 - not recognized
4046 // 1 - set
4047 // 2 - reset
4048 // 3 - permanently set
4049 // 4 - permanently reset
4050 Terminal.prototype.requestAnsiMode = function(params) {
4051 ;
4052 };
4053
4054 // CSI ? Ps$ p
4055 // Request DEC private mode (DECRQM). For VT300 and up, reply is
4056 // CSI ? Ps; Pm$ p
4057 // where Ps is the mode number as in DECSET, Pm is the mode value
4058 // as in the ANSI DECRQM.
4059 Terminal.prototype.requestPrivateMode = function(params) {
4060 ;
4061 };
4062
4063 // CSI Ps ; Ps " p
4064 // Set conformance level (DECSCL). Valid values for the first
4065 // parameter:
4066 // Ps = 6 1 -> VT100.
4067 // Ps = 6 2 -> VT200.
4068 // Ps = 6 3 -> VT300.
4069 // Valid values for the second parameter:
4070 // Ps = 0 -> 8-bit controls.
4071 // Ps = 1 -> 7-bit controls (always set for VT100).
4072 // Ps = 2 -> 8-bit controls.
4073 Terminal.prototype.setConformanceLevel = function(params) {
4074 ;
4075 };
4076
4077 // CSI Ps q Load LEDs (DECLL).
4078 // Ps = 0 -> Clear all LEDS (default).
4079 // Ps = 1 -> Light Num Lock.
4080 // Ps = 2 -> Light Caps Lock.
4081 // Ps = 3 -> Light Scroll Lock.
4082 // Ps = 2 1 -> Extinguish Num Lock.
4083 // Ps = 2 2 -> Extinguish Caps Lock.
4084 // Ps = 2 3 -> Extinguish Scroll Lock.
4085 Terminal.prototype.loadLEDs = function(params) {
4086 ;
4087 };
4088
4089 // CSI Ps SP q
4090 // Set cursor style (DECSCUSR, VT520).
4091 // Ps = 0 -> blinking block.
4092 // Ps = 1 -> blinking block (default).
4093 // Ps = 2 -> steady block.
4094 // Ps = 3 -> blinking underline.
4095 // Ps = 4 -> steady underline.
4096 Terminal.prototype.setCursorStyle = function(params) {
4097 ;
4098 };
4099
4100 // CSI Ps " q
4101 // Select character protection attribute (DECSCA). Valid values
4102 // for the parameter:
4103 // Ps = 0 -> DECSED and DECSEL can erase (default).
4104 // Ps = 1 -> DECSED and DECSEL cannot erase.
4105 // Ps = 2 -> DECSED and DECSEL can erase.
4106 Terminal.prototype.setCharProtectionAttr = function(params) {
4107 ;
4108 };
4109
4110 // CSI ? Pm r
4111 // Restore DEC Private Mode Values. The value of Ps previously
4112 // saved is restored. Ps values are the same as for DECSET.
4113 Terminal.prototype.restorePrivateValues = function(params) {
4114 ;
4115 };
4116
4117 // CSI Pt; Pl; Pb; Pr; Ps$ r
4118 // Change Attributes in Rectangular Area (DECCARA), VT400 and up.
4119 // Pt; Pl; Pb; Pr denotes the rectangle.
4120 // Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7.
4121 // NOTE: xterm doesn't enable this code by default.
4122 Terminal.prototype.setAttrInRectangle = function(params) {
4123 var t = params[0]
4124 , l = params[1]
4125 , b = params[2]
4126 , r = params[3]
4127 , attr = params[4];
4128
4129 var line
4130 , i;
4131
4132 for (; t < b + 1; t++) {
4133 line = this.lines[this.ybase + t];
4134 for (i = l; i < r; i++) {
4135 line[i] = [attr, line[i][1]];
4136 }
4137 }
4138
4139 // this.maxRange();
4140 this.updateRange(params[0]);
4141 this.updateRange(params[2]);
4142 };
4143
4144
4145 // CSI Pc; Pt; Pl; Pb; Pr$ x
4146 // Fill Rectangular Area (DECFRA), VT420 and up.
4147 // Pc is the character to use.
4148 // Pt; Pl; Pb; Pr denotes the rectangle.
4149 // NOTE: xterm doesn't enable this code by default.
4150 Terminal.prototype.fillRectangle = function(params) {
4151 var ch = params[0]
4152 , t = params[1]
4153 , l = params[2]
4154 , b = params[3]
4155 , r = params[4];
4156
4157 var line
4158 , i;
4159
4160 for (; t < b + 1; t++) {
4161 line = this.lines[this.ybase + t];
4162 for (i = l; i < r; i++) {
4163 line[i] = [line[i][0], String.fromCharCode(ch)];
4164 }
4165 }
4166
4167 // this.maxRange();
4168 this.updateRange(params[1]);
4169 this.updateRange(params[3]);
4170 };
4171
4172 // CSI Ps ; Pu ' z
4173 // Enable Locator Reporting (DECELR).
4174 // Valid values for the first parameter:
4175 // Ps = 0 -> Locator disabled (default).
4176 // Ps = 1 -> Locator enabled.
4177 // Ps = 2 -> Locator enabled for one report, then disabled.
4178 // The second parameter specifies the coordinate unit for locator
4179 // reports.
4180 // Valid values for the second parameter:
4181 // Pu = 0 <- or omitted -> default to character cells.
4182 // Pu = 1 <- device physical pixels.
4183 // Pu = 2 <- character cells.
4184 Terminal.prototype.enableLocatorReporting = function(params) {
4185 var val = params[0] > 0;
4186 //this.mouseEvents = val;
4187 //this.decLocator = val;
4188 };
4189
4190 // CSI Pt; Pl; Pb; Pr$ z
4191 // Erase Rectangular Area (DECERA), VT400 and up.
4192 // Pt; Pl; Pb; Pr denotes the rectangle.
4193 // NOTE: xterm doesn't enable this code by default.
4194 Terminal.prototype.eraseRectangle = function(params) {
4195 var t = params[0]
4196 , l = params[1]
4197 , b = params[2]
4198 , r = params[3];
4199
4200 var line
4201 , i
4202 , ch;
4203
4204 ch = [this.eraseAttr(), ' ']; // xterm?
4205
4206 for (; t < b + 1; t++) {
4207 line = this.lines[this.ybase + t];
4208 for (i = l; i < r; i++) {
4209 line[i] = ch;
4210 }
4211 }
4212
4213 // this.maxRange();
4214 this.updateRange(params[0]);
4215 this.updateRange(params[2]);
4216 };
8bc844c0 4217
8bc844c0 4218
3f455f90
PK
4219 // CSI P m SP }
4220 // Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
4221 // NOTE: xterm doesn't enable this code by default.
4222 Terminal.prototype.insertColumns = function() {
4223 var param = params[0]
4224 , l = this.ybase + this.rows
4225 , ch = [this.eraseAttr(), ' '] // xterm?
4226 , i;
8bc844c0 4227
3f455f90
PK
4228 while (param--) {
4229 for (i = this.ybase; i < l; i++) {
4230 this.lines[i].splice(this.x + 1, 0, ch);
4231 this.lines[i].pop();
8bc844c0 4232 }
3f455f90 4233 }
8bc844c0 4234
3f455f90
PK
4235 this.maxRange();
4236 };
8bc844c0 4237
178b611b 4238
3f455f90
PK
4239 // CSI P m SP ~
4240 // Delete P s Column(s) (default = 1) (DECDC), VT420 and up
4241 // NOTE: xterm doesn't enable this code by default.
4242 Terminal.prototype.deleteColumns = function() {
4243 var param = params[0]
4244 , l = this.ybase + this.rows
4245 , ch = [this.eraseAttr(), ' '] // xterm?
4246 , i;
4247
4248 while (param--) {
4249 for (i = this.ybase; i < l; i++) {
4250 this.lines[i].splice(this.x, 1);
4251 this.lines[i].push(ch);
4252 }
4253 }
8bc844c0 4254
3f455f90
PK
4255 this.maxRange();
4256 };
8bc844c0 4257
3f455f90
PK
4258 /**
4259 * Character Sets
4260 */
4261
4262 Terminal.charsets = {};
4263
4264 // DEC Special Character and Line Drawing Set.
4265 // http://vt100.net/docs/vt102-ug/table5-13.html
4266 // A lot of curses apps use this if they see TERM=xterm.
4267 // testing: echo -e '\e(0a\e(B'
4268 // The xterm output sometimes seems to conflict with the
4269 // reference above. xterm seems in line with the reference
4270 // when running vttest however.
4271 // The table below now uses xterm's output from vttest.
4272 Terminal.charsets.SCLD = { // (0
4273 '`': '\u25c6', // '◆'
4274 'a': '\u2592', // '▒'
4275 'b': '\u0009', // '\t'
4276 'c': '\u000c', // '\f'
4277 'd': '\u000d', // '\r'
4278 'e': '\u000a', // '\n'
4279 'f': '\u00b0', // '°'
4280 'g': '\u00b1', // '±'
4281 'h': '\u2424', // '\u2424' (NL)
4282 'i': '\u000b', // '\v'
4283 'j': '\u2518', // '┘'
4284 'k': '\u2510', // '┐'
4285 'l': '\u250c', // '┌'
4286 'm': '\u2514', // '└'
4287 'n': '\u253c', // '┼'
4288 'o': '\u23ba', // '⎺'
4289 'p': '\u23bb', // '⎻'
4290 'q': '\u2500', // '─'
4291 'r': '\u23bc', // '⎼'
4292 's': '\u23bd', // '⎽'
4293 't': '\u251c', // '├'
4294 'u': '\u2524', // '┤'
4295 'v': '\u2534', // '┴'
4296 'w': '\u252c', // '┬'
4297 'x': '\u2502', // '│'
4298 'y': '\u2264', // '≤'
4299 'z': '\u2265', // '≥'
4300 '{': '\u03c0', // 'π'
4301 '|': '\u2260', // '≠'
4302 '}': '\u00a3', // '£'
4303 '~': '\u00b7' // '·'
4304 };
4305
4306 Terminal.charsets.UK = null; // (A
4307 Terminal.charsets.US = null; // (B (USASCII)
4308 Terminal.charsets.Dutch = null; // (4
4309 Terminal.charsets.Finnish = null; // (C or (5
4310 Terminal.charsets.French = null; // (R
4311 Terminal.charsets.FrenchCanadian = null; // (Q
4312 Terminal.charsets.German = null; // (K
4313 Terminal.charsets.Italian = null; // (Y
4314 Terminal.charsets.NorwegianDanish = null; // (E or (6
4315 Terminal.charsets.Spanish = null; // (Z
4316 Terminal.charsets.Swedish = null; // (H or (7
4317 Terminal.charsets.Swiss = null; // (=
4318 Terminal.charsets.ISOLatin = null; // /A
4319
4320 /**
4321 * Helpers
4322 */
4323
4324 function on(el, type, handler, capture) {
4325 if (!Array.isArray(el)) {
4326 el = [el];
9e6cb6b6 4327 }
3f455f90
PK
4328 el.forEach(function (element) {
4329 element.addEventListener(type, handler, capture || false);
4330 });
9e6cb6b6 4331 }
8bc844c0 4332
3f455f90
PK
4333 function off(el, type, handler, capture) {
4334 el.removeEventListener(type, handler, capture || false);
5d3f8786 4335 }
3f455f90
PK
4336
4337 function cancel(ev, force) {
4338 if (!this.cancelEvents && !force) {
4339 return;
9e6cb6b6 4340 }
3f455f90
PK
4341 ev.preventDefault();
4342 ev.stopPropagation();
4343 return false;
9e6cb6b6 4344 }
8bc844c0 4345
3f455f90
PK
4346 function inherits(child, parent) {
4347 function f() {
4348 this.constructor = child;
9e6cb6b6 4349 }
3f455f90
PK
4350 f.prototype = parent.prototype;
4351 child.prototype = new f;
4352 }
8bc844c0 4353
3f455f90
PK
4354 // if bold is broken, we can't
4355 // use it in the terminal.
4356 function isBoldBroken(document) {
4357 var body = document.getElementsByTagName('body')[0];
4358 var el = document.createElement('span');
4359 el.innerHTML = 'hello world';
4360 body.appendChild(el);
4361 var w1 = el.scrollWidth;
4362 el.style.fontWeight = 'bold';
4363 var w2 = el.scrollWidth;
4364 body.removeChild(el);
4365 return w1 !== w2;
4366 }
8bc844c0 4367
3f455f90
PK
4368 var String = this.String;
4369 var setTimeout = this.setTimeout;
4370 var setInterval = this.setInterval;
4371
4372 function indexOf(obj, el) {
4373 var i = obj.length;
4374 while (i--) {
4375 if (obj[i] === el) return i;
9e6cb6b6 4376 }
3f455f90 4377 return -1;
9e6cb6b6 4378 }
8bc844c0 4379
3f455f90
PK
4380 function isWide(ch) {
4381 if (ch <= '\uff00') return false;
4382 return (ch >= '\uff01' && ch <= '\uffbe')
4383 || (ch >= '\uffc2' && ch <= '\uffc7')
4384 || (ch >= '\uffca' && ch <= '\uffcf')
4385 || (ch >= '\uffd2' && ch <= '\uffd7')
4386 || (ch >= '\uffda' && ch <= '\uffdc')
4387 || (ch >= '\uffe0' && ch <= '\uffe6')
4388 || (ch >= '\uffe8' && ch <= '\uffee');
9e6cb6b6 4389 }
8bc844c0 4390
3f455f90
PK
4391 function matchColor(r1, g1, b1) {
4392 var hash = (r1 << 16) | (g1 << 8) | b1;
4393
4394 if (matchColor._cache[hash] != null) {
4395 return matchColor._cache[hash];
4396 }
8bc844c0 4397
3f455f90
PK
4398 var ldiff = Infinity
4399 , li = -1
4400 , i = 0
4401 , c
4402 , r2
4403 , g2
4404 , b2
4405 , diff;
4406
4407 for (; i < Terminal.vcolors.length; i++) {
4408 c = Terminal.vcolors[i];
4409 r2 = c[0];
4410 g2 = c[1];
4411 b2 = c[2];
4412
4413 diff = matchColor.distance(r1, g1, b1, r2, g2, b2);
4414
4415 if (diff === 0) {
4416 li = i;
4417 break;
4418 }
9e6cb6b6 4419
3f455f90
PK
4420 if (diff < ldiff) {
4421 ldiff = diff;
4422 li = i;
4423 }
4424 }
8bc844c0 4425
3f455f90
PK
4426 return matchColor._cache[hash] = li;
4427 }
8bc844c0 4428
3f455f90 4429 matchColor._cache = {};
8bc844c0 4430
3f455f90
PK
4431 // http://stackoverflow.com/questions/1633828
4432 matchColor.distance = function(r1, g1, b1, r2, g2, b2) {
4433 return Math.pow(30 * (r1 - r2), 2)
4434 + Math.pow(59 * (g1 - g2), 2)
4435 + Math.pow(11 * (b1 - b2), 2);
4436 };
8bc844c0 4437
3f455f90
PK
4438 function each(obj, iter, con) {
4439 if (obj.forEach) return obj.forEach(iter, con);
4440 for (var i = 0; i < obj.length; i++) {
4441 iter.call(con, obj[i], i, obj);
4442 }
a68c8336
CJ
4443 }
4444
3f455f90
PK
4445 function keys(obj) {
4446 if (Object.keys) return Object.keys(obj);
4447 var key, keys = [];
4448 for (key in obj) {
4449 if (Object.prototype.hasOwnProperty.call(obj, key)) {
4450 keys.push(key);
4451 }
4452 }
4453 return keys;
86dad1b0 4454 }
86dad1b0 4455
3f455f90
PK
4456 /**
4457 * Expose
4458 */
4459
4460 Terminal.EventEmitter = EventEmitter;
4461 Terminal.inherits = inherits;
4462 Terminal.on = on;
4463 Terminal.off = off;
4464 Terminal.cancel = cancel;
8bc844c0 4465
3f455f90 4466 return Terminal;
987f09d8 4467});