EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
amt-terminal-0.0.2.js
Go to the documentation of this file.
1/**
2* @description Remote Terminal
3* @author Ylian Saint-Hilaire
4* @version v0.0.2c
5*/
6
7// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
8// https://www.x.org/docs/xterm/ctlseqs.pdf
9
10// Construct a MeshServer object
11var CreateAmtRemoteTerminal = function (divid, options) {
12 var obj = {};
13 obj.DivId = divid;
14 obj.DivElement = document.getElementById(divid);
15 obj.protocol = 1; // SOL
16 if (options.protocol) { obj.protocol = options.protocol; } // 1 = Normal, 6 = PowerShell
17 // ###BEGIN###{Terminal-Enumation-All}
18 obj.terminalEmulation = 1;
19 // ###END###{Terminal-Enumation-All}
20 obj.fxEmulation = 0;
21 obj.lineFeed = '\r\n';
22 obj.debugmode = 0;
23
24 obj.width = 80; // 80 or 100
25 obj.height = 25; // 25 or 30
26 obj.heightLock = 0;
27
28 var _Terminal_CellHeight = 21;
29 var _Terminal_CellWidth = 13;
30 var _TermColors = ['000000', 'BB0000', '00BB00', 'BBBB00', '0000BB', 'BB00BB', '00BBBB', 'BBBBBB', '555555', 'FF5555', '55FF55', 'FFFF55', '5555FF', 'FF55FF', '55FFFF', 'FFFFFF'];
31 var _TermCurrentReverse = 0;
32 var _TermCurrentFColor = 7;
33 var _TermCurrentBColor = 0;
34 var _TermLineWrap = true;
35 var _termx = 0;
36 var _termy = 0;
37 var _termsavex = 0;
38 var _termsavey = 0;
39 var _termstate = 0;
40 var _escNumber = [];
41 var _escNumberPtr = 0;
42 var _escNumberMode = 0;
43 var _scratt = [];
44 var _tscreen = [];
45 var _VTUNDERLINE = 1;
46 var _VTREVERSE = 2;
47 var _backSpaceErase = false;
48 var _cursorVisible = true;
49 var _scrollRegion;
50 var _altKeypadMode = false;
51 var scrollBackBuffer = [];
52 // ###BEGIN###{Terminal-Enumation-UTF8}
53 //var utf8decodeBuffer = '';
54 // ###END###{Terminal-Enumation-UTF8}
55 // ###BEGIN###{Terminal-Enumation-All}
56 var utf8decodeBuffer = '';
57 // ###END###{Terminal-Enumation-All}
58 obj.title = null;
59 obj.onTitleChange = null;
60
61 obj.Start = function () { }
62
63 obj.Init = function (width, height) {
64 obj.width = width ? width : 80;
65 obj.height = height ? height : 25;
66 for (var y = 0; y < obj.height; y++) {
67 _tscreen[y] = [];
68 _scratt[y] = [];
69 for (var x = 0; x < obj.width; x++) { _tscreen[y][x] = ' '; _scratt[y][x] = (7 << 6); }
70 }
71 obj.TermInit();
72 obj.TermDraw();
73 }
74
75 obj.xxStateChange = function (newstate) {
76 //if ((newstate == 3) && (options != null) && (options.xterm == true)) { obj.TermSendKeys(' stty rows ' + obj.height + ' cols ' + obj.width + ';clear\n'); }
77 }
78
79 obj.ProcessData = function (str) {
80 if (obj.debugmode == 2) { console.log("TRecv(" + str.length + "): " + rstr2hex(str)); }
81 // ###BEGIN###{Terminal-Enumation-UTF8}
82 //try { str = decode_utf8(utf8decodeBuffer + str); } catch (ex) { utf8decodeBuffer += str; return; } // If we get data in the middle of a UTF-8 code, buffer it for next time.
83 //utf8decodeBuffer = '';
84 // ###END###{Terminal-Enumation-UTF8}
85 // ###BEGIN###{Terminal-Enumation-All}
86 if (obj.terminalEmulation == 0) { try { str = decode_utf8(utf8decodeBuffer + str); } catch (ex) { utf8decodeBuffer += str; return; } } // If we get data in the middle of a UTF-8 code, buffer it for next time.
87 utf8decodeBuffer = '';
88 // ###END###{Terminal-Enumation-All}
89 if (obj.capture != null) obj.capture += str; _ProcessVt100EscString(str); obj.TermDraw();
90 }
91
92 function _ProcessVt100EscString(str) { for (var i = 0; i < str.length; i++) _ProcessVt100EscChar(String.fromCharCode(str.charCodeAt(i)), str.charCodeAt(i)); }
93
94 function _ProcessVt100EscChar(b, c) {
95 switch (_termstate) {
96 case 0: // Normal Term State
97 switch (c) {
98 case 27: // ESC
99 _termstate = 1;
100 _escNumber = [];
101 _escNumberPtr = 0;
102 _escNumberMode = 0;
103 break;
104 default:
105 // Process a single char
106 _ProcessVt100Char(b);
107 break;
108 }
109 break;
110 case 1:
111 switch (b) {
112 case '[':
113 _termstate = 2;
114 break;
115 case '(':
116 _termstate = 4;
117 break;
118 case ')':
119 _termstate = 5;
120 break;
121 case ']':
122 _termstate = 6; // xterm strings
123 break;
124 case '=':
125 // Set alternate keypad mode
126 _altKeypadMode = true;
127 _termstate = 0;
128 break;
129 case '>':
130 // Set numeric keypad mode
131 _altKeypadMode = false;
132 _termstate = 0;
133 break;
134 case '7':
135 // Save Cursor
136 _termsavex = _termx;
137 _termsavey = _termy;
138 _termstate = 0;
139 break;
140 case '8':
141 // Restore Cursor
142 _termx = _termsavex;
143 _termy = _termsavey;
144 _termstate = 0;
145 break;
146 case 'M':
147 // Scroll down one
148 var x = 1;
149 for (var y = _scrollRegion[1]; y >= _scrollRegion[0] + x; y--) {
150 for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y - x][z]; _scratt[y][z] = _scratt[y - x][z]; }
151 }
152 for (var y = _scrollRegion[0] + x - 1; y > _scrollRegion[0] - 1; y--) {
153 for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
154 }
155 _termstate = 0;
156 break;
157 default:
158 console.log('unknown terminal short code', b);
159 _termstate = 0;
160 break;
161 }
162 break;
163 case 2:
164 if (b >= '0' && b <= '9') {
165 // This is a number
166 if (!_escNumber[_escNumberPtr]) { _escNumber[_escNumberPtr] = (b - '0'); }
167 else { _escNumber[_escNumberPtr] = ((_escNumber[_escNumberPtr] * 10) + (b - '0')); }
168 break;
169 } else if (b == ';') {
170 // New number
171 _escNumberPtr++;
172 break;
173 } else if (b == '?') {
174 _escNumberMode = 1;
175 break;
176 } else {
177 // Process Escape Sequence
178 if (!_escNumber[0]) _escNumber[0] = 0;
179 _ProcessEscapeHandler(b, _escNumber, _escNumberPtr + 1, _escNumberMode);
180 _termstate = 0;
181 }
182 break;
183 case 4: // '(' Code
184 _termstate = 0;
185 break;
186 case 5: // ')' Code
187 _termstate = 0;
188 break;
189 case 6: // ']' Code, xterm
190 var bx = b.charCodeAt(0);
191 if (b == ';') {
192 _escNumberPtr++;
193 } else if (bx == 7) {
194 _ProcessXTermHandler(_escNumber);
195 _termstate = 0;
196 } else {
197 if (!_escNumber[_escNumberPtr]) { _escNumber[_escNumberPtr] = b; }
198 else { _escNumber[_escNumberPtr] += b; }
199 }
200 break;
201 }
202 }
203
204 function _ProcessXTermHandler(_escNumber) {
205 if (_escNumber.length == 0) return;
206 var cmd = parseInt(_escNumber[0]);
207 if ((cmd == 0 || cmd == 2) && (_escNumber.length > 1) && (_escNumber[1] != '?')) {
208 if (obj.onTitleChange) { obj.onTitleChange(obj, obj.title = _escNumber[1]); }
209 }
210 }
211
212 function _ProcessEscapeHandler(code, args, argslen, mode) {
213 //console.log('process', code, args, mode);
214 if (mode == 1) {
215 switch (code) {
216 case 'l': // Hide the cursor
217 if (args[0] == 25) { _cursorVisible = false; }
218 break;
219 case 'h': // Show the cursor
220 if (args[0] == 25) { _cursorVisible = true; }
221 break;
222 }
223 } else if (mode == 0) {
224 var i;
225 switch (code) {
226 case 'c': // ResetDevice
227 // Reset
228 obj.TermResetScreen();
229 break;
230 case 'A': // Move cursor up n lines
231 if (argslen == 1) {
232 if (args[0] == 0) { _termy--; } else { _termy -= args[0]; }
233 if (_termy < 0) _termy = 0;
234 }
235 break;
236 case 'B': // Move cursor down n lines
237 if (argslen == 1) {
238 if (args[0] == 0) { _termy++; } else { _termy += args[0]; }
239 if (_termy > obj.height) _termy = obj.height;
240 }
241 break;
242 case 'C': // Move cursor right n lines
243 if (argslen == 1) {
244 if (args[0] == 0) { _termx++; } else { _termx += args[0]; }
245 if (_termx > obj.width) _termx = obj.width;
246 }
247 break;
248 case 'D': // Move cursor left n lines
249 if (argslen == 1) {
250 if (args[0] == 0) { _termx--; } else { _termx -= args[0]; }
251 if (_termx < 0) _termx = 0;
252 }
253 break;
254 case 'd': // Set cursor to line n
255 if (argslen == 1) {
256 _termy = args[0] - 1;
257 if (_termy > obj.height) _termy = obj.height;
258 if (_termy < 0) _termy = 0;
259 }
260 break;
261 case 'G': // Set cursor to col n
262 if (argslen == 1) {
263 _termx = args[0] - 1;
264 if (_termx < 0) _termx = 0;
265 if (_termx > (obj.width - 1)) _termx = (obj.width - 1);
266 }
267 break;
268 case 'P': // Delete X Character(s), default 1 char
269 var x = 1;
270 if (argslen == 1) { x = args[0]; }
271 for (i = _termx; i < obj.width - x; i++) { _tscreen[_termy][i] = _tscreen[_termy][i + x]; _scratt[_termy][i] = _scratt[_termy][i + x]; }
272 for (i = (obj.width - x); i < obj.width; i++) { _tscreen[_termy][i] = ' '; _scratt[_termy][i] = (7 << 6); }
273 break;
274 case 'L': // Insert X Line(s), default 1 char
275 var linecount = 1;
276 if (argslen == 1) { linecount = args[0]; }
277 if (linecount == 0) { linecount = 1; }
278 for (y = _scrollRegion[1]; y >= _termy + linecount; y--) {
279 _tscreen[y] = _tscreen[y - linecount];
280 _scratt[y] = _scratt[y - linecount];
281 }
282 for (y = _termy; y < _termy + linecount; y++) {
283 _tscreen[y] = [];
284 _scratt[y] = [];
285 for (x = 0; x < obj.width; x++) { _tscreen[y][x] = ' '; _scratt[y][x] = (7 << 6); }
286 }
287 break;
288 case 'J': // ClearScreen:
289 if (argslen == 1 && args[0] == 2) {
290 obj.TermClear((_TermCurrentBColor << 12) + (_TermCurrentFColor << 6)); // Erase entire screen
291 _termx = 0;
292 _termy = 0;
293 scrollBackBuffer = [];
294 }
295 else if (argslen == 0 || argslen == 1 && args[0] == 0) // Erase cursor down
296 {
297 _EraseCursorToEol();
298 for (i = _termy + 1; i < obj.height; i++) _EraseLine(i);
299 }
300 else if (argslen == 1 && args[0] == 1) // Erase cursor up
301 {
302 _EraseCursorToEol();
303 for (i = 0; i < _termy - 1; i++) _EraseLine(i);
304 }
305 break;
306 case 'H': // MoveCursor:
307 if (argslen == 2) {
308 if (args[0] < 1) args[0] = 1;
309 if (args[1] < 1) args[1] = 1;
310 if (args[0] > obj.height) args[0] = obj.height;
311 if (args[1] > obj.width) args[1] = obj.width;
312 _termy = args[0] - 1;
313 _termx = args[1] - 1;
314 } else {
315 _termy = 0;
316 _termx = 0;
317 }
318 break;
319 case 'm': // ScreenAttribs:
320 // Change attributes
321 for (i = 0; i < argslen; i++) {
322 if (!args[i] || args[i] == 0) {
323 // Reset Attributes
324 _TermCurrentBColor = 0;
325 _TermCurrentFColor = 7;
326 _TermCurrentReverse = 0;
327 }
328 else if (args[i] == 1) {
329 // Bright
330 if (_TermCurrentFColor < 8) _TermCurrentFColor += 8;
331 }
332 else if (args[i] == 2 || args[i] == 22) {
333 // Dim
334 if (_TermCurrentFColor >= 8) _TermCurrentFColor -= 8;
335 }
336 else if (args[i] == 7) {
337 // Set Reverse attribute true
338 _TermCurrentReverse = 2;
339 }
340 else if (args[i] == 27) {
341 // Set Reverse attribute false
342 _TermCurrentReverse = 0;
343 }
344 else if (args[i] >= 30 && args[i] <= 37) {
345 // Set Foreground Color
346 var bright = (_TermCurrentFColor >= 8);
347 _TermCurrentFColor = (args[i] - 30);
348 if (bright && _TermCurrentFColor <= 8) _TermCurrentFColor += 8;
349 }
350 else if (args[i] >= 40 && args[i] <= 47) {
351 // Set Background Color
352 _TermCurrentBColor = (args[i] - 40);
353 }
354 else if (args[i] >= 90 && args[i] <= 99) {
355 // Set Bright Foreground Color
356 _TermCurrentFColor = (args[i] - 82);
357 }
358 else if (args[i] >= 100 && args[i] <= 109) {
359 // Set Bright Background Color
360 _TermCurrentBColor = (args[i] - 92);
361 }
362 }
363 break;
364 case 'K': // EraseLine:
365 if (argslen == 0 || (argslen == 1 && (!args[0] || args[0] == 0))) {
366 _EraseCursorToEol(); // Erase from the cursor to the end of the line
367 } else if (argslen == 1) {
368 if (args[0] == 1) { // Erase from the beginning of the line to the cursor
369 _EraseBolToCursor();
370 } else if (args[0] == 2) { // Erase the line with the cursor
371 _EraseLine(_termy);
372 }
373 }
374 break;
375 case 'h': // EnableLineWrap:
376 _TermLineWrap = true;
377 break;
378 case 'l': // DisableLineWrap:
379 _TermLineWrap = false;
380 break;
381 case 'r': // Set the scroll region
382 if (argslen == 2) { _scrollRegion = [args[0] - 1, args[1] - 1]; }
383 if (_scrollRegion[0] < 0) { _scrollRegion[0] = 0; }
384 if (_scrollRegion[0] > (obj.height - 1)) { _scrollRegion[0] = (obj.height - 1); }
385 if (_scrollRegion[1] < 0) { _scrollRegion[1] = 0; }
386 if (_scrollRegion[1] > (obj.height - 1)) { _scrollRegion[1] = (obj.height - 1); }
387 if (_scrollRegion[0] > _scrollRegion[1]) { _scrollRegion[0] = _scrollRegion[1]; }
388 break;
389 case 'S': // Scroll up the scroll region X lines, default 1
390 var x = 1;
391 if (argslen == 1) { x = args[0] }
392 for (var y = _scrollRegion[0]; y <= _scrollRegion[1] - x; y++) {
393 for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y + x][z]; _scratt[y][z] = _scratt[y + x][z]; }
394 }
395 for (var y = _scrollRegion[1] - x + 1; y < _scrollRegion[1]; y++) {
396 for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
397 }
398 break;
399 case 'M': // Delete X lines, default 1
400 var x = 1;
401 if (argslen == 1) { x = args[0] }
402 for (var y = _termy; y <= _scrollRegion[1] - x; y++) {
403 for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y + x][z]; _scratt[y][z] = _scratt[y + x][z]; }
404 }
405 for (var y = _scrollRegion[1] - x + 1; y < _scrollRegion[1]; y++) {
406 for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
407 }
408 break;
409 case 'T': // Scroll down the scroll region X lines, default 1
410 var x = 1;
411 if (argslen == 1) { x = args[0] }
412 for (var y = _scrollRegion[1]; y > _scrollRegion[0] + x; y--) {
413 for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y - x][z]; _scratt[y][z] = _scratt[y - x][z]; }
414 }
415 for (var y = _scrollRegion[0] + x; y > _scrollRegion[0]; y--) {
416 for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
417 }
418 break;
419 case 'X': // Erase X characters, default 1
420 var x = 1, xx = _termx, yy = _termy;
421 if (argslen == 1) { x = args[0] }
422 while ((x > 0) && (yy < obj.height)) { _tscreen[yy][xx] = ' '; xx++; x--; if (xx >= obj.width) { xx = 0; yy++; } }
423 break;
424 default:
425 //if (code != '@') alert(code);
426 console.log('Unknown terminal code', code, args, mode);
427 break;
428 }
429 }
430 }
431
432 obj.ProcessVt100String = function (str) {
433 for (var i = 0; i < str.length; i++) _ProcessVt100Char(String.fromCharCode(str.charCodeAt(i)));
434 }
435
436 // ###BEGIN###{Terminal-Enumation-All}
437 var AsciiToUnicode = [
438 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
439 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
440 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
441 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
442 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00da,
443 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
444 0x2593, 0x2592, 0x2591, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
445 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
446 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
447 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
448 0x2568, 0x2564, 0x2565, 0x2568, 0x2558, 0x2552, 0x2553, 0x256b,
449 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258b, 0x2590, 0x2580,
450 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
451 0x03c6, 0x03b8, 0x2126, 0x03b4, 0x221e, 0x00f8, 0x03b5, 0x220f,
452 0x2261, 0x00b1, 0x2265, 0x2266, 0x2320, 0x2321, 0x00f7, 0x2248,
453 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
454 ];
455
456 var AsciiToUnicodeIntel = [
457 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
458 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
459 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
460 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
461 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00da,
462 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ae, 0x00bb,
463 0x2593, 0x2592, 0x2591, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
464 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
465 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
466 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
467 0x2568, 0x2564, 0x2565, 0x2568, 0x2558, 0x2552, 0x2553, 0x256b,
468 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258b, 0x2590, 0x2580,
469 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
470 0x03c6, 0x03b8, 0x2126, 0x03b4, 0x221e, 0x00f8, 0x03b5, 0x220f,
471 0x2261, 0x00b1, 0x2265, 0x2266, 0x2320, 0x2321, 0x00f7, 0x2248,
472 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
473 ];
474 // ###END###{Terminal-Enumation-All}
475
476 // ###BEGIN###{Terminal-Enumation-ASCII}
477 var AsciiToUnicode = [
478 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
479 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
480 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
481 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
482 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00da,
483 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
484 0x2593, 0x2592, 0x2591, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
485 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
486 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
487 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
488 0x2568, 0x2564, 0x2565, 0x2568, 0x2558, 0x2552, 0x2553, 0x256b,
489 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258b, 0x2590, 0x2580,
490 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
491 0x03c6, 0x03b8, 0x2126, 0x03b4, 0x221e, 0x00f8, 0x03b5, 0x220f,
492 0x2261, 0x00b1, 0x2265, 0x2266, 0x2320, 0x2321, 0x00f7, 0x2248,
493 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
494 ];
495 // ###END###{Terminal-Enumation-ASCII}
496
497 // ###BEGIN###{Terminal-Enumation-Intel}
498 var AsciiToUnicodeIntel = [
499 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
500 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
501 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
502 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
503 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00da,
504 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ae, 0x00bb,
505 0x2593, 0x2592, 0x2591, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
506 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
507 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
508 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
509 0x2568, 0x2564, 0x2565, 0x2568, 0x2558, 0x2552, 0x2553, 0x256b,
510 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258b, 0x2590, 0x2580,
511 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
512 0x03c6, 0x03b8, 0x2126, 0x03b4, 0x221e, 0x00f8, 0x03b5, 0x220f,
513 0x2261, 0x00b1, 0x2265, 0x2266, 0x2320, 0x2321, 0x00f7, 0x2248,
514 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
515 ];
516 // ###END###{Terminal-Enumation-Intel}
517
518 function _ProcessVt100Char(c) {
519 if (c == '\0' || c.charCodeAt() == 7) return; // Ignore null & bell
520 var ch = c.charCodeAt();
521 //console.log('_ProcessVt100Char', ch, c);
522
523 // ###BEGIN###{Terminal-Enumation-All}
524 // UTF8 Terminal
525 if (obj.terminalEmulation == 1) {
526 // ANSI - Extended ASCII emulation.
527 if ((ch & 0x80) != 0) { c = String.fromCharCode(AsciiToUnicode[ch & 0x7F]); }
528 } else if (obj.terminalEmulation == 2) {
529 // ANSI - Intel Extended ASCII emulation.
530 if ((ch & 0x80) != 0) { c = String.fromCharCode(AsciiToUnicodeIntel[ch & 0x7F]); }
531 }
532 // ###END###{Terminal-Enumation-All}
533
534 // ###BEGIN###{Terminal-Enumation-ASCII}
535 // ANSI - Extended ASCII emulation.
536 //if ((ch & 0x80) != 0) { c = String.fromCharCode(AsciiToUnicode[ch & 0x7F]); }
537 // ###END###{Terminal-Enumation-ASCII}
538
539 // ###BEGIN###{Terminal-Enumation-Intel}
540 // ANSI - Intel Extended ASCII emulation.
541 //if ((ch & 0x80) != 0) { c = String.fromCharCode(AsciiToUnicodeIntel[ch & 0x7F]); }
542 // ###END###{Terminal-Enumation-Intel}
543
544 //if (ch < 32 && ch != 10 && ch != 13) alert(ch);
545 switch (ch) {
546 case 16: { c = ' '; break; } // This is an odd char that show up on Intel BIOS's.
547 case 24: { c = '↑'; break; }
548 case 25: { c = '↓'; break; }
549 }
550
551 if (_termx > obj.width) _termx = obj.width;
552 if (_termy > (obj.height - 1)) _termy = (obj.height - 1);
553
554 switch (c) {
555 case '\b': // Backspace
556 if (_termx > 0) {
557 _termx--;
558 if (_backSpaceErase) { _TermDrawChar(' '); }
559 }
560 break;
561 case '\t': // tab
562 var tab = 8 - (_termx % 8)
563 for (var x = 0; x < tab; x++) _ProcessVt100Char(" ");
564 break;
565 case '\n': // Linefeed
566 _termy++;
567 if (_termy > _scrollRegion[1]) {
568 // Move everything up one line
569 obj.recordLineTobackBuffer(0);
570 _TermMoveUp(1);
571 _termy = _scrollRegion[1];
572 }
573 if (obj.lineFeed = '\r') { _termx = 0; } // *** If we are in Linux mode, \n will also return the cursor to the first col
574 break;
575 case '\r': // Carriage Return
576 _termx = 0;
577 break;
578 default:
579 if (_termx >= obj.width) {
580 _termx = 0;
581 if (_TermLineWrap) { _termy++; }
582 if (_termy >= (obj.height - 1)) { _TermMoveUp(1); _termy = (obj.height - 1); }
583 }
584 _TermDrawChar(c);
585 _termx++;
586 break;
587 }
588 }
589
590 function _TermDrawChar(c) {
591 _tscreen[_termy][_termx] = c;
592 _scratt[_termy][_termx] = (_TermCurrentFColor << 6) + (_TermCurrentBColor << 12) + _TermCurrentReverse;
593 }
594
595 obj.TermClear = function(TermColor) {
596 for (var y = 0; y < obj.height; y++) {
597 for (var x = 0; x < obj.width; x++) {
598 _tscreen[y][x] = ' ';
599 _scratt[y][x] = TermColor;
600 }
601 }
602 scrollBackBuffer = [];
603 }
604
605 obj.TermResetScreen = function () {
606 _TermCurrentReverse = 0;
607 _TermCurrentFColor = 7;
608 _TermCurrentBColor = 0;
609 _TermLineWrap = _cursorVisible = true;
610 _termx = _termy = 0;
611 _backSpaceErase = false;
612 _scrollRegion = [0, (obj.height - 1)];
613 _altKeypadMode = false;
614 obj.TermClear(7 << 6);
615 // ###BEGIN###{Terminal-Enumation-UTF8}
616 //utf8decodeBuffer = '';
617 // ###END###{Terminal-Enumation-UTF8}
618 // ###BEGIN###{Terminal-Enumation-All}
619 utf8decodeBuffer = '';
620 // ###END###{Terminal-Enumation-All}
621 }
622
623 function _EraseCursorToEol() {
624 var t = (_TermCurrentFColor << 6) + (_TermCurrentBColor << 12) + _TermCurrentReverse;
625 for (var x = _termx; x < obj.width; x++) {
626 _tscreen[_termy][x] = ' ';
627 _scratt[_termy][x] = t;
628 }
629 }
630
631 function _EraseBolToCursor() {
632 var t = (_TermCurrentFColor << 6) + (_TermCurrentBColor << 12) + _TermCurrentReverse;
633 for (var x = 0; x < _termx; x++) {
634 _tscreen[_termy][x] = ' ';
635 _scratt[_termy][x] = t;
636 }
637 }
638
639 function _EraseLine(line) {
640 var t = (_TermCurrentFColor << 6) + (_TermCurrentBColor << 12) + _TermCurrentReverse;
641 for (var x = 0; x < obj.width; x++) {
642 _tscreen[line][x] = ' ';
643 _scratt[line][x] = t;
644 }
645 }
646
647 obj.TermSendKeys = function (keys) { if (obj.debugmode == 2) { console.log("TSend(" + keys.length + "): " + rstr2hex(keys), keys); } obj.parent.send(keys); }
648 obj.TermSendKey = function (key) { if (obj.debugmode == 2) { console.log("TSend(1): " + rstr2hex(String.fromCharCode(key)), key); } obj.parent.send(String.fromCharCode(key)); }
649
650 function _TermMoveUp(linecount) {
651 var x, y;
652 for (y = _scrollRegion[0]; y <= _scrollRegion[1] - linecount; y++) {
653 _tscreen[y] = _tscreen[y + linecount];
654 _scratt[y] = _scratt[y + linecount];
655 }
656 for (y = _scrollRegion[1] - linecount + 1; y <= _scrollRegion[1]; y++) {
657 _tscreen[y] = [];
658 _scratt[y] = [];
659 for (x = 0; x < obj.width; x++) {
660 _tscreen[y][x] = ' ';
661 _scratt[y][x] = (7 << 6);
662 }
663 }
664 }
665
666 obj.TermHandleKeys = function (e) {
667 if (!e.ctrlKey) {
668 if (e.which == 127) obj.TermSendKey(8);
669 else if (e.which == 13) { obj.TermSendKeys(obj.lineFeed); }
670 else if (e.which != 0) obj.TermSendKey(e.which);
671 return false;
672 }
673 if (e.preventDefault) e.preventDefault();
674 if (e.stopPropagation) e.stopPropagation();
675 }
676
677 obj.TermHandleKeyUp = function (e) {
678 if ((e.which != 8) && (e.which != 32) && (e.which != 9)) return true;
679 if (e.preventDefault) e.preventDefault();
680 if (e.stopPropagation) e.stopPropagation();
681 return false;
682 }
683
684 obj.TermHandleKeyDown = function (e) {
685 if ((e.which >= 65) && (e.which <= 90) && (e.ctrlKey == true)) {
686 obj.TermSendKey(e.which - 64);
687 if (e.preventDefault) e.preventDefault();
688 if (e.stopPropagation) e.stopPropagation();
689 return;
690 }
691 if (e.which == 27) { obj.TermSendKeys(String.fromCharCode(27)); return true; }; // ESC
692
693 if (_altKeypadMode == true) {
694 if (e.which == 37) { obj.TermSendKeys(String.fromCharCode(27, 79, 68)); return true; }; // Left
695 if (e.which == 38) { obj.TermSendKeys(String.fromCharCode(27, 79, 65)); return true; }; // Up
696 if (e.which == 39) { obj.TermSendKeys(String.fromCharCode(27, 79, 67)); return true; }; // Right
697 if (e.which == 40) { obj.TermSendKeys(String.fromCharCode(27, 79, 66)); return true; }; // Down
698 } else {
699 if (e.which == 37) { obj.TermSendKeys(String.fromCharCode(27, 91, 68)); return true; }; // Left
700 if (e.which == 38) { obj.TermSendKeys(String.fromCharCode(27, 91, 65)); return true; }; // Up
701 if (e.which == 39) { obj.TermSendKeys(String.fromCharCode(27, 91, 67)); return true; }; // Right
702 if (e.which == 40) { obj.TermSendKeys(String.fromCharCode(27, 91, 66)); return true; }; // Down
703 }
704
705 if (e.which == 33) { obj.TermSendKeys(String.fromCharCode(27, 91, 53, 126)); return true; }; // PageUp
706 if (e.which == 34) { obj.TermSendKeys(String.fromCharCode(27, 91, 54, 126)); return true; }; // PageDown
707 if (e.which == 35) { obj.TermSendKeys(String.fromCharCode(27, 91, 70)); return true; }; // End
708 if (e.which == 36) { obj.TermSendKeys(String.fromCharCode(27, 91, 72)); return true; }; // Home
709 if (e.which == 45) { obj.TermSendKeys(String.fromCharCode(27, 91, 50, 126)); return true; }; // Insert
710 if (e.which == 46) { obj.TermSendKeys(String.fromCharCode(27, 91, 51, 126)); return true; }; // Delete
711
712 if (e.which == 9) { obj.TermSendKeys("\t"); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return true; }; // TAB
713
714 // F1 to F12 keys
715 // ###BEGIN###{Terminal-FxEnumation-All}
716 var fx0 = [80, 81, 119, 120, 116, 117, 113, 114, 112, 77];
717 var fx1 = [49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 33, 64];
718 var fx2 = [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91];
719 if (e.which > 111 & e.which < 124 && e.repeat == false) { // F1 to F12 keys
720 if (obj.fxEmulation == 0 && e.which < 122) { obj.TermSendKeys(String.fromCharCode(27, 91, 79, fx0[e.which - 112])); return true; } // 'Intel (F10 = ESC+[OM)'
721 if (obj.fxEmulation == 1) { obj.TermSendKeys(String.fromCharCode(27, fx1[e.which - 112])); return true; } // 'Alternate (F10 = ESC+0)'
722 if (obj.fxEmulation == 2) { obj.TermSendKeys(String.fromCharCode(27, 79, fx2[e.which - 112])); return true; } // 'VT100+ (F10 = ESC+[OY)'
723 }
724 // ###END###{Terminal-FxEnumation-All}
725 // ###BEGIN###{Terminal-FxEnumation-Intel}
726 var fx0 = [80, 81, 119, 120, 116, 117, 113, 114, 112, 77];
727 if (e.which > 111 & e.which < 122 && e.repeat == false) { obj.TermSendKeys(String.fromCharCode(27, 91, 79, fx0[e.which - 112])); return true; } // 'Intel (F10 = ESC+[OM)'
728 // ###END###{Terminal-FxEnumation-Intel}
729 // ###BEGIN###{Terminal-FxEnumation-Alternate}
730 var fx1 = [49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 33, 64];
731 if (e.which > 111 & e.which < 124 && e.repeat == false) { obj.TermSendKeys(String.fromCharCode(27, fx1[e.which - 112])); return true; } // 'Alternate (F10 = ESC+0)'
732 // ###END###{Terminal-FxEnumation-Alternate}
733 // ###BEGIN###{Terminal-FxEnumation-VT100Plus}
734 var fx2 = [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91];
735 if (e.which > 111 & e.which < 124 && e.repeat == false) { obj.TermSendKeys(String.fromCharCode(27, 79, fx2[e.which - 112])); return true; } // 'VT100+ (F10 = ESC+[OY)'
736 // ###END###{Terminal-FxEnumation-VT100Plus}
737
738 if (e.which != 8 && e.which != 32 && e.which != 9) return true;
739 obj.TermSendKey(e.which);
740 if (e.preventDefault) e.preventDefault();
741 if (e.stopPropagation) e.stopPropagation();
742 return false;
743 }
744
745 obj.recordLineTobackBuffer = function(y) {
746 var closetag = '', buf = '';
747 var r = obj.TermDrawLine(buf, y, closetag);
748 buf = r[0];
749 closetag = r[1];
750 scrollBackBuffer.push(buf + closetag + '<br>');
751 }
752
753 obj.TermDrawLine = function (buf, y, closetag) {
754 var newat, c, oldat = 1, x1, x2;
755 for (var x = 0; x < obj.width; ++x) {
756 newat = _scratt[y][x];
757 if (_termx == x && _termy == y && _cursorVisible) { newat |= _VTREVERSE; } // If this is the cursor location, reverse the color.
758 if (newat != oldat) {
759 buf += closetag;
760 closetag = '';
761 x1 = 6; x2 = 12;
762 if (newat & _VTREVERSE) { x1 = 12; x2 = 6; }
763 buf += '<span style="color:#' + _TermColors[(newat >> x1) & 0x3F] + ';background-color:#' + _TermColors[(newat >> x2) & 0x3F];
764 if (newat & _VTUNDERLINE) buf += ';text-decoration:underline';
765 buf += ';">';
766 closetag = "</span>" + closetag;
767 oldat = newat;
768 }
769
770 c = _tscreen[y][x];
771 switch (c) {
772 case '&': buf += '&amp;'; break;
773 case '<': buf += '&lt;'; break;
774 case '>': buf += '&gt;'; break;
775 case ' ': buf += '&nbsp;'; break;
776 default: buf += c; break;
777 }
778 }
779 return [buf, closetag];
780 }
781
782 obj.TermDraw = function() {
783 var closetag = '', buf = '';
784 for (var y = 0; y < obj.height; ++y) {
785 var r = obj.TermDrawLine(buf, y, closetag);
786 buf = r[0];
787 closetag = r[1];
788 if (y != (obj.height - 1)) buf += '<br>';
789 }
790
791 if (scrollBackBuffer.length > 800) { scrollBackBuffer = scrollBackBuffer.slice(scrollBackBuffer.length - 800); }
792 var backbuffer = scrollBackBuffer.join('');
793 obj.DivElement.innerHTML = "<font size='4'><b>" + backbuffer + buf + closetag + "</b></font>";
794 obj.DivElement.scrollTop = obj.DivElement.scrollHeight;
795 if (obj.heightLock == 0) { setTimeout(obj.TermLockHeight, 10); }
796 }
797
798 obj.TermLockHeight = function () {
799 obj.heightLock = obj.DivElement.clientHeight;
800 obj.DivElement.style['height'] = obj.DivElement.parentNode.style['height'] = obj.heightLock + 'px';
801 obj.DivElement.style['overflow-y'] = 'scroll';
802 }
803
804 obj.TermInit = function () { obj.TermResetScreen(); }
805
806 obj.heightLock = 0;
807 obj.DivElement.style['height'] = '';
808 if ((options != null) && (options.cols != null) && (options.rows != null)) { obj.Init(options.cols, options.rows); } else { obj.Init(); }
809 return obj;
810}