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