comparison src/de/mud/terminal/vt320.java @ 0:0ce5cc452d02

initial version
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 10:41:19 -0700
parents
children 9621ac4dd5eb
comparison
equal deleted inserted replaced
-1:000000000000 0:0ce5cc452d02
1 /*
2 * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
3 *
4 * (c) Matthias L. Jugel, Marcus Meiner 1996-2005. All Rights Reserved.
5 *
6 * Please visit http://javatelnet.org/ for updates and contact.
7 *
8 * --LICENSE NOTICE--
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * --LICENSE NOTICE--
23 *
24 */
25
26 package de.mud.terminal;
27
28 import android.text.AndroidCharacter;
29
30 import java.util.Properties;
31
32 /**
33 * Implementation of a VT terminal emulation plus ANSI compatible.
34 * <P>
35 * <B>Maintainer:</B> Marcus Meißner
36 *
37 * @version $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
38 * @author Matthias L. Jugel, Marcus Meißner
39 */
40 public abstract class vt320 extends VDUBuffer implements VDUInput {
41
42 /** The current version id tag.<P>
43 * $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
44 *
45 */
46 public final static String ID = "$Id: vt320.java 507 2005-10-25 10:14:52Z marcus $";
47
48 /** the debug level */
49 private final static int debug = 0;
50 private StringBuilder debugStr;
51 public abstract void debug(String notice);
52
53 /**
54 * Write an answer back to the remote host. This is needed to be able to
55 * send terminal answers requests like status and type information.
56 * @param b the array of bytes to be sent
57 */
58 public abstract void write(byte[] b);
59
60 /**
61 * Write an answer back to the remote host. This is needed to be able to
62 * send terminal answers requests like status and type information.
63 * @param b the byte to be sent
64 */
65 public abstract void write(int b);
66
67 /**
68 * No more bytes to read from the transport, hook here to test screen changes
69 */
70 public void testChanged() {
71 /* do nothing by default */
72 }
73
74 /**
75 * Play the beep sound ...
76 */
77 public void beep() {
78 /* do nothing by default */
79 }
80
81 /**
82 * Convenience function for putString(char[], int, int)
83 */
84 public void putString(String s) {
85 int len = s.length();
86 char[] tmp = new char[len];
87 s.getChars(0, len, tmp, 0);
88 putString(tmp, null, 0, len);
89 }
90
91 /**
92 * Put string at current cursor position. Moves cursor
93 * according to the String. Does NOT wrap.
94 * @param s character array
95 * @param start place to start in array
96 * @param len number of characters to process
97 */
98 public void putString(char[] s, byte[] fullwidths, int start, int len) {
99 if (len > 0) {
100 //markLine(R, 1);
101 int lastChar = -1;
102 char c;
103 boolean isWide = false;
104
105 for (int i = 0; i < len; i++) {
106 c = s[start + i];
107
108 // Shortcut for my favorite ASCII
109 if (c <= 0x7F) {
110 if (lastChar != -1)
111 putChar((char) lastChar, isWide, false);
112
113 lastChar = c;
114 isWide = false;
115 }
116 else if (!Character.isLowSurrogate(c) && !Character.isHighSurrogate(c)) {
117 if (Character.getType(c) == Character.NON_SPACING_MARK) {
118 if (lastChar != -1) {
119 char nc = Precomposer.precompose((char) lastChar, c);
120 putChar(nc, isWide, false);
121 lastChar = -1;
122 }
123 }
124 else {
125 if (lastChar != -1)
126 putChar((char) lastChar, isWide, false);
127
128 lastChar = c;
129
130 if (fullwidths != null) {
131 final byte width = fullwidths[i];
132 isWide = (width == AndroidCharacter.EAST_ASIAN_WIDTH_WIDE)
133 || (width == AndroidCharacter.EAST_ASIAN_WIDTH_FULL_WIDTH);
134 }
135 }
136 }
137 }
138
139 if (lastChar != -1)
140 putChar((char) lastChar, isWide, false);
141
142 setCursorPosition(C, R);
143 redraw();
144 }
145 }
146
147 protected void sendTelnetCommand(byte cmd) {
148 /* do nothing by default */
149 }
150
151 /**
152 * Sent the changed window size from the terminal to all listeners.
153 */
154 protected void setWindowSize(int c, int r) {
155 /* To be overridden by Terminal.java */
156 }
157
158 @Override
159 public void setScreenSize(int c, int r, boolean broadcast) {
160 int oldrows = height;
161
162 if (debug > 2) {
163 if (debugStr == null)
164 debugStr = new StringBuilder();
165
166 debugStr.append("setscreensize (")
167 .append(c)
168 .append(',')
169 .append(r)
170 .append(',')
171 .append(broadcast)
172 .append(')');
173 debug(debugStr.toString());
174 debugStr.setLength(0);
175 }
176
177 super.setScreenSize(c, r, false);
178 boolean cursorChanged = false;
179
180 // Don't let the cursor go off the screen.
181 if (C >= c) {
182 C = c - 1;
183 cursorChanged = true;
184 }
185
186 if (R >= r) {
187 R = r - 1;
188 cursorChanged = true;
189 }
190
191 if (cursorChanged) {
192 setCursorPosition(C, R);
193 redraw();
194 }
195
196 if (broadcast) {
197 setWindowSize(c, r); /* broadcast up */
198 }
199 }
200
201
202 /**
203 * Create a new vt320 terminal and intialize it with useful settings.
204 */
205 public vt320(int width, int height) {
206 super(width, height);
207 debugStr = new StringBuilder();
208 setVMS(false);
209 setIBMCharset(false);
210 setTerminalID("vt320");
211 setBufferSize(100);
212 //setBorder(2, false);
213 gx = new char[4];
214 reset();
215 /* top row of numpad */
216 PF1 = "\u001bOP";
217 PF2 = "\u001bOQ";
218 PF3 = "\u001bOR";
219 PF4 = "\u001bOS";
220 /* the 3x2 keyblock on PC keyboards */
221 Insert = new String[4];
222 Remove = new String[4];
223 KeyHome = new String[4];
224 KeyEnd = new String[4];
225 NextScn = new String[4];
226 PrevScn = new String[4];
227 Escape = new String[4];
228 BackSpace = new String[4];
229 TabKey = new String[4];
230 Insert[0] = Insert[1] = Insert[2] = Insert[3] = "\u001b[2~";
231 Remove[0] = Remove[1] = Remove[2] = Remove[3] = "\u001b[3~";
232 PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[5~";
233 NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[6~";
234 KeyHome[0] = KeyHome[1] = KeyHome[2] = KeyHome[3] = "\u001b[H";
235 KeyEnd[0] = KeyEnd[1] = KeyEnd[2] = KeyEnd[3] = "\u001b[F";
236 Escape[0] = Escape[1] = Escape[2] = Escape[3] = "\u001b";
237
238 if (vms) {
239 BackSpace[1] = "" + (char) 10; // VMS shift deletes word back
240 BackSpace[2] = "\u0018"; // VMS control deletes line back
241 BackSpace[0] = BackSpace[3] = "\u007f"; // VMS other is delete
242 }
243 else {
244 //BackSpace[0] = BackSpace[1] = BackSpace[2] = BackSpace[3] = "\b";
245 // ConnectBot modifications.
246 BackSpace[0] = "\b";
247 BackSpace[1] = "\u007f";
248 BackSpace[2] = "\u001b[3~";
249 BackSpace[3] = "\u001b[2~";
250 }
251
252 /* some more VT100 keys */
253 Find = "\u001b[1~";
254 Select = "\u001b[4~";
255 Help = "\u001b[28~";
256 Do = "\u001b[29~";
257 FunctionKey = new String[21];
258 FunctionKey[0] = "";
259 FunctionKey[1] = PF1;
260 FunctionKey[2] = PF2;
261 FunctionKey[3] = PF3;
262 FunctionKey[4] = PF4;
263 /* following are defined differently for vt220 / vt132 ... */
264 FunctionKey[5] = "\u001b[15~";
265 FunctionKey[6] = "\u001b[17~";
266 FunctionKey[7] = "\u001b[18~";
267 FunctionKey[8] = "\u001b[19~";
268 FunctionKey[9] = "\u001b[20~";
269 FunctionKey[10] = "\u001b[21~";
270 FunctionKey[11] = "\u001b[23~";
271 FunctionKey[12] = "\u001b[24~";
272 FunctionKey[13] = "\u001b[25~";
273 FunctionKey[14] = "\u001b[26~";
274 FunctionKey[15] = Help;
275 FunctionKey[16] = Do;
276 FunctionKey[17] = "\u001b[31~";
277 FunctionKey[18] = "\u001b[32~";
278 FunctionKey[19] = "\u001b[33~";
279 FunctionKey[20] = "\u001b[34~";
280 FunctionKeyShift = new String[21];
281 FunctionKeyAlt = new String[21];
282 FunctionKeyCtrl = new String[21];
283
284 for (int i = 0; i < 20; i++) {
285 FunctionKeyShift[i] = "";
286 FunctionKeyAlt[i] = "";
287 FunctionKeyCtrl[i] = "";
288 }
289
290 FunctionKeyShift[15] = Find;
291 FunctionKeyShift[16] = Select;
292 TabKey[0] = "\u0009";
293 TabKey[1] = "\u001bOP\u0009";
294 TabKey[2] = TabKey[3] = "";
295 KeyUp = new String[4];
296 KeyUp[0] = "\u001b[A";
297 KeyDown = new String[4];
298 KeyDown[0] = "\u001b[B";
299 KeyRight = new String[4];
300 KeyRight[0] = "\u001b[C";
301 KeyLeft = new String[4];
302 KeyLeft[0] = "\u001b[D";
303 Numpad = new String[10];
304 Numpad[0] = "\u001bOp";
305 Numpad[1] = "\u001bOq";
306 Numpad[2] = "\u001bOr";
307 Numpad[3] = "\u001bOs";
308 Numpad[4] = "\u001bOt";
309 Numpad[5] = "\u001bOu";
310 Numpad[6] = "\u001bOv";
311 Numpad[7] = "\u001bOw";
312 Numpad[8] = "\u001bOx";
313 Numpad[9] = "\u001bOy";
314 KPMinus = PF4;
315 KPComma = "\u001bOl";
316 KPPeriod = "\u001bOn";
317 KPEnter = "\u001bOM";
318 NUMPlus = new String[4];
319 NUMPlus[0] = "+";
320 NUMDot = new String[4];
321 NUMDot[0] = ".";
322 }
323
324 public void setBackspace(int type) {
325 switch (type) {
326 case DELETE_IS_DEL:
327 BackSpace[0] = "\u007f";
328 BackSpace[1] = "\b";
329 break;
330
331 case DELETE_IS_BACKSPACE:
332 BackSpace[0] = "\b";
333 BackSpace[1] = "\u007f";
334 break;
335 }
336 }
337
338 /**
339 * Create a default vt320 terminal with 80 columns and 24 lines.
340 */
341 public vt320() {
342 this(80, 24);
343 }
344
345 /**
346 * Terminal is mouse-aware and requires (x,y) coordinates of
347 * on the terminal (character coordinates) and the button clicked.
348 * @param x
349 * @param y
350 * @param modifiers
351 */
352 public void mousePressed(int x, int y, int modifiers) {
353 if (mouserpt == 0)
354 return;
355
356 int mods = modifiers;
357 mousebut = 3;
358
359 if ((mods & 16) == 16) mousebut = 0;
360
361 if ((mods & 8) == 8) mousebut = 1;
362
363 if ((mods & 4) == 4) mousebut = 2;
364
365 int mousecode;
366
367 if (mouserpt == 9) /* X10 Mouse */
368 mousecode = 0x20 | mousebut;
369 else /* normal xterm mouse reporting */
370 mousecode = mousebut | 0x20 | ((mods & 7) << 2);
371
372 byte b[] = new byte[6];
373 b[0] = 27;
374 b[1] = (byte) '[';
375 b[2] = (byte) 'M';
376 b[3] = (byte) mousecode;
377 b[4] = (byte)(0x20 + x + 1);
378 b[5] = (byte)(0x20 + y + 1);
379 write(b); // FIXME: writeSpecial here
380 }
381
382 /**
383 * Terminal is mouse-aware and requires the coordinates and button
384 * of the release.
385 * @param x
386 * @param y
387 * @param modifiers
388 */
389 public void mouseReleased(int x, int y, int modifiers) {
390 if (mouserpt == 0)
391 return;
392
393 /* problem is tht modifiers still have the released button set in them.
394 int mods = modifiers;
395 mousebut = 3;
396 if ((mods & 16)==16) mousebut=0;
397 if ((mods & 8)==8 ) mousebut=1;
398 if ((mods & 4)==4 ) mousebut=2;
399 */
400 int mousecode;
401
402 if (mouserpt == 9)
403 mousecode = 0x20 + mousebut; /* same as press? appears so. */
404 else
405 mousecode = '#';
406
407 byte b[] = new byte[6];
408 b[0] = 27;
409 b[1] = (byte) '[';
410 b[2] = (byte) 'M';
411 b[3] = (byte) mousecode;
412 b[4] = (byte)(0x20 + x + 1);
413 b[5] = (byte)(0x20 + y + 1);
414 write(b); // FIXME: writeSpecial here
415 mousebut = 0;
416 }
417
418
419 /** we should do localecho (passed from other modules). false is default */
420 private boolean localecho = false;
421
422 /**
423 * Enable or disable the local echo property of the terminal.
424 * @param echo true if the terminal should echo locally
425 */
426 public void setLocalEcho(boolean echo) {
427 localecho = echo;
428 }
429
430 /**
431 * Enable the VMS mode of the terminal to handle some things differently
432 * for VMS hosts.
433 * @param vms true for vms mode, false for normal mode
434 */
435 public void setVMS(boolean vms) {
436 this.vms = vms;
437 }
438
439 /**
440 * Enable the usage of the IBM character set used by some BBS's. Special
441 * graphical character are available in this mode.
442 * @param ibm true to use the ibm character set
443 */
444 public void setIBMCharset(boolean ibm) {
445 useibmcharset = ibm;
446 }
447
448 /**
449 * Override the standard key codes used by the terminal emulation.
450 * @param codes a properties object containing key code definitions
451 */
452 public void setKeyCodes(Properties codes) {
453 String res, prefixes[] = {"", "S", "C", "A"};
454 int i;
455
456 for (i = 0; i < 10; i++) {
457 res = codes.getProperty("NUMPAD" + i);
458
459 if (res != null) Numpad[i] = unEscape(res);
460 }
461
462 for (i = 1; i < 20; i++) {
463 res = codes.getProperty("F" + i);
464
465 if (res != null) FunctionKey[i] = unEscape(res);
466
467 res = codes.getProperty("SF" + i);
468
469 if (res != null) FunctionKeyShift[i] = unEscape(res);
470
471 res = codes.getProperty("CF" + i);
472
473 if (res != null) FunctionKeyCtrl[i] = unEscape(res);
474
475 res = codes.getProperty("AF" + i);
476
477 if (res != null) FunctionKeyAlt[i] = unEscape(res);
478 }
479
480 for (i = 0; i < 4; i++) {
481 res = codes.getProperty(prefixes[i] + "PGUP");
482
483 if (res != null) PrevScn[i] = unEscape(res);
484
485 res = codes.getProperty(prefixes[i] + "PGDOWN");
486
487 if (res != null) NextScn[i] = unEscape(res);
488
489 res = codes.getProperty(prefixes[i] + "END");
490
491 if (res != null) KeyEnd[i] = unEscape(res);
492
493 res = codes.getProperty(prefixes[i] + "HOME");
494
495 if (res != null) KeyHome[i] = unEscape(res);
496
497 res = codes.getProperty(prefixes[i] + "INSERT");
498
499 if (res != null) Insert[i] = unEscape(res);
500
501 res = codes.getProperty(prefixes[i] + "REMOVE");
502
503 if (res != null) Remove[i] = unEscape(res);
504
505 res = codes.getProperty(prefixes[i] + "UP");
506
507 if (res != null) KeyUp[i] = unEscape(res);
508
509 res = codes.getProperty(prefixes[i] + "DOWN");
510
511 if (res != null) KeyDown[i] = unEscape(res);
512
513 res = codes.getProperty(prefixes[i] + "LEFT");
514
515 if (res != null) KeyLeft[i] = unEscape(res);
516
517 res = codes.getProperty(prefixes[i] + "RIGHT");
518
519 if (res != null) KeyRight[i] = unEscape(res);
520
521 res = codes.getProperty(prefixes[i] + "ESCAPE");
522
523 if (res != null) Escape[i] = unEscape(res);
524
525 res = codes.getProperty(prefixes[i] + "BACKSPACE");
526
527 if (res != null) BackSpace[i] = unEscape(res);
528
529 res = codes.getProperty(prefixes[i] + "TAB");
530
531 if (res != null) TabKey[i] = unEscape(res);
532
533 res = codes.getProperty(prefixes[i] + "NUMPLUS");
534
535 if (res != null) NUMPlus[i] = unEscape(res);
536
537 res = codes.getProperty(prefixes[i] + "NUMDECIMAL");
538
539 if (res != null) NUMDot[i] = unEscape(res);
540 }
541 }
542
543 /**
544 * Set the terminal id used to identify this terminal.
545 * @param terminalID the id string
546 */
547 public void setTerminalID(String terminalID) {
548 this.terminalID = terminalID;
549
550 if (terminalID.equals("scoansi")) {
551 FunctionKey[1] = "\u001b[M"; FunctionKey[2] = "\u001b[N";
552 FunctionKey[3] = "\u001b[O"; FunctionKey[4] = "\u001b[P";
553 FunctionKey[5] = "\u001b[Q"; FunctionKey[6] = "\u001b[R";
554 FunctionKey[7] = "\u001b[S"; FunctionKey[8] = "\u001b[T";
555 FunctionKey[9] = "\u001b[U"; FunctionKey[10] = "\u001b[V";
556 FunctionKey[11] = "\u001b[W"; FunctionKey[12] = "\u001b[X";
557 FunctionKey[13] = "\u001b[Y"; FunctionKey[14] = "?";
558 FunctionKey[15] = "\u001b[a"; FunctionKey[16] = "\u001b[b";
559 FunctionKey[17] = "\u001b[c"; FunctionKey[18] = "\u001b[d";
560 FunctionKey[19] = "\u001b[e"; FunctionKey[20] = "\u001b[f";
561 PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[I";
562 NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[G";
563 // more theoretically.
564 }
565 }
566
567 public void setAnswerBack(String ab) {
568 this.answerBack = unEscape(ab);
569 }
570
571 /**
572 * Get the terminal id used to identify this terminal.
573 */
574 public String getTerminalID() {
575 return terminalID;
576 }
577
578 /**
579 * A small conveniance method thar converts the string to a byte array
580 * for sending.
581 * @param s the string to be sent
582 */
583 private boolean write(String s, boolean doecho) {
584 if (debug > 2) {
585 debugStr.append("write(|")
586 .append(s)
587 .append("|,")
588 .append(doecho);
589 debug(debugStr.toString());
590 debugStr.setLength(0);
591 }
592
593 if (s == null) // aka the empty string.
594 return true;
595
596 /* NOTE: getBytes() honours some locale, it *CONVERTS* the string.
597 * However, we output only 7bit stuff towards the target, and *some*
598 * 8 bit control codes. We must not mess up the latter, so we do hand
599 * by hand copy.
600 */
601 byte arr[] = new byte[s.length()];
602
603 for (int i = 0; i < s.length(); i++) {
604 arr[i] = (byte) s.charAt(i);
605 }
606
607 write(arr);
608
609 if (doecho)
610 putString(s);
611
612 return true;
613 }
614
615 private boolean write(int s, boolean doecho) {
616 if (debug > 2) {
617 debugStr.append("write(|")
618 .append(s)
619 .append("|,")
620 .append(doecho);
621 debug(debugStr.toString());
622 debugStr.setLength(0);
623 }
624
625 write(s);
626
627 // TODO check if character is wide
628 if (doecho)
629 putChar((char)s, false, false);
630
631 return true;
632 }
633
634 private boolean write(String s) {
635 return write(s, localecho);
636 }
637
638 // ===================================================================
639 // the actual terminal emulation code comes here:
640 // ===================================================================
641
642 private String terminalID = "vt320";
643 private String answerBack = "Use Terminal.answerback to set ...\n";
644
645 // X - COLUMNS, Y - ROWS
646 int R, C;
647 int attributes = 0;
648
649 int Sc, Sr, Sa, Stm, Sbm;
650 char Sgr, Sgl;
651 char Sgx[];
652
653 int insertmode = 0;
654 int statusmode = 0;
655 boolean vt52mode = false;
656 boolean keypadmode = false; /* false - numeric, true - application */
657 boolean output8bit = false;
658 int normalcursor = 0;
659 boolean moveoutsidemargins = true;
660 boolean wraparound = true;
661 boolean sendcrlf = true;
662 boolean capslock = false;
663 boolean numlock = false;
664 int mouserpt = 0;
665 byte mousebut = 0;
666
667 boolean useibmcharset = false;
668
669 int lastwaslf = 0;
670 boolean usedcharsets = false;
671
672 private final static char ESC = 27;
673 private final static char IND = 132;
674 private final static char NEL = 133;
675 private final static char RI = 141;
676 private final static char SS2 = 142;
677 private final static char SS3 = 143;
678 private final static char DCS = 144;
679 private final static char HTS = 136;
680 private final static char CSI = 155;
681 private final static char OSC = 157;
682 private final static int TSTATE_DATA = 0;
683 private final static int TSTATE_ESC = 1; /* ESC */
684 private final static int TSTATE_CSI = 2; /* ESC [ */
685 private final static int TSTATE_DCS = 3; /* ESC P */
686 private final static int TSTATE_DCEQ = 4; /* ESC [? */
687 private final static int TSTATE_ESCSQUARE = 5; /* ESC # */
688 private final static int TSTATE_OSC = 6; /* ESC ] */
689 private final static int TSTATE_SETG0 = 7; /* ESC (? */
690 private final static int TSTATE_SETG1 = 8; /* ESC )? */
691 private final static int TSTATE_SETG2 = 9; /* ESC *? */
692 private final static int TSTATE_SETG3 = 10; /* ESC +? */
693 private final static int TSTATE_CSI_DOLLAR = 11; /* ESC [ Pn $ */
694 private final static int TSTATE_CSI_EX = 12; /* ESC [ ! */
695 private final static int TSTATE_ESCSPACE = 13; /* ESC <space> */
696 private final static int TSTATE_VT52X = 14;
697 private final static int TSTATE_VT52Y = 15;
698 private final static int TSTATE_CSI_TICKS = 16;
699 private final static int TSTATE_CSI_EQUAL = 17; /* ESC [ = */
700 private final static int TSTATE_TITLE = 18; /* xterm title */
701
702 /* Keys we support */
703 public final static int KEY_PAUSE = 1;
704 public final static int KEY_F1 = 2;
705 public final static int KEY_F2 = 3;
706 public final static int KEY_F3 = 4;
707 public final static int KEY_F4 = 5;
708 public final static int KEY_F5 = 6;
709 public final static int KEY_F6 = 7;
710 public final static int KEY_F7 = 8;
711 public final static int KEY_F8 = 9;
712 public final static int KEY_F9 = 10;
713 public final static int KEY_F10 = 11;
714 public final static int KEY_F11 = 12;
715 public final static int KEY_F12 = 13;
716 public final static int KEY_UP = 14;
717 public final static int KEY_DOWN = 15 ;
718 public final static int KEY_LEFT = 16;
719 public final static int KEY_RIGHT = 17;
720 public final static int KEY_PAGE_DOWN = 18;
721 public final static int KEY_PAGE_UP = 19;
722 public final static int KEY_INSERT = 20;
723 public final static int KEY_DELETE = 21;
724 public final static int KEY_BACK_SPACE = 22;
725 public final static int KEY_HOME = 23;
726 public final static int KEY_END = 24;
727 public final static int KEY_NUM_LOCK = 25;
728 public final static int KEY_CAPS_LOCK = 26;
729 public final static int KEY_SHIFT = 27;
730 public final static int KEY_CONTROL = 28;
731 public final static int KEY_ALT = 29;
732 public final static int KEY_ENTER = 30;
733 public final static int KEY_NUMPAD0 = 31;
734 public final static int KEY_NUMPAD1 = 32;
735 public final static int KEY_NUMPAD2 = 33;
736 public final static int KEY_NUMPAD3 = 34;
737 public final static int KEY_NUMPAD4 = 35;
738 public final static int KEY_NUMPAD5 = 36;
739 public final static int KEY_NUMPAD6 = 37;
740 public final static int KEY_NUMPAD7 = 38;
741 public final static int KEY_NUMPAD8 = 39;
742 public final static int KEY_NUMPAD9 = 40;
743 public final static int KEY_DECIMAL = 41;
744 public final static int KEY_ADD = 42;
745 public final static int KEY_ESCAPE = 43;
746
747 public final static int DELETE_IS_DEL = 0;
748 public final static int DELETE_IS_BACKSPACE = 1;
749
750 /* The graphics charsets
751 * B - default ASCII
752 * A - ISO Latin 1
753 * 0 - DEC SPECIAL
754 * < - User defined
755 * ....
756 */
757 char gx[];
758 char gl; // GL (left charset)
759 char gr; // GR (right charset)
760 int onegl; // single shift override for GL.
761
762 // Map from scoansi linedrawing to DEC _and_ unicode (for the stuff which
763 // is not in linedrawing). Got from experimenting with scoadmin.
764 private final static String scoansi_acs = "Tm7k3x4u?kZl@mYjEnB\u2566DqCtAvM\u2550:\u2551N\u2557I\u2554;\u2557H\u255a0a<\u255d";
765 // array to store DEC Special -> Unicode mapping
766 // Unicode DEC Unicode name (DEC name)
767 private static char DECSPECIAL[] = {
768 '\u0040', //5f blank
769 '\u2666', //60 black diamond
770 '\u2592', //61 grey square
771 '\u2409', //62 Horizontal tab (ht) pict. for control
772 '\u240c', //63 Form Feed (ff) pict. for control
773 '\u240d', //64 Carriage Return (cr) pict. for control
774 '\u240a', //65 Line Feed (lf) pict. for control
775 '\u00ba', //66 Masculine ordinal indicator
776 '\u00b1', //67 Plus or minus sign
777 '\u2424', //68 New Line (nl) pict. for control
778 '\u240b', //69 Vertical Tab (vt) pict. for control
779 '\u2518', //6a Forms light up and left
780 '\u2510', //6b Forms light down and left
781 '\u250c', //6c Forms light down and right
782 '\u2514', //6d Forms light up and right
783 '\u253c', //6e Forms light vertical and horizontal
784 '\u2594', //6f Upper 1/8 block (Scan 1)
785 '\u2580', //70 Upper 1/2 block (Scan 3)
786 '\u2500', //71 Forms light horizontal or ?em dash? (Scan 5)
787 '\u25ac', //72 \u25ac black rect. or \u2582 lower 1/4 (Scan 7)
788 '\u005f', //73 \u005f underscore or \u2581 lower 1/8 (Scan 9)
789 '\u251c', //74 Forms light vertical and right
790 '\u2524', //75 Forms light vertical and left
791 '\u2534', //76 Forms light up and horizontal
792 '\u252c', //77 Forms light down and horizontal
793 '\u2502', //78 vertical bar
794 '\u2264', //79 less than or equal
795 '\u2265', //7a greater than or equal
796 '\u00b6', //7b paragraph
797 '\u2260', //7c not equal
798 '\u00a3', //7d Pound Sign (british)
799 '\u00b7' //7e Middle Dot
800 };
801
802 /** Strings to send on function key pressing */
803 private String Numpad[];
804 private String FunctionKey[];
805 private String FunctionKeyShift[];
806 private String FunctionKeyCtrl[];
807 private String FunctionKeyAlt[];
808 private String TabKey[];
809 private String KeyUp[], KeyDown[], KeyLeft[], KeyRight[];
810 private String KPMinus, KPComma, KPPeriod, KPEnter;
811 private String PF1, PF2, PF3, PF4;
812 private String Help, Do, Find, Select;
813
814 private String KeyHome[], KeyEnd[], Insert[], Remove[], PrevScn[], NextScn[];
815 private String Escape[], BackSpace[], NUMDot[], NUMPlus[];
816
817 private String osc, dcs; /* to memorize OSC & DCS control sequence */
818
819 /** vt320 state variable (internal) */
820 private int term_state = TSTATE_DATA;
821 /** in vms mode, set by Terminal.VMS property */
822 private boolean vms = false;
823 /** Tabulators */
824 private byte[] Tabs;
825 /** The list of integers as used by CSI */
826 private int[] DCEvars = new int[30];
827 private int DCEvar;
828
829 /**
830 * Replace escape code characters (backslash + identifier) with their
831 * respective codes.
832 * @param tmp the string to be parsed
833 * @return a unescaped string
834 */
835 static String unEscape(String tmp) {
836 int idx = 0, oldidx = 0;
837 String cmd;
838 // f.println("unescape("+tmp+")");
839 cmd = "";
840
841 while ((idx = tmp.indexOf('\\', oldidx)) >= 0 &&
842 ++idx <= tmp.length()) {
843 cmd += tmp.substring(oldidx, idx - 1);
844
845 if (idx == tmp.length()) return cmd;
846
847 switch (tmp.charAt(idx)) {
848 case 'b':
849 cmd += "\b";
850 break;
851
852 case 'e':
853 cmd += "\u001b";
854 break;
855
856 case 'n':
857 cmd += "\n";
858 break;
859
860 case 'r':
861 cmd += "\r";
862 break;
863
864 case 't':
865 cmd += "\t";
866 break;
867
868 case 'v':
869 cmd += "\u000b";
870 break;
871
872 case 'a':
873 cmd += "\u0012";
874 break;
875
876 default :
877 if ((tmp.charAt(idx) >= '0') && (tmp.charAt(idx) <= '9')) {
878 int i;
879
880 for (i = idx; i < tmp.length(); i++)
881 if ((tmp.charAt(i) < '0') || (tmp.charAt(i) > '9'))
882 break;
883
884 cmd += (char) Integer.parseInt(tmp.substring(idx, i));
885 idx = i - 1;
886 }
887 else
888 cmd += tmp.substring(idx, ++idx);
889
890 break;
891 }
892
893 oldidx = ++idx;
894 }
895
896 if (oldidx <= tmp.length()) cmd += tmp.substring(oldidx);
897
898 return cmd;
899 }
900
901 /**
902 * A small conveniance method thar converts a 7bit string to the 8bit
903 * version depending on VT52/Output8Bit mode.
904 *
905 * @param s the string to be sent
906 */
907 private boolean writeSpecial(String s) {
908 if (s == null)
909 return true;
910
911 if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == 'O'))) {
912 if (vt52mode) {
913 if ((s.charAt(2) >= 'P') && (s.charAt(2) <= 'S')) {
914 s = "\u001b" + s.substring(2); /* ESC x */
915 }
916 else {
917 s = "\u001b?" + s.substring(2); /* ESC ? x */
918 }
919 }
920 else {
921 if (output8bit) {
922 s = "\u008f" + s.substring(2); /* SS3 x */
923 } /* else keep string as it is */
924 }
925 }
926
927 if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == '['))) {
928 if (output8bit) {
929 s = "\u009b" + s.substring(2); /* CSI ... */
930 } /* else keep */
931 }
932
933 return write(s, false);
934 }
935
936 /**
937 * main keytyping event handler...
938 */
939 public void keyPressed(int keyCode, char keyChar, int modifiers) {
940 boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0;
941 boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0;
942 boolean alt = (modifiers & VDUInput.KEY_ALT) != 0;
943
944 if (debug > 1) {
945 debugStr.append("keyPressed(")
946 .append(keyCode)
947 .append(", ")
948 .append((int)keyChar)
949 .append(", ")
950 .append(modifiers)
951 .append(')');
952 debug(debugStr.toString());
953 debugStr.setLength(0);
954 }
955
956 int xind;
957 String fmap[];
958 xind = 0;
959 fmap = FunctionKey;
960
961 if (shift) {
962 fmap = FunctionKeyShift;
963 xind = 1;
964 }
965
966 if (control) {
967 fmap = FunctionKeyCtrl;
968 xind = 2;
969 }
970
971 if (alt) {
972 fmap = FunctionKeyAlt;
973 xind = 3;
974 }
975
976 switch (keyCode) {
977 case KEY_PAUSE:
978 if (shift || control)
979 sendTelnetCommand((byte) 243); // BREAK
980
981 break;
982
983 case KEY_F1:
984 writeSpecial(fmap[1]);
985 break;
986
987 case KEY_F2:
988 writeSpecial(fmap[2]);
989 break;
990
991 case KEY_F3:
992 writeSpecial(fmap[3]);
993 break;
994
995 case KEY_F4:
996 writeSpecial(fmap[4]);
997 break;
998
999 case KEY_F5:
1000 writeSpecial(fmap[5]);
1001 break;
1002
1003 case KEY_F6:
1004 writeSpecial(fmap[6]);
1005 break;
1006
1007 case KEY_F7:
1008 writeSpecial(fmap[7]);
1009 break;
1010
1011 case KEY_F8:
1012 writeSpecial(fmap[8]);
1013 break;
1014
1015 case KEY_F9:
1016 writeSpecial(fmap[9]);
1017 break;
1018
1019 case KEY_F10:
1020 writeSpecial(fmap[10]);
1021 break;
1022
1023 case KEY_F11:
1024 writeSpecial(fmap[11]);
1025 break;
1026
1027 case KEY_F12:
1028 writeSpecial(fmap[12]);
1029 break;
1030
1031 case KEY_UP:
1032 writeSpecial(KeyUp[xind]);
1033 break;
1034
1035 case KEY_DOWN:
1036 writeSpecial(KeyDown[xind]);
1037 break;
1038
1039 case KEY_LEFT:
1040 writeSpecial(KeyLeft[xind]);
1041 break;
1042
1043 case KEY_RIGHT:
1044 writeSpecial(KeyRight[xind]);
1045 break;
1046
1047 case KEY_PAGE_DOWN:
1048 writeSpecial(NextScn[xind]);
1049 break;
1050
1051 case KEY_PAGE_UP:
1052 writeSpecial(PrevScn[xind]);
1053 break;
1054
1055 case KEY_INSERT:
1056 writeSpecial(Insert[xind]);
1057 break;
1058
1059 case KEY_DELETE:
1060 writeSpecial(Remove[xind]);
1061 break;
1062
1063 case KEY_BACK_SPACE:
1064 writeSpecial(BackSpace[xind]);
1065
1066 if (localecho) {
1067 if (BackSpace[xind] == "\b") {
1068 putString("\b \b"); // make the last char 'deleted'
1069 }
1070 else {
1071 putString(BackSpace[xind]); // echo it
1072 }
1073 }
1074
1075 break;
1076
1077 case KEY_HOME:
1078 writeSpecial(KeyHome[xind]);
1079 break;
1080
1081 case KEY_END:
1082 writeSpecial(KeyEnd[xind]);
1083 break;
1084
1085 case KEY_NUM_LOCK:
1086 if (vms && control) {
1087 writeSpecial(PF1);
1088 }
1089
1090 if (!control)
1091 numlock = !numlock;
1092
1093 break;
1094
1095 case KEY_CAPS_LOCK:
1096 capslock = !capslock;
1097 return;
1098
1099 case KEY_SHIFT:
1100 case KEY_CONTROL:
1101 case KEY_ALT:
1102 return;
1103
1104 default:
1105 break;
1106 }
1107 }
1108 /*
1109 public void keyReleased(KeyEvent evt) {
1110 if (debug > 1) debug("keyReleased("+evt+")");
1111 // ignore
1112 }
1113 */
1114 /**
1115 * Handle key Typed events for the terminal, this will get
1116 * all normal key types, but no shift/alt/control/numlock.
1117 */
1118 public void keyTyped(int keyCode, char keyChar, int modifiers) {
1119 boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0;
1120 boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0;
1121 boolean alt = (modifiers & VDUInput.KEY_ALT) != 0;
1122
1123 if (debug > 1) debug("keyTyped(" + keyCode + ", " + (int)keyChar + ", " + modifiers + ")");
1124
1125 if (keyChar == '\t') {
1126 if (shift) {
1127 write(TabKey[1], false);
1128 }
1129 else {
1130 if (control) {
1131 write(TabKey[2], false);
1132 }
1133 else {
1134 if (alt) {
1135 write(TabKey[3], false);
1136 }
1137 else {
1138 write(TabKey[0], false);
1139 }
1140 }
1141 }
1142
1143 return;
1144 }
1145
1146 if (alt) {
1147 write(((char)(keyChar | 0x80)));
1148 return;
1149 }
1150
1151 if (((keyCode == KEY_ENTER) || (keyChar == 10))
1152 && !control) {
1153 write('\r');
1154
1155 if (localecho) putString("\r\n"); // bad hack
1156
1157 return;
1158 }
1159
1160 if ((keyCode == 10) && !control) {
1161 debug("Sending \\r");
1162 write('\r');
1163 return;
1164 }
1165
1166 // FIXME: on german PC keyboards you have to use Alt-Ctrl-q to get an @,
1167 // so we can't just use it here... will probably break some other VMS
1168 // codes. -Marcus
1169 // if(((!vms && keyChar == '2') || keyChar == '@' || keyChar == ' ')
1170 // && control)
1171 if (((!vms && keyChar == '2') || keyChar == ' ') && control)
1172 write(0);
1173
1174 if (vms) {
1175 if (keyChar == 127 && !control) {
1176 if (shift)
1177 writeSpecial(Insert[0]); // VMS shift delete = insert
1178 else
1179 writeSpecial(Remove[0]); // VMS delete = remove
1180
1181 return;
1182 }
1183 else if (control)
1184 switch (keyChar) {
1185 case '0':
1186 writeSpecial(Numpad[0]);
1187 return;
1188
1189 case '1':
1190 writeSpecial(Numpad[1]);
1191 return;
1192
1193 case '2':
1194 writeSpecial(Numpad[2]);
1195 return;
1196
1197 case '3':
1198 writeSpecial(Numpad[3]);
1199 return;
1200
1201 case '4':
1202 writeSpecial(Numpad[4]);
1203 return;
1204
1205 case '5':
1206 writeSpecial(Numpad[5]);
1207 return;
1208
1209 case '6':
1210 writeSpecial(Numpad[6]);
1211 return;
1212
1213 case '7':
1214 writeSpecial(Numpad[7]);
1215 return;
1216
1217 case '8':
1218 writeSpecial(Numpad[8]);
1219 return;
1220
1221 case '9':
1222 writeSpecial(Numpad[9]);
1223 return;
1224
1225 case '.':
1226 writeSpecial(KPPeriod);
1227 return;
1228
1229 case '-':
1230 case 31:
1231 writeSpecial(KPMinus);
1232 return;
1233
1234 case '+':
1235 writeSpecial(KPComma);
1236 return;
1237
1238 case 10:
1239 writeSpecial(KPEnter);
1240 return;
1241
1242 case '/':
1243 writeSpecial(PF2);
1244 return;
1245
1246 case '*':
1247 writeSpecial(PF3);
1248 return;
1249
1250 /* NUMLOCK handled in keyPressed */
1251 default:
1252 break;
1253 }
1254
1255 /* Now what does this do and how did it get here. -Marcus
1256 if (shift && keyChar < 32) {
1257 write(PF1+(char)(keyChar + 64));
1258 return;
1259 }
1260 */
1261 }
1262
1263 // FIXME: not used?
1264 //String fmap[];
1265 int xind;
1266 xind = 0;
1267
1268 //fmap = FunctionKey;
1269 if (shift) {
1270 //fmap = FunctionKeyShift;
1271 xind = 1;
1272 }
1273
1274 if (control) {
1275 //fmap = FunctionKeyCtrl;
1276 xind = 2;
1277 }
1278
1279 if (alt) {
1280 //fmap = FunctionKeyAlt;
1281 xind = 3;
1282 }
1283
1284 if (keyCode == KEY_ESCAPE) {
1285 writeSpecial(Escape[xind]);
1286 return;
1287 }
1288
1289 if ((modifiers & VDUInput.KEY_ACTION) != 0)
1290 switch (keyCode) {
1291 case KEY_NUMPAD0:
1292 writeSpecial(Numpad[0]);
1293 return;
1294
1295 case KEY_NUMPAD1:
1296 writeSpecial(Numpad[1]);
1297 return;
1298
1299 case KEY_NUMPAD2:
1300 writeSpecial(Numpad[2]);
1301 return;
1302
1303 case KEY_NUMPAD3:
1304 writeSpecial(Numpad[3]);
1305 return;
1306
1307 case KEY_NUMPAD4:
1308 writeSpecial(Numpad[4]);
1309 return;
1310
1311 case KEY_NUMPAD5:
1312 writeSpecial(Numpad[5]);
1313 return;
1314
1315 case KEY_NUMPAD6:
1316 writeSpecial(Numpad[6]);
1317 return;
1318
1319 case KEY_NUMPAD7:
1320 writeSpecial(Numpad[7]);
1321 return;
1322
1323 case KEY_NUMPAD8:
1324 writeSpecial(Numpad[8]);
1325 return;
1326
1327 case KEY_NUMPAD9:
1328 writeSpecial(Numpad[9]);
1329 return;
1330
1331 case KEY_DECIMAL:
1332 writeSpecial(NUMDot[xind]);
1333 return;
1334
1335 case KEY_ADD:
1336 writeSpecial(NUMPlus[xind]);
1337 return;
1338 }
1339
1340 if (!((keyChar == 8) || (keyChar == 127) || (keyChar == '\r') || (keyChar == '\n'))) {
1341 write(keyChar);
1342 return;
1343 }
1344 }
1345
1346 private void handle_dcs(String dcs) {
1347 debugStr.append("DCS: ")
1348 .append(dcs);
1349 debug(debugStr.toString());
1350 debugStr.setLength(0);
1351 }
1352
1353 private void handle_osc(String osc) {
1354 if (osc.length() > 2 && osc.substring(0, 2).equals("4;")) {
1355 // Define color palette
1356 String[] colorData = osc.split(";");
1357
1358 try {
1359 int colorIndex = Integer.parseInt(colorData[1]);
1360
1361 if ("rgb:".equals(colorData[2].substring(0, 4))) {
1362 String[] rgb = colorData[2].substring(4).split("/");
1363 int red = Integer.parseInt(rgb[0].substring(0, 2), 16) & 0xFF;
1364 int green = Integer.parseInt(rgb[1].substring(0, 2), 16) & 0xFF;
1365 int blue = Integer.parseInt(rgb[2].substring(0, 2), 16) & 0xFF;
1366 display.setColor(colorIndex, red, green, blue);
1367 }
1368 }
1369 catch (Exception e) {
1370 debugStr.append("OSC: invalid color sequence encountered: ")
1371 .append(osc);
1372 debug(debugStr.toString());
1373 debugStr.setLength(0);
1374 }
1375 }
1376 else
1377 debug("OSC: " + osc);
1378 }
1379
1380 private final static char unimap[] = {
1381 //#
1382 //# Name: cp437_DOSLatinUS to Unicode table
1383 //# Unicode version: 1.1
1384 //# Table version: 1.1
1385 //# Table format: Format A
1386 //# Date: 03/31/95
1387 //# Authors: Michel Suignard <michelsu@microsoft.com>
1388 //# Lori Hoerth <lorih@microsoft.com>
1389 //# General notes: none
1390 //#
1391 //# Format: Three tab-separated columns
1392 //# Column #1 is the cp1255_WinHebrew code (in hex)
1393 //# Column #2 is the Unicode (in hex as 0xXXXX)
1394 //# Column #3 is the Unicode name (follows a comment sign, '#')
1395 //#
1396 //# The entries are in cp437_DOSLatinUS order
1397 //#
1398
1399 0x0000, // #NULL
1400 0x0001, // #START OF HEADING
1401 0x0002, // #START OF TEXT
1402 0x0003, // #END OF TEXT
1403 0x0004, // #END OF TRANSMISSION
1404 0x0005, // #ENQUIRY
1405 0x0006, // #ACKNOWLEDGE
1406 0x0007, // #BELL
1407 0x0008, // #BACKSPACE
1408 0x0009, // #HORIZONTAL TABULATION
1409 0x000a, // #LINE FEED
1410 0x000b, // #VERTICAL TABULATION
1411 0x000c, // #FORM FEED
1412 0x000d, // #CARRIAGE RETURN
1413 0x000e, // #SHIFT OUT
1414 0x000f, // #SHIFT IN
1415 0x0010, // #DATA LINK ESCAPE
1416 0x0011, // #DEVICE CONTROL ONE
1417 0x0012, // #DEVICE CONTROL TWO
1418 0x0013, // #DEVICE CONTROL THREE
1419 0x0014, // #DEVICE CONTROL FOUR
1420 0x0015, // #NEGATIVE ACKNOWLEDGE
1421 0x0016, // #SYNCHRONOUS IDLE
1422 0x0017, // #END OF TRANSMISSION BLOCK
1423 0x0018, // #CANCEL
1424 0x0019, // #END OF MEDIUM
1425 0x001a, // #SUBSTITUTE
1426 0x001b, // #ESCAPE
1427 0x001c, // #FILE SEPARATOR
1428 0x001d, // #GROUP SEPARATOR
1429 0x001e, // #RECORD SEPARATOR
1430 0x001f, // #UNIT SEPARATOR
1431 0x0020, // #SPACE
1432 0x0021, // #EXCLAMATION MARK
1433 0x0022, // #QUOTATION MARK
1434 0x0023, // #NUMBER SIGN
1435 0x0024, // #DOLLAR SIGN
1436 0x0025, // #PERCENT SIGN
1437 0x0026, // #AMPERSAND
1438 0x0027, // #APOSTROPHE
1439 0x0028, // #LEFT PARENTHESIS
1440 0x0029, // #RIGHT PARENTHESIS
1441 0x002a, // #ASTERISK
1442 0x002b, // #PLUS SIGN
1443 0x002c, // #COMMA
1444 0x002d, // #HYPHEN-MINUS
1445 0x002e, // #FULL STOP
1446 0x002f, // #SOLIDUS
1447 0x0030, // #DIGIT ZERO
1448 0x0031, // #DIGIT ONE
1449 0x0032, // #DIGIT TWO
1450 0x0033, // #DIGIT THREE
1451 0x0034, // #DIGIT FOUR
1452 0x0035, // #DIGIT FIVE
1453 0x0036, // #DIGIT SIX
1454 0x0037, // #DIGIT SEVEN
1455 0x0038, // #DIGIT EIGHT
1456 0x0039, // #DIGIT NINE
1457 0x003a, // #COLON
1458 0x003b, // #SEMICOLON
1459 0x003c, // #LESS-THAN SIGN
1460 0x003d, // #EQUALS SIGN
1461 0x003e, // #GREATER-THAN SIGN
1462 0x003f, // #QUESTION MARK
1463 0x0040, // #COMMERCIAL AT
1464 0x0041, // #LATIN CAPITAL LETTER A
1465 0x0042, // #LATIN CAPITAL LETTER B
1466 0x0043, // #LATIN CAPITAL LETTER C
1467 0x0044, // #LATIN CAPITAL LETTER D
1468 0x0045, // #LATIN CAPITAL LETTER E
1469 0x0046, // #LATIN CAPITAL LETTER F
1470 0x0047, // #LATIN CAPITAL LETTER G
1471 0x0048, // #LATIN CAPITAL LETTER H
1472 0x0049, // #LATIN CAPITAL LETTER I
1473 0x004a, // #LATIN CAPITAL LETTER J
1474 0x004b, // #LATIN CAPITAL LETTER K
1475 0x004c, // #LATIN CAPITAL LETTER L
1476 0x004d, // #LATIN CAPITAL LETTER M
1477 0x004e, // #LATIN CAPITAL LETTER N
1478 0x004f, // #LATIN CAPITAL LETTER O
1479 0x0050, // #LATIN CAPITAL LETTER P
1480 0x0051, // #LATIN CAPITAL LETTER Q
1481 0x0052, // #LATIN CAPITAL LETTER R
1482 0x0053, // #LATIN CAPITAL LETTER S
1483 0x0054, // #LATIN CAPITAL LETTER T
1484 0x0055, // #LATIN CAPITAL LETTER U
1485 0x0056, // #LATIN CAPITAL LETTER V
1486 0x0057, // #LATIN CAPITAL LETTER W
1487 0x0058, // #LATIN CAPITAL LETTER X
1488 0x0059, // #LATIN CAPITAL LETTER Y
1489 0x005a, // #LATIN CAPITAL LETTER Z
1490 0x005b, // #LEFT SQUARE BRACKET
1491 0x005c, // #REVERSE SOLIDUS
1492 0x005d, // #RIGHT SQUARE BRACKET
1493 0x005e, // #CIRCUMFLEX ACCENT
1494 0x005f, // #LOW LINE
1495 0x0060, // #GRAVE ACCENT
1496 0x0061, // #LATIN SMALL LETTER A
1497 0x0062, // #LATIN SMALL LETTER B
1498 0x0063, // #LATIN SMALL LETTER C
1499 0x0064, // #LATIN SMALL LETTER D
1500 0x0065, // #LATIN SMALL LETTER E
1501 0x0066, // #LATIN SMALL LETTER F
1502 0x0067, // #LATIN SMALL LETTER G
1503 0x0068, // #LATIN SMALL LETTER H
1504 0x0069, // #LATIN SMALL LETTER I
1505 0x006a, // #LATIN SMALL LETTER J
1506 0x006b, // #LATIN SMALL LETTER K
1507 0x006c, // #LATIN SMALL LETTER L
1508 0x006d, // #LATIN SMALL LETTER M
1509 0x006e, // #LATIN SMALL LETTER N
1510 0x006f, // #LATIN SMALL LETTER O
1511 0x0070, // #LATIN SMALL LETTER P
1512 0x0071, // #LATIN SMALL LETTER Q
1513 0x0072, // #LATIN SMALL LETTER R
1514 0x0073, // #LATIN SMALL LETTER S
1515 0x0074, // #LATIN SMALL LETTER T
1516 0x0075, // #LATIN SMALL LETTER U
1517 0x0076, // #LATIN SMALL LETTER V
1518 0x0077, // #LATIN SMALL LETTER W
1519 0x0078, // #LATIN SMALL LETTER X
1520 0x0079, // #LATIN SMALL LETTER Y
1521 0x007a, // #LATIN SMALL LETTER Z
1522 0x007b, // #LEFT CURLY BRACKET
1523 0x007c, // #VERTICAL LINE
1524 0x007d, // #RIGHT CURLY BRACKET
1525 0x007e, // #TILDE
1526 0x007f, // #DELETE
1527 0x00c7, // #LATIN CAPITAL LETTER C WITH CEDILLA
1528 0x00fc, // #LATIN SMALL LETTER U WITH DIAERESIS
1529 0x00e9, // #LATIN SMALL LETTER E WITH ACUTE
1530 0x00e2, // #LATIN SMALL LETTER A WITH CIRCUMFLEX
1531 0x00e4, // #LATIN SMALL LETTER A WITH DIAERESIS
1532 0x00e0, // #LATIN SMALL LETTER A WITH GRAVE
1533 0x00e5, // #LATIN SMALL LETTER A WITH RING ABOVE
1534 0x00e7, // #LATIN SMALL LETTER C WITH CEDILLA
1535 0x00ea, // #LATIN SMALL LETTER E WITH CIRCUMFLEX
1536 0x00eb, // #LATIN SMALL LETTER E WITH DIAERESIS
1537 0x00e8, // #LATIN SMALL LETTER E WITH GRAVE
1538 0x00ef, // #LATIN SMALL LETTER I WITH DIAERESIS
1539 0x00ee, // #LATIN SMALL LETTER I WITH CIRCUMFLEX
1540 0x00ec, // #LATIN SMALL LETTER I WITH GRAVE
1541 0x00c4, // #LATIN CAPITAL LETTER A WITH DIAERESIS
1542 0x00c5, // #LATIN CAPITAL LETTER A WITH RING ABOVE
1543 0x00c9, // #LATIN CAPITAL LETTER E WITH ACUTE
1544 0x00e6, // #LATIN SMALL LIGATURE AE
1545 0x00c6, // #LATIN CAPITAL LIGATURE AE
1546 0x00f4, // #LATIN SMALL LETTER O WITH CIRCUMFLEX
1547 0x00f6, // #LATIN SMALL LETTER O WITH DIAERESIS
1548 0x00f2, // #LATIN SMALL LETTER O WITH GRAVE
1549 0x00fb, // #LATIN SMALL LETTER U WITH CIRCUMFLEX
1550 0x00f9, // #LATIN SMALL LETTER U WITH GRAVE
1551 0x00ff, // #LATIN SMALL LETTER Y WITH DIAERESIS
1552 0x00d6, // #LATIN CAPITAL LETTER O WITH DIAERESIS
1553 0x00dc, // #LATIN CAPITAL LETTER U WITH DIAERESIS
1554 0x00a2, // #CENT SIGN
1555 0x00a3, // #POUND SIGN
1556 0x00a5, // #YEN SIGN
1557 0x20a7, // #PESETA SIGN
1558 0x0192, // #LATIN SMALL LETTER F WITH HOOK
1559 0x00e1, // #LATIN SMALL LETTER A WITH ACUTE
1560 0x00ed, // #LATIN SMALL LETTER I WITH ACUTE
1561 0x00f3, // #LATIN SMALL LETTER O WITH ACUTE
1562 0x00fa, // #LATIN SMALL LETTER U WITH ACUTE
1563 0x00f1, // #LATIN SMALL LETTER N WITH TILDE
1564 0x00d1, // #LATIN CAPITAL LETTER N WITH TILDE
1565 0x00aa, // #FEMININE ORDINAL INDICATOR
1566 0x00ba, // #MASCULINE ORDINAL INDICATOR
1567 0x00bf, // #INVERTED QUESTION MARK
1568 0x2310, // #REVERSED NOT SIGN
1569 0x00ac, // #NOT SIGN
1570 0x00bd, // #VULGAR FRACTION ONE HALF
1571 0x00bc, // #VULGAR FRACTION ONE QUARTER
1572 0x00a1, // #INVERTED EXCLAMATION MARK
1573 0x00ab, // #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
1574 0x00bb, // #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
1575 0x2591, // #LIGHT SHADE
1576 0x2592, // #MEDIUM SHADE
1577 0x2593, // #DARK SHADE
1578 0x2502, // #BOX DRAWINGS LIGHT VERTICAL
1579 0x2524, // #BOX DRAWINGS LIGHT VERTICAL AND LEFT
1580 0x2561, // #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
1581 0x2562, // #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
1582 0x2556, // #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
1583 0x2555, // #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
1584 0x2563, // #BOX DRAWINGS DOUBLE VERTICAL AND LEFT
1585 0x2551, // #BOX DRAWINGS DOUBLE VERTICAL
1586 0x2557, // #BOX DRAWINGS DOUBLE DOWN AND LEFT
1587 0x255d, // #BOX DRAWINGS DOUBLE UP AND LEFT
1588 0x255c, // #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
1589 0x255b, // #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
1590 0x2510, // #BOX DRAWINGS LIGHT DOWN AND LEFT
1591 0x2514, // #BOX DRAWINGS LIGHT UP AND RIGHT
1592 0x2534, // #BOX DRAWINGS LIGHT UP AND HORIZONTAL
1593 0x252c, // #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
1594 0x251c, // #BOX DRAWINGS LIGHT VERTICAL AND RIGHT
1595 0x2500, // #BOX DRAWINGS LIGHT HORIZONTAL
1596 0x253c, // #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
1597 0x255e, // #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
1598 0x255f, // #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
1599 0x255a, // #BOX DRAWINGS DOUBLE UP AND RIGHT
1600 0x2554, // #BOX DRAWINGS DOUBLE DOWN AND RIGHT
1601 0x2569, // #BOX DRAWINGS DOUBLE UP AND HORIZONTAL
1602 0x2566, // #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
1603 0x2560, // #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
1604 0x2550, // #BOX DRAWINGS DOUBLE HORIZONTAL
1605 0x256c, // #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
1606 0x2567, // #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
1607 0x2568, // #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
1608 0x2564, // #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
1609 0x2565, // #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
1610 0x2559, // #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
1611 0x2558, // #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
1612 0x2552, // #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
1613 0x2553, // #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
1614 0x256b, // #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
1615 0x256a, // #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
1616 0x2518, // #BOX DRAWINGS LIGHT UP AND LEFT
1617 0x250c, // #BOX DRAWINGS LIGHT DOWN AND RIGHT
1618 0x2588, // #FULL BLOCK
1619 0x2584, // #LOWER HALF BLOCK
1620 0x258c, // #LEFT HALF BLOCK
1621 0x2590, // #RIGHT HALF BLOCK
1622 0x2580, // #UPPER HALF BLOCK
1623 0x03b1, // #GREEK SMALL LETTER ALPHA
1624 0x00df, // #LATIN SMALL LETTER SHARP S
1625 0x0393, // #GREEK CAPITAL LETTER GAMMA
1626 0x03c0, // #GREEK SMALL LETTER PI
1627 0x03a3, // #GREEK CAPITAL LETTER SIGMA
1628 0x03c3, // #GREEK SMALL LETTER SIGMA
1629 0x00b5, // #MICRO SIGN
1630 0x03c4, // #GREEK SMALL LETTER TAU
1631 0x03a6, // #GREEK CAPITAL LETTER PHI
1632 0x0398, // #GREEK CAPITAL LETTER THETA
1633 0x03a9, // #GREEK CAPITAL LETTER OMEGA
1634 0x03b4, // #GREEK SMALL LETTER DELTA
1635 0x221e, // #INFINITY
1636 0x03c6, // #GREEK SMALL LETTER PHI
1637 0x03b5, // #GREEK SMALL LETTER EPSILON
1638 0x2229, // #INTERSECTION
1639 0x2261, // #IDENTICAL TO
1640 0x00b1, // #PLUS-MINUS SIGN
1641 0x2265, // #GREATER-THAN OR EQUAL TO
1642 0x2264, // #LESS-THAN OR EQUAL TO
1643 0x2320, // #TOP HALF INTEGRAL
1644 0x2321, // #BOTTOM HALF INTEGRAL
1645 0x00f7, // #DIVISION SIGN
1646 0x2248, // #ALMOST EQUAL TO
1647 0x00b0, // #DEGREE SIGN
1648 0x2219, // #BULLET OPERATOR
1649 0x00b7, // #MIDDLE DOT
1650 0x221a, // #SQUARE ROOT
1651 0x207f, // #SUPERSCRIPT LATIN SMALL LETTER N
1652 0x00b2, // #SUPERSCRIPT TWO
1653 0x25a0, // #BLACK SQUARE
1654 0x00a0, // #NO-BREAK SPACE
1655 };
1656
1657 public char map_cp850_unicode(char x) {
1658 if (x >= 0x100)
1659 return x;
1660
1661 return unimap[x];
1662 }
1663
1664 private void _SetCursor(int row, int col) {
1665 int maxr = height - 1;
1666 int tm = getTopMargin();
1667 R = (row < 0) ? 0 : row;
1668 C = (col < 0) ? 0 : (col >= width) ? width - 1 : col;
1669
1670 if (!moveoutsidemargins) {
1671 R += tm;
1672 maxr = getBottomMargin();
1673 }
1674
1675 if (R > maxr) R = maxr;
1676 }
1677
1678 private void putChar(char c, boolean isWide, boolean doshowcursor) {
1679 int rows = this.height; //statusline
1680 int columns = this.width;
1681
1682 // byte msg[];
1683 // if (debug > 4) {
1684 // debugStr.append("putChar(")
1685 // .append(c)
1686 // .append(" [")
1687 // .append((int) c)
1688 // .append("]) at R=")
1689 // .append(R)
1690 // .append(" , C=")
1691 // .append(C)
1692 // .append(", columns=")
1693 // .append(columns)
1694 // .append(", rows=")
1695 // .append(rows);
1696 // debug(debugStr.toString());
1697 // debugStr.setLength(0);
1698 // }
1699 // markLine(R, 1);
1700 // if (c > 255) {
1701 // if (debug > 0)
1702 // debug("char > 255:" + (int) c);
1703 // //return;
1704 // }
1705 switch (term_state) {
1706 case TSTATE_DATA:
1707
1708 /* FIXME: we shouldn't use chars with bit 8 set if ibmcharset.
1709 * probably... but some BBS do anyway...
1710 */
1711 if (!useibmcharset) {
1712 boolean doneflag = true;
1713
1714 switch (c) {
1715 case OSC:
1716 osc = "";
1717 term_state = TSTATE_OSC;
1718 break;
1719
1720 case RI:
1721 if (R > getTopMargin())
1722 R--;
1723 else
1724 insertLine(R, 1, SCROLL_DOWN);
1725
1726 if (debug > 1)
1727 debug("RI");
1728
1729 break;
1730
1731 case IND:
1732 if (debug > 2) {
1733 debugStr.append("IND at ")
1734 .append(R)
1735 .append(", tm is ")
1736 .append(getTopMargin())
1737 .append(", bm is ")
1738 .append(getBottomMargin());
1739 debug(debugStr.toString());
1740 debugStr.setLength(0);
1741 }
1742
1743 if (R == getBottomMargin() || R == rows - 1)
1744 insertLine(R, 1, SCROLL_UP);
1745 else
1746 R++;
1747
1748 if (debug > 1)
1749 debug("IND (at " + R + " )");
1750
1751 break;
1752
1753 case NEL:
1754 if (R == getBottomMargin() || R == rows - 1)
1755 insertLine(R, 1, SCROLL_UP);
1756 else
1757 R++;
1758
1759 C = 0;
1760
1761 if (debug > 1)
1762 debug("NEL (at " + R + " )");
1763
1764 break;
1765
1766 case HTS:
1767 Tabs[C] = 1;
1768
1769 if (debug > 1)
1770 debug("HTS");
1771
1772 break;
1773
1774 case DCS:
1775 dcs = "";
1776 term_state = TSTATE_DCS;
1777 break;
1778
1779 default:
1780 doneflag = false;
1781 break;
1782 }
1783
1784 if (doneflag) break;
1785 }
1786
1787 switch (c) {
1788 case SS3:
1789 onegl = 3;
1790 break;
1791
1792 case SS2:
1793 onegl = 2;
1794 break;
1795
1796 case CSI: // should be in the 8bit section, but some BBS use this
1797 DCEvar = 0;
1798 DCEvars[0] = 0;
1799 DCEvars[1] = 0;
1800 DCEvars[2] = 0;
1801 DCEvars[3] = 0;
1802 term_state = TSTATE_CSI;
1803 break;
1804
1805 case ESC:
1806 term_state = TSTATE_ESC;
1807 lastwaslf = 0;
1808 break;
1809
1810 case 5: /* ENQ */
1811 write(answerBack, false);
1812 break;
1813
1814 case 12:
1815 /* FormFeed, Home for the BBS world */
1816 deleteArea(0, 0, columns, rows, attributes);
1817 C = R = 0;
1818 break;
1819
1820 case '\b': /* 8 */
1821 C--;
1822
1823 if (C < 0)
1824 C = 0;
1825
1826 lastwaslf = 0;
1827 break;
1828
1829 case '\t':
1830 do {
1831 // Don't overwrite or insert! TABS are not destructive, but movement!
1832 C++;
1833 }
1834 while (C < columns && (Tabs[C] == 0));
1835
1836 lastwaslf = 0;
1837 break;
1838
1839 case '\r': // 13 CR
1840 C = 0;
1841 break;
1842
1843 case '\n': // 10 LF
1844 if (debug > 3)
1845 debug("R= " + R + ", bm " + getBottomMargin() + ", tm=" + getTopMargin() + ", rows=" + rows);
1846
1847 if (!vms) {
1848 if (lastwaslf != 0 && lastwaslf != c) // Ray: I do not understand this logic.
1849 break;
1850
1851 lastwaslf = c;
1852 /*C = 0;*/
1853 }
1854
1855 if (R == getBottomMargin() || R >= rows - 1)
1856 insertLine(R, 1, SCROLL_UP);
1857 else
1858 R++;
1859
1860 break;
1861
1862 case 7:
1863 beep();
1864 break;
1865
1866 case '\016': /* SMACS , as */
1867 /* ^N, Shift out - Put G1 into GL */
1868 gl = 1;
1869 usedcharsets = true;
1870 break;
1871
1872 case '\017': /* RMACS , ae */
1873 /* ^O, Shift in - Put G0 into GL */
1874 gl = 0;
1875 usedcharsets = true;
1876 break;
1877
1878 default: {
1879 int thisgl = gl;
1880
1881 if (onegl >= 0) {
1882 thisgl = onegl;
1883 onegl = -1;
1884 }
1885
1886 lastwaslf = 0;
1887
1888 if (c < 32) {
1889 if (c != 0)
1890 if (debug > 0)
1891 debug("TSTATE_DATA char: " + ((int) c));
1892
1893 /*break; some BBS really want those characters, like hearst etc. */
1894 if (c == 0) /* print 0 ... you bet */
1895 break;
1896 }
1897
1898 if (C >= columns) {
1899 if (wraparound) {
1900 int bot = rows;
1901
1902 // If we're in the scroll region, check against the bottom margin
1903 if (R <= getBottomMargin() && R >= getTopMargin())
1904 bot = getBottomMargin() + 1;
1905
1906 if (R < bot - 1)
1907 R++;
1908 else {
1909 if (debug > 3) debug("scrolling due to wrap at " + R);
1910
1911 insertLine(R, 1, SCROLL_UP);
1912 }
1913
1914 C = 0;
1915 }
1916 else {
1917 // cursor stays on last character.
1918 C = columns - 1;
1919 }
1920 }
1921
1922 boolean mapped = false;
1923
1924 // Mapping if DEC Special is chosen charset
1925 if (usedcharsets) {
1926 if (c >= '\u0020' && c <= '\u007f') {
1927 switch (gx[thisgl]) {
1928 case '0':
1929
1930 // Remap SCOANSI line drawing to VT100 line drawing chars
1931 // for our SCO using customers.
1932 if (terminalID.equals("scoansi") || terminalID.equals("ansi")) {
1933 for (int i = 0; i < scoansi_acs.length(); i += 2) {
1934 if (c == scoansi_acs.charAt(i)) {
1935 c = scoansi_acs.charAt(i + 1);
1936 break;
1937 }
1938 }
1939 }
1940
1941 if (c >= '\u005f' && c <= '\u007e') {
1942 c = DECSPECIAL[(short) c - 0x5f];
1943 mapped = true;
1944 }
1945
1946 break;
1947
1948 case '<': // 'user preferred' is currently 'ISO Latin-1 suppl
1949 c = (char)((c & 0x7f) | 0x80);
1950 mapped = true;
1951 break;
1952
1953 case 'A':
1954 case 'B': // Latin-1 , ASCII -> fall through
1955 mapped = true;
1956 break;
1957
1958 default:
1959 debug("Unsupported GL mapping: " + gx[thisgl]);
1960 break;
1961 }
1962 }
1963
1964 if (!mapped && (c >= '\u0080' && c <= '\u00ff')) {
1965 switch (gx[gr]) {
1966 case '0':
1967 if (c >= '\u00df' && c <= '\u00fe') {
1968 c = DECSPECIAL[c - '\u00df'];
1969 mapped = true;
1970 }
1971
1972 break;
1973
1974 case '<':
1975 case 'A':
1976 case 'B':
1977 mapped = true;
1978 break;
1979
1980 default:
1981 debug("Unsupported GR mapping: " + gx[gr]);
1982 break;
1983 }
1984 }
1985 }
1986
1987 if (!mapped && useibmcharset)
1988 c = map_cp850_unicode(c);
1989
1990 /*if(true || (statusmode == 0)) { */
1991 if (isWide) {
1992 if (C >= columns - 1) {
1993 if (wraparound) {
1994 int bot = rows;
1995
1996 // If we're in the scroll region, check against the bottom margin
1997 if (R <= getBottomMargin() && R >= getTopMargin())
1998 bot = getBottomMargin() + 1;
1999
2000 if (R < bot - 1)
2001 R++;
2002 else {
2003 if (debug > 3) debug("scrolling due to wrap at " + R);
2004
2005 insertLine(R, 1, SCROLL_UP);
2006 }
2007
2008 C = 0;
2009 }
2010 else {
2011 // cursor stays on last wide character.
2012 C = columns - 2;
2013 }
2014 }
2015 }
2016
2017 if (insertmode == 1) {
2018 if (isWide) {
2019 insertChar(C++, R, c, attributes | FULLWIDTH);
2020 insertChar(C, R, ' ', attributes | FULLWIDTH);
2021 }
2022 else
2023 insertChar(C, R, c, attributes);
2024 }
2025 else {
2026 if (isWide) {
2027 putChar(C++, R, c, attributes | FULLWIDTH);
2028 putChar(C, R, ' ', attributes | FULLWIDTH);
2029 }
2030 else
2031 putChar(C, R, c, attributes);
2032 }
2033
2034 /*
2035 } else {
2036 if (insertmode==1) {
2037 insertChar(C, rows, c, attributes);
2038 } else {
2039 putChar(C, rows, c, attributes);
2040 }
2041 }
2042 */
2043 C++;
2044 break;
2045 }
2046 } /* switch(c) */
2047
2048 break;
2049
2050 case TSTATE_OSC:
2051 if ((c < 0x20) && (c != ESC)) {// NP - No printing character
2052 handle_osc(osc);
2053 term_state = TSTATE_DATA;
2054 break;
2055 }
2056
2057 //but check for vt102 ESC \
2058 if (c == '\\' && osc.charAt(osc.length() - 1) == ESC) {
2059 handle_osc(osc);
2060 term_state = TSTATE_DATA;
2061 break;
2062 }
2063
2064 osc = osc + c;
2065 break;
2066
2067 case TSTATE_ESCSPACE:
2068 term_state = TSTATE_DATA;
2069
2070 switch (c) {
2071 case 'F': /* S7C1T, Disable output of 8-bit controls, use 7-bit */
2072 output8bit = false;
2073 break;
2074
2075 case 'G': /* S8C1T, Enable output of 8-bit control codes*/
2076 output8bit = true;
2077 break;
2078
2079 default:
2080 debug("ESC <space> " + c + " unhandled.");
2081 }
2082
2083 break;
2084
2085 case TSTATE_ESC:
2086 term_state = TSTATE_DATA;
2087
2088 switch (c) {
2089 case ' ':
2090 term_state = TSTATE_ESCSPACE;
2091 break;
2092
2093 case '#':
2094 term_state = TSTATE_ESCSQUARE;
2095 break;
2096
2097 case 'c':
2098 /* Hard terminal reset */
2099 reset();
2100 break;
2101
2102 case '[':
2103 DCEvar = 0;
2104 DCEvars[0] = 0;
2105 DCEvars[1] = 0;
2106 DCEvars[2] = 0;
2107 DCEvars[3] = 0;
2108 term_state = TSTATE_CSI;
2109 break;
2110
2111 case ']':
2112 osc = "";
2113 term_state = TSTATE_OSC;
2114 break;
2115
2116 case 'P':
2117 dcs = "";
2118 term_state = TSTATE_DCS;
2119 break;
2120
2121 case 'A': /* CUU */
2122 R--;
2123
2124 if (R < 0) R = 0;
2125
2126 break;
2127
2128 case 'B': /* CUD */
2129 R++;
2130
2131 if (R >= rows) R = rows - 1;
2132
2133 break;
2134
2135 case 'C':
2136 C++;
2137
2138 if (C >= columns) C = columns - 1;
2139
2140 break;
2141
2142 case 'I': // RI
2143 insertLine(R, 1, SCROLL_DOWN);
2144 break;
2145
2146 case 'E': /* NEL */
2147 if (R == getBottomMargin() || R == rows - 1)
2148 insertLine(R, 1, SCROLL_UP);
2149 else
2150 R++;
2151
2152 C = 0;
2153
2154 if (debug > 1)
2155 debug("ESC E (at " + R + ")");
2156
2157 break;
2158
2159 case 'D': /* IND */
2160 if (R == getBottomMargin() || R == rows - 1)
2161 insertLine(R, 1, SCROLL_UP);
2162 else
2163 R++;
2164
2165 if (debug > 1)
2166 debug("ESC D (at " + R + " )");
2167
2168 break;
2169
2170 case 'J': /* erase to end of screen */
2171 if (R < rows - 1)
2172 deleteArea(0, R + 1, columns, rows - R - 1, attributes);
2173
2174 if (C < columns - 1)
2175 deleteArea(C, R, columns - C, 1, attributes);
2176
2177 break;
2178
2179 case 'K':
2180 if (C < columns - 1)
2181 deleteArea(C, R, columns - C, 1, attributes);
2182
2183 break;
2184
2185 case 'M': // RI
2186 debug("ESC M : R is " + R + ", tm is " + getTopMargin() + ", bm is " + getBottomMargin());
2187
2188 if (R > getTopMargin()) { // just go up 1 line.
2189 R--;
2190 }
2191 else { // scroll down
2192 insertLine(R, 1, SCROLL_DOWN);
2193 }
2194
2195 /* else do nothing ; */
2196 if (debug > 2)
2197 debug("ESC M ");
2198
2199 break;
2200
2201 case 'H':
2202 if (debug > 1)
2203 debug("ESC H at " + C);
2204
2205 /* right border probably ...*/
2206 if (C >= columns)
2207 C = columns - 1;
2208
2209 Tabs[C] = 1;
2210 break;
2211
2212 case 'N': // SS2
2213 onegl = 2;
2214 break;
2215
2216 case 'O': // SS3
2217 onegl = 3;
2218 break;
2219
2220 case '=':
2221
2222 /*application keypad*/
2223 if (debug > 0)
2224 debug("ESC =");
2225
2226 keypadmode = true;
2227 break;
2228
2229 case '<': /* vt52 mode off */
2230 vt52mode = false;
2231 break;
2232
2233 case '>': /*normal keypad*/
2234 if (debug > 0)
2235 debug("ESC >");
2236
2237 keypadmode = false;
2238 break;
2239
2240 case '7': /* DECSC: save cursor, attributes */
2241 Sc = C;
2242 Sr = R;
2243 Sgl = gl;
2244 Sgr = gr;
2245 Sa = attributes;
2246 Sgx = new char[4];
2247
2248 for (int i = 0; i < 4; i++) Sgx[i] = gx[i];
2249
2250 if (debug > 1)
2251 debug("ESC 7");
2252
2253 break;
2254
2255 case '8': /* DECRC: restore cursor, attributes */
2256 C = Sc;
2257 R = Sr;
2258 gl = Sgl;
2259 gr = Sgr;
2260
2261 if (Sgx != null)
2262 for (int i = 0; i < 4; i++) gx[i] = Sgx[i];
2263
2264 attributes = Sa;
2265
2266 if (debug > 1)
2267 debug("ESC 8");
2268
2269 break;
2270
2271 case '(': /* Designate G0 Character set (ISO 2022) */
2272 term_state = TSTATE_SETG0;
2273 usedcharsets = true;
2274 break;
2275
2276 case ')': /* Designate G1 character set (ISO 2022) */
2277 term_state = TSTATE_SETG1;
2278 usedcharsets = true;
2279 break;
2280
2281 case '*': /* Designate G2 Character set (ISO 2022) */
2282 term_state = TSTATE_SETG2;
2283 usedcharsets = true;
2284 break;
2285
2286 case '+': /* Designate G3 Character set (ISO 2022) */
2287 term_state = TSTATE_SETG3;
2288 usedcharsets = true;
2289 break;
2290
2291 case '~': /* Locking Shift 1, right */
2292 gr = 1;
2293 usedcharsets = true;
2294 break;
2295
2296 case 'n': /* Locking Shift 2 */
2297 gl = 2;
2298 usedcharsets = true;
2299 break;
2300
2301 case '}': /* Locking Shift 2, right */
2302 gr = 2;
2303 usedcharsets = true;
2304 break;
2305
2306 case 'o': /* Locking Shift 3 */
2307 gl = 3;
2308 usedcharsets = true;
2309 break;
2310
2311 case '|': /* Locking Shift 3, right */
2312 gr = 3;
2313 usedcharsets = true;
2314 break;
2315
2316 case 'Y': /* vt52 cursor address mode , next chars are x,y */
2317 term_state = TSTATE_VT52Y;
2318 break;
2319
2320 case '_':
2321 term_state = TSTATE_TITLE;
2322 break;
2323
2324 case '\\':
2325 // TODO save title
2326 term_state = TSTATE_DATA;
2327 break;
2328
2329 default:
2330 debug("ESC unknown letter: " + c + " (" + ((int) c) + ")");
2331 break;
2332 }
2333
2334 break;
2335
2336 case TSTATE_VT52X:
2337 C = c - 37;
2338
2339 if (C < 0)
2340 C = 0;
2341 else if (C >= width)
2342 C = width - 1;
2343
2344 term_state = TSTATE_VT52Y;
2345 break;
2346
2347 case TSTATE_VT52Y:
2348 R = c - 37;
2349
2350 if (R < 0)
2351 R = 0;
2352 else if (R >= height)
2353 R = height - 1;
2354
2355 term_state = TSTATE_DATA;
2356 break;
2357
2358 case TSTATE_SETG0:
2359 if (c != '0' && c != 'A' && c != 'B' && c != '<')
2360 debug("ESC ( " + c + ": G0 char set? (" + ((int) c) + ")");
2361 else {
2362 if (debug > 2) debug("ESC ( : G0 char set (" + c + " " + ((int) c) + ")");
2363
2364 gx[0] = c;
2365 }
2366
2367 term_state = TSTATE_DATA;
2368 break;
2369
2370 case TSTATE_SETG1:
2371 if (c != '0' && c != 'A' && c != 'B' && c != '<') {
2372 debug("ESC ) " + c + " (" + ((int) c) + ") :G1 char set?");
2373 }
2374 else {
2375 if (debug > 2) debug("ESC ) :G1 char set (" + c + " " + ((int) c) + ")");
2376
2377 gx[1] = c;
2378 }
2379
2380 term_state = TSTATE_DATA;
2381 break;
2382
2383 case TSTATE_SETG2:
2384 if (c != '0' && c != 'A' && c != 'B' && c != '<')
2385 debug("ESC*:G2 char set? (" + ((int) c) + ")");
2386 else {
2387 if (debug > 2) debug("ESC*:G2 char set (" + c + " " + ((int) c) + ")");
2388
2389 gx[2] = c;
2390 }
2391
2392 term_state = TSTATE_DATA;
2393 break;
2394
2395 case TSTATE_SETG3:
2396 if (c != '0' && c != 'A' && c != 'B' && c != '<')
2397 debug("ESC+:G3 char set? (" + ((int) c) + ")");
2398 else {
2399 if (debug > 2) debug("ESC+:G3 char set (" + c + " " + ((int) c) + ")");
2400
2401 gx[3] = c;
2402 }
2403
2404 term_state = TSTATE_DATA;
2405 break;
2406
2407 case TSTATE_ESCSQUARE:
2408 switch (c) {
2409 case '8':
2410 for (int i = 0; i < columns; i++)
2411 for (int j = 0; j < rows; j++)
2412 putChar(i, j, 'E', 0);
2413
2414 break;
2415
2416 default:
2417 debug("ESC # " + c + " not supported.");
2418 break;
2419 }
2420
2421 term_state = TSTATE_DATA;
2422 break;
2423
2424 case TSTATE_DCS:
2425 if (c == '\\' && dcs.charAt(dcs.length() - 1) == ESC) {
2426 handle_dcs(dcs);
2427 term_state = TSTATE_DATA;
2428 break;
2429 }
2430
2431 dcs = dcs + c;
2432 break;
2433
2434 case TSTATE_DCEQ:
2435 term_state = TSTATE_DATA;
2436
2437 switch (c) {
2438 case '0':
2439 case '1':
2440 case '2':
2441 case '3':
2442 case '4':
2443 case '5':
2444 case '6':
2445 case '7':
2446 case '8':
2447 case '9':
2448 DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
2449 term_state = TSTATE_DCEQ;
2450 break;
2451
2452 case ';':
2453 DCEvar++;
2454 DCEvars[DCEvar] = 0;
2455 term_state = TSTATE_DCEQ;
2456 break;
2457
2458 case 's': // XTERM_SAVE missing!
2459 if (true || debug > 1)
2460 debug("ESC [ ? " + DCEvars[0] + " s unimplemented!");
2461
2462 break;
2463
2464 case 'r': // XTERM_RESTORE
2465 if (true || debug > 1)
2466 debug("ESC [ ? " + DCEvars[0] + " r");
2467
2468 /* DEC Mode reset */
2469 for (int i = 0; i <= DCEvar; i++) {
2470 switch (DCEvars[i]) {
2471 case 3: /* 80 columns*/
2472 setScreenSize(80, height, true);
2473 break;
2474
2475 case 4: /* scrolling mode, smooth */
2476 break;
2477
2478 case 5: /* light background */
2479 break;
2480
2481 case 6: /* DECOM (Origin Mode) move inside margins. */
2482 moveoutsidemargins = true;
2483 break;
2484
2485 case 7: /* DECAWM: Autowrap Mode */
2486 wraparound = false;
2487 break;
2488
2489 case 12:/* local echo off */
2490 break;
2491
2492 case 9: /* X10 mouse */
2493 case 1000: /* xterm style mouse report on */
2494 case 1001:
2495 case 1002:
2496 case 1003:
2497 mouserpt = DCEvars[i];
2498 break;
2499
2500 default:
2501 debug("ESC [ ? " + DCEvars[0] + " r, unimplemented!");
2502 }
2503 }
2504
2505 break;
2506
2507 case 'h': // DECSET
2508 if (debug > 0)
2509 debug("ESC [ ? " + DCEvars[0] + " h");
2510
2511 /* DEC Mode set */
2512 for (int i = 0; i <= DCEvar; i++) {
2513 switch (DCEvars[i]) {
2514 case 1: /* Application cursor keys */
2515 KeyUp[0] = "\u001bOA";
2516 KeyDown[0] = "\u001bOB";
2517 KeyRight[0] = "\u001bOC";
2518 KeyLeft[0] = "\u001bOD";
2519 break;
2520
2521 case 2: /* DECANM */
2522 vt52mode = false;
2523 break;
2524
2525 case 3: /* 132 columns*/
2526 setScreenSize(132, height, true);
2527 break;
2528
2529 case 6: /* DECOM: move inside margins. */
2530 moveoutsidemargins = false;
2531 break;
2532
2533 case 7: /* DECAWM: Autowrap Mode */
2534 wraparound = true;
2535 break;
2536
2537 case 25: /* turn cursor on */
2538 showCursor(true);
2539 break;
2540
2541 case 9: /* X10 mouse */
2542 case 1000: /* xterm style mouse report on */
2543 case 1001:
2544 case 1002:
2545 case 1003:
2546 mouserpt = DCEvars[i];
2547 break;
2548
2549 /* unimplemented stuff, fall through */
2550 /* 4 - scrolling mode, smooth */
2551 /* 5 - light background */
2552 /* 12 - local echo off */
2553 /* 18 - DECPFF - Printer Form Feed Mode -> On */
2554 /* 19 - DECPEX - Printer Extent Mode -> Screen */
2555 default:
2556 debug("ESC [ ? " + DCEvars[0] + " h, unsupported.");
2557 break;
2558 }
2559 }
2560
2561 break;
2562
2563 case 'i': // DEC Printer Control, autoprint, echo screenchars to printer
2564
2565 // This is different to CSI i!
2566 // Also: "Autoprint prints a final display line only when the
2567 // cursor is moved off the line by an autowrap or LF, FF, or
2568 // VT (otherwise do not print the line)."
2569 switch (DCEvars[0]) {
2570 case 1:
2571 if (debug > 1)
2572 debug("CSI ? 1 i : Print line containing cursor");
2573
2574 break;
2575
2576 case 4:
2577 if (debug > 1)
2578 debug("CSI ? 4 i : Start passthrough printing");
2579
2580 break;
2581
2582 case 5:
2583 if (debug > 1)
2584 debug("CSI ? 4 i : Stop passthrough printing");
2585
2586 break;
2587 }
2588
2589 break;
2590
2591 case 'l': //DECRST
2592
2593 /* DEC Mode reset */
2594 if (debug > 0)
2595 debug("ESC [ ? " + DCEvars[0] + " l");
2596
2597 for (int i = 0; i <= DCEvar; i++) {
2598 switch (DCEvars[i]) {
2599 case 1: /* Application cursor keys */
2600 KeyUp[0] = "\u001b[A";
2601 KeyDown[0] = "\u001b[B";
2602 KeyRight[0] = "\u001b[C";
2603 KeyLeft[0] = "\u001b[D";
2604 break;
2605
2606 case 2: /* DECANM */
2607 vt52mode = true;
2608 break;
2609
2610 case 3: /* 80 columns*/
2611 setScreenSize(80, height, true);
2612 break;
2613
2614 case 6: /* DECOM: move outside margins. */
2615 moveoutsidemargins = true;
2616 break;
2617
2618 case 7: /* DECAWM: Autowrap Mode OFF */
2619 wraparound = false;
2620 break;
2621
2622 case 25: /* turn cursor off */
2623 showCursor(false);
2624 break;
2625
2626 /* Unimplemented stuff: */
2627 /* 4 - scrolling mode, jump */
2628 /* 5 - dark background */
2629 /* 7 - DECAWM - no wrap around mode */
2630 /* 12 - local echo on */
2631 /* 18 - DECPFF - Printer Form Feed Mode -> Off*/
2632 /* 19 - DECPEX - Printer Extent Mode -> Scrolling Region */
2633 case 9: /* X10 mouse */
2634 case 1000: /* xterm style mouse report OFF */
2635 case 1001:
2636 case 1002:
2637 case 1003:
2638 mouserpt = 0;
2639 break;
2640
2641 default:
2642 debug("ESC [ ? " + DCEvars[0] + " l, unsupported.");
2643 break;
2644 }
2645 }
2646
2647 break;
2648
2649 case 'n':
2650 if (debug > 0)
2651 debug("ESC [ ? " + DCEvars[0] + " n");
2652
2653 switch (DCEvars[0]) {
2654 case 15:
2655 /* printer? no printer. */
2656 write((ESC) + "[?13n", false);
2657 debug("ESC[5n");
2658 break;
2659
2660 default:
2661 debug("ESC [ ? " + DCEvars[0] + " n, unsupported.");
2662 break;
2663 }
2664
2665 break;
2666
2667 default:
2668 debug("ESC [ ? " + DCEvars[0] + " " + c + ", unsupported.");
2669 break;
2670 }
2671
2672 break;
2673
2674 case TSTATE_CSI_EX:
2675 term_state = TSTATE_DATA;
2676
2677 switch (c) {
2678 case ESC:
2679 term_state = TSTATE_ESC;
2680 break;
2681
2682 default:
2683 debug("Unknown character ESC[! character is " + (int) c);
2684 break;
2685 }
2686
2687 break;
2688
2689 case TSTATE_CSI_TICKS:
2690 term_state = TSTATE_DATA;
2691
2692 switch (c) {
2693 case 'p':
2694 debug("Conformance level: " + DCEvars[0] + " (unsupported)," + DCEvars[1]);
2695
2696 if (DCEvars[0] == 61) {
2697 output8bit = false;
2698 break;
2699 }
2700
2701 if (DCEvars[1] == 1) {
2702 output8bit = false;
2703 }
2704 else {
2705 output8bit = true; /* 0 or 2 */
2706 }
2707
2708 break;
2709
2710 default:
2711 debug("Unknown ESC [... \"" + c);
2712 break;
2713 }
2714
2715 break;
2716
2717 case TSTATE_CSI_EQUAL:
2718 term_state = TSTATE_DATA;
2719
2720 switch (c) {
2721 case '0':
2722 case '1':
2723 case '2':
2724 case '3':
2725 case '4':
2726 case '5':
2727 case '6':
2728 case '7':
2729 case '8':
2730 case '9':
2731 DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
2732 term_state = TSTATE_CSI_EQUAL;
2733 break;
2734
2735 case ';':
2736 DCEvar++;
2737 DCEvars[DCEvar] = 0;
2738 term_state = TSTATE_CSI_EQUAL;
2739 break;
2740
2741 case 'F': { /* SCO ANSI foreground */
2742 int newcolor;
2743 debug("ESC [ = " + DCEvars[0] + " F");
2744 attributes &= ~COLOR_FG;
2745 newcolor = ((DCEvars[0] & 1) << 2) |
2746 (DCEvars[0] & 2) |
2747 ((DCEvars[0] & 4) >> 2) ;
2748 attributes |= (newcolor + 1) << COLOR_FG_SHIFT;
2749 break;
2750 }
2751
2752 case 'G': { /* SCO ANSI background */
2753 int newcolor;
2754 debug("ESC [ = " + DCEvars[0] + " G");
2755 attributes &= ~COLOR_BG;
2756 newcolor = ((DCEvars[0] & 1) << 2) |
2757 (DCEvars[0] & 2) |
2758 ((DCEvars[0] & 4) >> 2) ;
2759 attributes |= (newcolor + 1) << COLOR_BG_SHIFT;
2760 break;
2761 }
2762
2763 default:
2764 debugStr.append("Unknown ESC [ = ");
2765
2766 for (int i = 0; i <= DCEvar; i++) {
2767 debugStr.append(DCEvars[i])
2768 .append(',');
2769 }
2770
2771 debugStr.append(c);
2772 debug(debugStr.toString());
2773 debugStr.setLength(0);
2774 break;
2775 }
2776
2777 break;
2778
2779 case TSTATE_CSI_DOLLAR:
2780 term_state = TSTATE_DATA;
2781
2782 switch (c) {
2783 case '}':
2784 debug("Active Status Display now " + DCEvars[0]);
2785 statusmode = DCEvars[0];
2786 break;
2787
2788 /* bad documentation?
2789 case '-':
2790 debug("Set Status Display now "+DCEvars[0]);
2791 break;
2792 */
2793 case '~':
2794 debug("Status Line mode now " + DCEvars[0]);
2795 break;
2796
2797 default:
2798 debug("UNKNOWN Status Display code " + c + ", with Pn=" + DCEvars[0]);
2799 break;
2800 }
2801
2802 break;
2803
2804 case TSTATE_CSI:
2805 term_state = TSTATE_DATA;
2806
2807 switch (c) {
2808 case '"':
2809 term_state = TSTATE_CSI_TICKS;
2810 break;
2811
2812 case '$':
2813 term_state = TSTATE_CSI_DOLLAR;
2814 break;
2815
2816 case '=':
2817 term_state = TSTATE_CSI_EQUAL;
2818 break;
2819
2820 case '!':
2821 term_state = TSTATE_CSI_EX;
2822 break;
2823
2824 case '?':
2825 DCEvar = 0;
2826 DCEvars[0] = 0;
2827 term_state = TSTATE_DCEQ;
2828 break;
2829
2830 case '0':
2831 case '1':
2832 case '2':
2833 case '3':
2834 case '4':
2835 case '5':
2836 case '6':
2837 case '7':
2838 case '8':
2839 case '9':
2840 DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
2841 term_state = TSTATE_CSI;
2842 break;
2843
2844 case ';':
2845 DCEvar++;
2846 DCEvars[DCEvar] = 0;
2847 term_state = TSTATE_CSI;
2848 break;
2849
2850 case 'c':/* send primary device attributes */
2851 /* send (ESC[?61c) */
2852 String subcode = "";
2853
2854 if (terminalID.equals("vt320")) subcode = "63;";
2855
2856 if (terminalID.equals("vt220")) subcode = "62;";
2857
2858 if (terminalID.equals("vt100")) subcode = "61;";
2859
2860 write((ESC) + "[?" + subcode + "1;2c", false);
2861
2862 if (debug > 1)
2863 debug("ESC [ " + DCEvars[0] + " c");
2864
2865 break;
2866
2867 case 'q':
2868 if (debug > 1)
2869 debug("ESC [ " + DCEvars[0] + " q");
2870
2871 break;
2872
2873 case 'g':
2874
2875 /* used for tabsets */
2876 switch (DCEvars[0]) {
2877 case 3:/* clear them */
2878 Tabs = new byte[width];
2879 break;
2880
2881 case 0:
2882 Tabs[C] = 0;
2883 break;
2884 }
2885
2886 if (debug > 1)
2887 debug("ESC [ " + DCEvars[0] + " g");
2888
2889 break;
2890
2891 case 'h':
2892 switch (DCEvars[0]) {
2893 case 4:
2894 insertmode = 1;
2895 break;
2896
2897 case 20:
2898 debug("Setting CRLF to TRUE");
2899 sendcrlf = true;
2900 break;
2901
2902 default:
2903 debug("unsupported: ESC [ " + DCEvars[0] + " h");
2904 break;
2905 }
2906
2907 if (debug > 1)
2908 debug("ESC [ " + DCEvars[0] + " h");
2909
2910 break;
2911
2912 case 'i': // Printer Controller mode.
2913
2914 // "Transparent printing sends all output, except the CSI 4 i
2915 // termination string, to the printer and not the screen,
2916 // uses an 8-bit channel if no parity so NUL and DEL will be
2917 // seen by the printer and by the termination recognizer code,
2918 // and all translation and character set selections are
2919 // bypassed."
2920 switch (DCEvars[0]) {
2921 case 0:
2922 if (debug > 1)
2923 debug("CSI 0 i: Print Screen, not implemented.");
2924
2925 break;
2926
2927 case 4:
2928 if (debug > 1)
2929 debug("CSI 4 i: Enable Transparent Printing, not implemented.");
2930
2931 break;
2932
2933 case 5:
2934 if (debug > 1)
2935 debug("CSI 4/5 i: Disable Transparent Printing, not implemented.");
2936
2937 break;
2938
2939 default:
2940 debug("ESC [ " + DCEvars[0] + " i, unimplemented!");
2941 }
2942
2943 break;
2944
2945 case 'l':
2946 switch (DCEvars[0]) {
2947 case 4:
2948 insertmode = 0;
2949 break;
2950
2951 case 20:
2952 debug("Setting CRLF to FALSE");
2953 sendcrlf = false;
2954 break;
2955
2956 default:
2957 debug("ESC [ " + DCEvars[0] + " l, unimplemented!");
2958 break;
2959 }
2960
2961 break;
2962
2963 case 'A': { // CUU
2964 int limit;
2965
2966 /* FIXME: xterm only cares about 0 and topmargin */
2967 if (R >= getTopMargin()) {
2968 limit = getTopMargin();
2969 }
2970 else
2971 limit = 0;
2972
2973 if (DCEvars[0] == 0)
2974 R--;
2975 else
2976 R -= DCEvars[0];
2977
2978 if (R < limit)
2979 R = limit;
2980
2981 if (debug > 1)
2982 debug("ESC [ " + DCEvars[0] + " A");
2983
2984 break;
2985 }
2986
2987 case 'B': // CUD
2988 /* cursor down n (1) times */
2989 {
2990 int limit;
2991
2992 if (R <= getBottomMargin()) {
2993 limit = getBottomMargin();
2994 }
2995 else
2996 limit = rows - 1;
2997
2998 if (DCEvars[0] == 0)
2999 R++;
3000 else
3001 R += DCEvars[0];
3002
3003 if (R > limit)
3004 R = limit;
3005 else {
3006 if (debug > 2) debug("Not limited.");
3007 }
3008
3009 if (debug > 2) debug("to: " + R);
3010
3011 if (debug > 1)
3012 debug("ESC [ " + DCEvars[0] + " B (at C=" + C + ")");
3013
3014 break;
3015 }
3016
3017 case 'C':
3018 if (DCEvars[0] == 0)
3019 DCEvars[0] = 1;
3020
3021 while (DCEvars[0]-- > 0) {
3022 C++;
3023 }
3024
3025 if (C >= columns)
3026 C = columns - 1;
3027
3028 if (debug > 1)
3029 debug("ESC [ " + DCEvars[0] + " C");
3030
3031 break;
3032
3033 case 'd': // CVA
3034 R = DCEvars[0] - 1;
3035
3036 if (R < 0)
3037 R = 0;
3038 else if (R >= height)
3039 R = height - 1;
3040
3041 if (debug > 1)
3042 debug("ESC [ " + DCEvars[0] + " d");
3043
3044 break;
3045
3046 case 'D':
3047 if (DCEvars[0] == 0)
3048 DCEvars[0] = 1;
3049
3050 while (DCEvars[0]-- > 0) {
3051 C--;
3052 }
3053
3054 if (C < 0) C = 0;
3055
3056 if (debug > 1)
3057 debug("ESC [ " + DCEvars[0] + " D");
3058
3059 break;
3060
3061 case 'r': // DECSTBM
3062 if (DCEvar > 0) { // Ray: Any argument is optional
3063 R = DCEvars[1] - 1;
3064
3065 if (R < 0)
3066 R = rows - 1;
3067 else if (R >= rows) {
3068 R = rows - 1;
3069 }
3070 }
3071 else
3072 R = rows - 1;
3073
3074 int bot = R;
3075
3076 if (R >= DCEvars[0]) {
3077 R = DCEvars[0] - 1;
3078
3079 if (R < 0)
3080 R = 0;
3081 }
3082
3083 setMargins(R, bot);
3084 _SetCursor(0, 0);
3085
3086 if (debug > 1)
3087 debug("ESC [" + DCEvars[0] + " ; " + DCEvars[1] + " r");
3088
3089 break;
3090
3091 case 'G': /* CUP / cursor absolute column */
3092 C = DCEvars[0];
3093
3094 if (C < 0)
3095 C = 0;
3096 else if (C >= width)
3097 C = width - 1;
3098
3099 if (debug > 1) debug("ESC [ " + DCEvars[0] + " G");
3100
3101 break;
3102
3103 case 'H': /* CUP / cursor position */
3104 /* gets 2 arguments */
3105 _SetCursor(DCEvars[0] - 1, DCEvars[1] - 1);
3106
3107 if (debug > 2) {
3108 debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " H, moveoutsidemargins " + moveoutsidemargins);
3109 debug(" -> R now " + R + ", C now " + C);
3110 }
3111
3112 break;
3113
3114 case 'f': /* move cursor 2 */
3115 /* gets 2 arguments */
3116 R = DCEvars[0] - 1;
3117 C = DCEvars[1] - 1;
3118
3119 if (C < 0)
3120 C = 0;
3121 else if (C >= width)
3122 C = width - 1;
3123
3124 if (R < 0)
3125 R = 0;
3126 else if (R >= height)
3127 R = height - 1;
3128
3129 if (debug > 2)
3130 debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " f");
3131
3132 break;
3133
3134 case 'S': /* ind aka 'scroll forward' */
3135 if (DCEvars[0] == 0)
3136 insertLine(getBottomMargin(), SCROLL_UP);
3137 else
3138 insertLine(getBottomMargin(), DCEvars[0], SCROLL_UP);
3139
3140 break;
3141
3142 case 'L':
3143
3144 /* insert n lines */
3145 if (DCEvars[0] == 0)
3146 insertLine(R, SCROLL_DOWN);
3147 else
3148 insertLine(R, DCEvars[0], SCROLL_DOWN);
3149
3150 if (debug > 1)
3151 debug("ESC [ " + DCEvars[0] + "" + (c) + " (at R " + R + ")");
3152
3153 break;
3154
3155 case 'T': /* 'ri' aka scroll backward */
3156 if (DCEvars[0] == 0)
3157 insertLine(getTopMargin(), SCROLL_DOWN);
3158 else
3159 insertLine(getTopMargin(), DCEvars[0], SCROLL_DOWN);
3160
3161 break;
3162
3163 case 'M':
3164 if (debug > 1)
3165 debug("ESC [ " + DCEvars[0] + "" + (c) + " at R=" + R);
3166
3167 if (DCEvars[0] == 0)
3168 deleteLine(R);
3169 else
3170 for (int i = 0; i < DCEvars[0]; i++)
3171 deleteLine(R);
3172
3173 break;
3174
3175 case 'K':
3176 if (debug > 1)
3177 debug("ESC [ " + DCEvars[0] + " K");
3178
3179 /* clear in line */
3180 switch (DCEvars[0]) {
3181 case 6: /* 97801 uses ESC[6K for delete to end of line */
3182 case 0:/*clear to right*/
3183 if (C < columns - 1)
3184 deleteArea(C, R, columns - C, 1, attributes);
3185
3186 break;
3187
3188 case 1:/*clear to the left, including this */
3189 if (C > 0)
3190 deleteArea(0, R, C + 1, 1, attributes);
3191
3192 break;
3193
3194 case 2:/*clear whole line */
3195 deleteArea(0, R, columns, 1, attributes);
3196 break;
3197 }
3198
3199 break;
3200
3201 case 'J':
3202
3203 /* clear below current line */
3204 switch (DCEvars[0]) {
3205 case 0:
3206 if (R < rows - 1)
3207 deleteArea(0, R + 1, columns, rows - R - 1, attributes);
3208
3209 if (C < columns - 1)
3210 deleteArea(C, R, columns - C, 1, attributes);
3211
3212 break;
3213
3214 case 1:
3215 if (R > 0)
3216 deleteArea(0, 0, columns, R, attributes);
3217
3218 if (C > 0)
3219 deleteArea(0, R, C + 1, 1, attributes); // include up to and including current
3220
3221 break;
3222
3223 case 2:
3224 deleteArea(0, 0, columns, rows, attributes);
3225 break;
3226 }
3227
3228 if (debug > 1)
3229 debug("ESC [ " + DCEvars[0] + " J");
3230
3231 break;
3232
3233 case '@':
3234 if (DCEvars[0] == 0) DCEvars[0] = 1;
3235
3236 if (debug > 1)
3237 debug("ESC [ " + DCEvars[0] + " @");
3238
3239 for (int i = 0; i < DCEvars[0]; i++)
3240 insertChar(C, R, ' ', attributes);
3241
3242 break;
3243
3244 case 'X': {
3245 int toerase = DCEvars[0];
3246
3247 if (debug > 1)
3248 debug("ESC [ " + DCEvars[0] + " X, C=" + C + ",R=" + R);
3249
3250 if (toerase == 0)
3251 toerase = 1;
3252
3253 if (toerase + C > columns)
3254 toerase = columns - C;
3255
3256 deleteArea(C, R, toerase, 1, attributes);
3257 // does not change cursor position
3258 break;
3259 }
3260
3261 case 'P':
3262 if (debug > 1)
3263 debug("ESC [ " + DCEvars[0] + " P, C=" + C + ",R=" + R);
3264
3265 if (DCEvars[0] == 0) DCEvars[0] = 1;
3266
3267 for (int i = 0; i < DCEvars[0]; i++)
3268 deleteChar(C, R);
3269
3270 break;
3271
3272 case 'n':
3273 switch (DCEvars[0]) {
3274 case 5: /* malfunction? No malfunction. */
3275 writeSpecial((ESC) + "[0n");
3276
3277 if (debug > 1)
3278 debug("ESC[5n");
3279
3280 break;
3281
3282 case 6:
3283 // DO NOT offset R and C by 1! (checked against /usr/X11R6/bin/resize
3284 // FIXME check again.
3285 // FIXME: but vttest thinks different???
3286 writeSpecial((ESC) + "[" + R + ";" + C + "R");
3287
3288 if (debug > 1)
3289 debug("ESC[6n");
3290
3291 break;
3292
3293 default:
3294 if (debug > 0)
3295 debug("ESC [ " + DCEvars[0] + " n??");
3296
3297 break;
3298 }
3299
3300 break;
3301
3302 case 's': /* DECSC - save cursor */
3303 Sc = C;
3304 Sr = R;
3305 Sa = attributes;
3306
3307 if (debug > 3)
3308 debug("ESC[s");
3309
3310 break;
3311
3312 case 'u': /* DECRC - restore cursor */
3313 C = Sc;
3314 R = Sr;
3315 attributes = Sa;
3316
3317 if (debug > 3)
3318 debug("ESC[u");
3319
3320 break;
3321
3322 case 'm': /* attributes as color, bold , blink,*/
3323 if (debug > 3)
3324 debug("ESC [ ");
3325
3326 if (DCEvar == 0 && DCEvars[0] == 0)
3327 attributes = 0;
3328
3329 for (int i = 0; i <= DCEvar; i++) {
3330 switch (DCEvars[i]) {
3331 case 0:
3332 if (DCEvar > 0) {
3333 if (terminalID.equals("scoansi")) {
3334 attributes &= COLOR; /* Keeps color. Strange but true. */
3335 }
3336 else {
3337 attributes = 0;
3338 }
3339 }
3340
3341 break;
3342
3343 case 1:
3344 attributes |= BOLD;
3345 attributes &= ~LOW;
3346 break;
3347
3348 case 2:
3349
3350 /* SCO color hack mode */
3351 if (terminalID.equals("scoansi") && ((DCEvar - i) >= 2)) {
3352 int ncolor;
3353 attributes &= ~(COLOR | BOLD);
3354 ncolor = DCEvars[i + 1];
3355
3356 if ((ncolor & 8) == 8)
3357 attributes |= BOLD;
3358
3359 ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
3360 attributes |= ((ncolor) + 1) << COLOR_FG_SHIFT;
3361 ncolor = DCEvars[i + 2];
3362 ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
3363 attributes |= ((ncolor) + 1) << COLOR_BG_SHIFT;
3364 i += 2;
3365 }
3366 else {
3367 attributes |= LOW;
3368 }
3369
3370 break;
3371
3372 case 3: /* italics */
3373 attributes |= INVERT;
3374 break;
3375
3376 case 4:
3377 attributes |= UNDERLINE;
3378 break;
3379
3380 case 7:
3381 attributes |= INVERT;
3382 break;
3383
3384 case 8:
3385 attributes |= INVISIBLE;
3386 break;
3387
3388 case 5: /* blink on */
3389 break;
3390
3391 /* 10 - ANSI X3.64-1979, select primary font, don't display control
3392 * chars, don't set bit 8 on output */
3393 case 10:
3394 gl = 0;
3395 usedcharsets = true;
3396 break;
3397
3398 /* 11 - ANSI X3.64-1979, select second alt. font, display control
3399 * chars, set bit 8 on output */
3400 case 11: /* SMACS , as */
3401 case 12:
3402 gl = 1;
3403 usedcharsets = true;
3404 break;
3405
3406 case 21: /* normal intensity */
3407 attributes &= ~(LOW | BOLD);
3408 break;
3409
3410 case 23: /* italics off */
3411 attributes &= ~INVERT;
3412 break;
3413
3414 case 25: /* blinking off */
3415 break;
3416
3417 case 27:
3418 attributes &= ~INVERT;
3419 break;
3420
3421 case 28:
3422 attributes &= ~INVISIBLE;
3423 break;
3424
3425 case 24:
3426 attributes &= ~UNDERLINE;
3427 break;
3428
3429 case 22:
3430 attributes &= ~BOLD;
3431 break;
3432
3433 case 30:
3434 case 31:
3435 case 32:
3436 case 33:
3437 case 34:
3438 case 35:
3439 case 36:
3440 case 37:
3441 attributes &= ~COLOR_FG;
3442 attributes |= ((DCEvars[i] - 30) + 1) << COLOR_FG_SHIFT;
3443 break;
3444
3445 case 38:
3446 if (DCEvars[i + 1] == 5) {
3447 attributes &= ~COLOR_FG;
3448 attributes |= ((DCEvars[i + 2]) + 1) << COLOR_FG_SHIFT;
3449 i += 2;
3450 }
3451
3452 break;
3453
3454 case 39:
3455 attributes &= ~COLOR_FG;
3456 break;
3457
3458 case 40:
3459 case 41:
3460 case 42:
3461 case 43:
3462 case 44:
3463 case 45:
3464 case 46:
3465 case 47:
3466 attributes &= ~COLOR_BG;
3467 attributes |= ((DCEvars[i] - 40) + 1) << COLOR_BG_SHIFT;
3468 break;
3469
3470 case 48:
3471 if (DCEvars[i + 1] == 5) {
3472 attributes &= ~COLOR_BG;
3473 attributes |= (DCEvars[i + 2] + 1) << COLOR_BG_SHIFT;
3474 i += 2;
3475 }
3476
3477 break;
3478
3479 case 49:
3480 attributes &= ~COLOR_BG;
3481 break;
3482
3483 case 90:
3484 case 91:
3485 case 92:
3486 case 93:
3487 case 94:
3488 case 95:
3489 case 96:
3490 case 97:
3491 attributes &= ~COLOR_FG;
3492 attributes |= ((DCEvars[i] - 82) + 1) << COLOR_FG_SHIFT;
3493 break;
3494
3495 case 100:
3496 case 101:
3497 case 102:
3498 case 103:
3499 case 104:
3500 case 105:
3501 case 106:
3502 case 107:
3503 attributes &= ~COLOR_BG;
3504 attributes |= ((DCEvars[i] - 92) + 1) << COLOR_BG_SHIFT;
3505 break;
3506
3507 default:
3508 debugStr.append("ESC [ ")
3509 .append(DCEvars[i])
3510 .append(" m unknown...");
3511 debug(debugStr.toString());
3512 debugStr.setLength(0);
3513 break;
3514 }
3515
3516 if (debug > 3) {
3517 debugStr.append(DCEvars[i])
3518 .append(';');
3519 debug(debugStr.toString());
3520 debugStr.setLength(0);
3521 }
3522 }
3523
3524 if (debug > 3) {
3525 debugStr.append(" (attributes = ")
3526 .append(attributes)
3527 .append(")m");
3528 debug(debugStr.toString());
3529 debugStr.setLength(0);
3530 }
3531
3532 break;
3533
3534 default:
3535 debugStr.append("ESC [ unknown letter: ")
3536 .append(c)
3537 .append(" (")
3538 .append((int)c)
3539 .append(')');
3540 debug(debugStr.toString());
3541 debugStr.setLength(0);
3542 break;
3543 }
3544
3545 break;
3546
3547 case TSTATE_TITLE:
3548 switch (c) {
3549 case ESC:
3550 term_state = TSTATE_ESC;
3551 break;
3552
3553 default:
3554 // TODO save title
3555 break;
3556 }
3557
3558 break;
3559
3560 default:
3561 term_state = TSTATE_DATA;
3562 break;
3563 }
3564
3565 setCursorPosition(C, R);
3566 }
3567
3568 /* hard reset the terminal */
3569 public void reset() {
3570 gx[0] = 'B';
3571 gx[1] = 'B';
3572 gx[2] = 'B';
3573 gx[3] = 'B';
3574 gl = 0; // default GL to G0
3575 gr = 2; // default GR to G2
3576 onegl = -1; // Single shift override
3577 /* reset tabs */
3578 int nw = width;
3579
3580 if (nw < 132) nw = 132;
3581
3582 Tabs = new byte[nw];
3583
3584 for (int i = 0; i < nw; i += 8) {
3585 Tabs[i] = 1;
3586 }
3587
3588 deleteArea(0, 0, width, height, attributes);
3589 setMargins(0, height);
3590 C = R = 0;
3591 _SetCursor(0, 0);
3592
3593 if (display != null)
3594 display.resetColors();
3595
3596 showCursor(true);
3597 /*FIXME:*/
3598 term_state = TSTATE_DATA;
3599 }
3600 }