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