amt-terminal-0.0.2.js 37 KB

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