1 package telnet; 2 3 import javax.microedition.lcdui.*; 4 import javax.microedition.rms.*; 5 import java.io.*; 6 7 /* This file is part of "Telnet Floyd". 8 * 9 * (c) Radek Polak 2003-2004. All Rights Reserved. 10 * 11 * Please visit project homepage at http://phoenix.inf.upol.cz/~polakr 12 * 13 * --LICENSE NOTICE-- 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * as published by the Free Software Foundation; either version 2 17 * of the License, or (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program; if not, write to the Free Software 26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 27 * --LICENSE NOTICE-- 28 * 29 */ 30 31 /** 32 * Class that acts as terminal. It can basicly draw input from emulation (see 33 * variable "buffer"), execute and store actions defined by user. 34 */ 35 36 public class MidletTerminal 37 extends Canvas 38 implements CommandListener { 39 40 /** the VDU buffer */ 41 private vt320 buffer; 42 43 /** first top and left character in buffer, that is displayed */ 44 private int top, left; 45 46 /** display size in characters */ 47 public int rows, cols; 48 49 private Image backingStore = null; 50 51 private DrawFont font; 52 53 public int fgcolor = 0x000000; 54 public int bgcolor = 0xffffff; 55 56 /** A list of colors used for representation of the display */ 57 private int color[] = { 58 0x000000, 59 0xff0000, 60 0x00ff00, 61 0xffff00, // yellow 62 0x0000ff, // blue 63 0x00ffff, // magenta 64 0x00ffff, // cyan 65 0xffffff, // white 66 0xffffff, // bold color 67 0xffffff, // inverted color 68 }; 69 70 public final static int COLOR_INVERT = 9; 71 72 public java.util.Hashtable bindings = new java.util.Hashtable(); 73 74 public MidletTerminal(vt320 buffer) { 75 76 this.buffer = buffer; 77 78 if (Telnet.useColors) { 79 fgcolor = 0xffffff; 80 bgcolor = 0x000000; 81 } 82 83 font = new DrawFont(); 84 backingStore = Image.createImage(this.getWidth(), this.getHeight()); 85 86 cols = this.getWidth() / font.width; 87 rows = this.getHeight() / font.height; 88 89 buffer.setScreenSize(cols, rows); 90 91 top = 0; 92 left = 0; 93 94 loadBindings(); 95 displayHelp(); 96 } 97 98 public void commandAction(Command command, Displayable displayable) { 99 Telnet.setDisplay(new SelectFunctionDlg()); 100 } 101 102 protected void keyPressed(int keycode) { 103 104 keycode += 64; 105 Object o = bindings.get(new Integer(keycode)); 106 if (o == null) { 107 Telnet.setDisplay(new SelectFunctionDlg()); 108 return; 109 } 110 Action action = (Action) o; 111 112 int arg0 = 0; 113 int arg1 = 0; 114 int arg2 = 0; 115 try { 116 arg0 = Integer.parseInt(action.arg0); 117 } 118 catch (Exception e) {} 119 try { 120 arg1 = Integer.parseInt(action.arg1); 121 } 122 catch (Exception e) {} 123 try { 124 arg2 = Integer.parseInt(action.arg2); 125 } 126 catch (Exception e) {} 127 128 switch (action.funct.hashCode()) { 129 case Action.INPUT_DIALOG_HASH: 130 InputDialog inputDlg = new InputDialog(); 131 inputDlg.setString(action.arg0); 132 Telnet.setDisplay(inputDlg); 133 break; 134 case Action.SHOW_HELP_HASH: 135 displayHelp(); 136 break; 137 case Action.SCROLL_LEFT_HASH: 138 if (left >= arg0) // arg0 is horizontal step here 139 left -= arg0; 140 else 141 left = 0; 142 redraw(); 143 break; 144 case Action.SCROLL_RIGH_HASH: 145 if ( (left + arg0 + cols) <= buffer.width) 146 left += arg0; 147 else 148 left = buffer.width - cols; 149 redraw(); 150 break; 151 case Action.SCROLL_UP_HASH: 152 if (top >= arg0) // arg0 is vertical step here 153 top -= arg0; 154 else 155 top = 0; 156 redraw(); 157 break; 158 case Action.SCROLL_DOWN_HASH: 159 if ( (top + arg0 + rows) < buffer.height) 160 top += arg0; 161 else 162 top = buffer.height - rows; 163 redraw(); 164 break; 165 case Action.TYPE_STRING_HASH: 166 String str = action.arg0; 167 for (int i = 0; i < str.length(); i++) 168 Telnet.emulation.keyTyped(0, str.charAt(i), 0); 169 break; 170 case Action.ENTER_STRING_HASH: 171 str = action.arg0; 172 for (int i = 0; i < str.length(); i++) 173 Telnet.emulation.keyTyped(0, str.charAt(i), 0); 174 Telnet.emulation.keyTyped(0, '\n', 0); 175 break; 176 case Action.KEY_PRESSED_HASH: 177 Telnet.emulation.keyPressed(arg0, (char) arg1, arg2); 178 break; 179 case Action.KEY_TYPED_HASH: 180 if (action.arg2.length() != 0) // key indentified by 3 integer codes 181 Telnet.emulation.keyTyped(arg0, (char) arg1, arg2); 182 else { 183 char keyChar = (char) (action.arg0.charAt(action.arg0.length() - 1) - 184 'a' + 1); 185 if (action.arg0.equals("tab")) 186 Telnet.emulation.keyTyped(0, '\t', 0); 187 else 188 Telnet.emulation.keyTyped(0, keyChar, getModifiers(action.arg0)); // key identified by specific string (CTRL+x) 189 } 190 break; 191 case Action.SET_SCREEN_SIZE_HASH: 192 Telnet.emulation.setScreenSize(arg0, arg1); 193 break; 194 case Action.CONNECT_HASH: 195 Telnet.host = action.arg0; 196 Telnet.sshIO.login = action.arg1; 197 Telnet.sshIO.password = action.arg2; 198 Telnet.reader.start(); 199 break; 200 case Action.TRAFFIC_HASH: 201 Telnet.console.append(Telnet.traffic / 1024 + "kb" ); 202 Telnet.setDisplay(Telnet.console); 203 break; 204 case Action.BG_COLOR_HASH: 205 bgcolor = arg2 | (arg1 << 8) | (arg0 << 16); 206 redraw(); 207 break; 208 case Action.FG_COLOR_HASH: 209 fgcolor = arg2 | (arg1 << 8) | (arg0 << 16); 210 redraw(); 211 break; 212 case Action.VIEW_CONSOLE_HASH: 213 Telnet.setDisplay(Telnet.console); 214 break; 215 case Action.SET_SCOLLBACK_SIZE_HASH: 216 buffer.setBufferSize(arg0); 217 break; 218 case Action.SCOLLBACK_UP_HASH: 219 buffer.setWindowBase(buffer.getWindowBase() - arg0); 220 break; 221 case Action.SCOLLBACK_DOWN_HASH: 222 buffer.setWindowBase(buffer.getWindowBase() + arg0); 223 break; 224 case Action.SHOW_TERMINAL_SIZE_HASH: 225 Telnet.emulation.putString(buffer.width + "x" + buffer.height); 226 redraw(); 227 break; 228 case Action.SET_SLEEP_TIME_HASH: 229 Telnet.sleepTime = arg0; 230 break; 231 case Action.KEEP_CONNECTION_TIME_HASH: 232 Telnet.keepAliveCycles = (1000 * arg0) / Telnet.sleepTime; 233 break; 234 case Action.EXIT_APP_HASH: 235 Telnet.quitApp(); 236 break; 237 } 238 } 239 240 /** 241 * Create a color representation that is brighter than the standard 242 * color but not what we would like to use for bold characters. 243 * @param clr the standard color 244 * @return the new brighter color 245 */ 246 private int brighten(int color) { 247 int r = (color & 0xff0000) >> 16; 248 int g = (color & 0x00ff00) >> 8; 249 int b = (color & 0x0000ff); 250 251 r *= 12; 252 r /= 10; 253 if (r > 255) { 254 r = 255; 255 } 256 g *= 12; 257 g /= 10; 258 if (g > 255) { 259 g = 255; 260 } 261 b *= 12; 262 b /= 10; 263 if (b > 255) { 264 b = 255; 265 } 266 return b | (g << 8) | (r << 16); 267 } 268 269 /** 270 * Create a color representation that is darker than the standard 271 * color but not what we would like to use for bold characters. 272 * @param clr the standard color 273 * @return the new darker color 274 */ 275 private int darken(int color) { 276 int r = (color & 0xff0000) >> 16; 277 int g = (color & 0x00ff00) >> 8; 278 int b = (color & 0x0000ff); 279 280 r *= 8; 281 r /= 10; 282 g *= 8; 283 g /= 10; 284 b *= 8; 285 b /= 10; 286 return b | (g << 8) | (r << 16); 287 } 288 289 /** Required paint implementation */ 290 protected void paint(Graphics g) { 291 g.drawImage(backingStore, 0, 0, 0); 292 } 293 294 public void redraw() { 295 296 Graphics g = backingStore.getGraphics(); 297 298 for (int l = top; l < buffer.height && l < (top + rows); l++) { 299 if (!buffer.update[0] && !buffer.update[l + 1]) { 300 continue; 301 } 302 buffer.update[l + 1] = false; 303 for (int c = left; c < buffer.width && c < (left + cols); c++) { 304 int addr = 0; 305 int currAttr = buffer.charAttributes[buffer.windowBase + l][c]; 306 307 int fg = darken(fgcolor); 308 int bg = darken(bgcolor); 309 310 if ( (currAttr & buffer.COLOR_FG) != 0) { 311 fg = darken(color[ ( (currAttr & buffer.COLOR_FG) >> 4) - 1]); 312 } 313 if ( (currAttr & buffer.COLOR_BG) != 0) { 314 bg = darken(darken(color[ ( (currAttr & buffer.COLOR_BG) >> 8) - 1])); 315 316 // bold font handling was DELETED 317 318 } 319 if ( (currAttr & VDUBuffer.LOW) != 0) { 320 fg = darken(fg); 321 } 322 if ( (currAttr & VDUBuffer.INVERT) != 0) { 323 int swapc = bg; 324 bg = fg; 325 fg = swapc; 326 } 327 328 // determine the maximum of characters we can print in one go 329 while ( (c + addr < buffer.width) && 330 ( (buffer.charArray[buffer.windowBase + l][c + addr] < ' ') || 331 (buffer.charAttributes[buffer.windowBase + l][c + addr] == 332 currAttr))) { 333 if (buffer.charArray[buffer.windowBase + l][c + addr] < ' ') { 334 buffer.charArray[buffer.windowBase + l][c + addr] = ' '; 335 buffer.charAttributes[buffer.windowBase + l][c + addr] = 0; 336 continue; 337 } 338 addr++; 339 } 340 341 // clear the part of the screen we want to change (fill rectangle) 342 if (Telnet.useColors) 343 g.setColor(bg); 344 else 345 g.setColor(bgcolor); 346 347 g.fillRect( (c - left) * font.width, (l - top) * font.height, 348 addr * font.width, font.height); 349 350 if (Telnet.useColors) 351 g.setColor(fg); 352 else 353 g.setColor(fgcolor); 354 355 // draw the characters 356 font.drawChars(g, buffer.charArray[buffer.windowBase + l], c, addr, 357 (c - left) * font.width, 358 (l - top) * font.height); 359 360 c += addr - 1; 361 } 362 } 363 364 // draw cursor 365 if (buffer.showcursor && ( 366 buffer.screenBase + buffer.cursorY >= buffer.windowBase && 367 buffer.screenBase + buffer.cursorY < buffer.windowBase + buffer.height) 368 ) { 369 g.setColor(fgcolor); 370 g.fillRect( (buffer.cursorX - left) * font.width, 371 (buffer.cursorY - top + buffer.screenBase - buffer.windowBase) * 372 font.height, 373 font.width, font.height); 374 } 375 376 repaint(); 377 } 378 379 /** 380 * Set a new terminal (VDU) buffer. 381 * @param buffer new buffer 382 */ 383 public void setVDUBuffer(vt320 buffer) { 384 this.buffer = buffer; 385 buffer.setDisplay(this); 386 } 387 388 public void loadBindings() { 389 bindings = new java.util.Hashtable(); 390 RecordStore rec = null; 391 try { 392 // RecordStore.deleteRecordStore("binds"); // uncomment to delete all binds 393 rec = RecordStore.openRecordStore("binds", false); 394 } 395 catch (Exception e) { // Set up default bindings 396 bindings.put(new Integer(Canvas.KEY_NUM1 + 64), 397 new Action(Action.CONNECT, "158.194.80.13", "polakr", 398 "mypass")); 399 bindings.put(new Integer(Canvas.KEY_NUM5 + 64), 400 new Action(Action.INPUT_DIALOG, "", "", "")); 401 bindings.put(new Integer(Canvas.KEY_STAR + 64), 402 new Action(Action.KEY_PRESSED, "37", "65535", "8")); 403 bindings.put(new Integer(Canvas.KEY_POUND + 64), 404 new Action(Action.KEY_PRESSED, "39", "65535", "8")); 405 bindings.put(new Integer(Canvas.KEY_NUM8 + 64), 406 new Action(Action.KEY_PRESSED, "38", "65535", "8")); 407 bindings.put(new Integer(Canvas.KEY_NUM0 + 64), 408 new Action(Action.KEY_PRESSED, "40", "65535", "8")); 409 bindings.put(new Integer(Canvas.KEY_NUM9 + 64), 410 new Action(Action.VIEW_CONSOLE, "", "", "")); 411 return; 412 } 413 try { 414 byte[] data; 415 RecordEnumeration enumerator = rec.enumerateRecords(null, null, false); 416 if (enumerator.hasNextElement()) { 417 data = enumerator.nextRecord(); 418 ByteArrayInputStream stream = new ByteArrayInputStream(data); 419 DataInputStream in = new DataInputStream(stream); 420 while (in.available() > 0) 421 bindings.put(new Integer(in.readInt()), 422 new Action(in.readUTF(), in.readUTF(), in.readUTF(), 423 in.readUTF())); 424 in.close(); 425 } 426 rec.closeRecordStore(); 427 } 428 catch (Exception e) { 429 e.printStackTrace(); 430 } 431 } 432 433 public void saveBindings() { 434 try { 435 try 436 { 437 RecordStore.deleteRecordStore("binds"); 438 } 439 catch( Exception e ) {} 440 RecordStore rec = RecordStore.openRecordStore("binds", true); 441 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 442 DataOutputStream out = new DataOutputStream(stream); 443 for (int i = 0; i < 128; i++) { 444 Object o = bindings.get(new Integer(i)); 445 if (o != null) { 446 Action a = (Action) o; 447 out.writeInt( i ); 448 out.writeUTF(a.funct); 449 out.writeUTF(a.arg0); 450 out.writeUTF(a.arg1); 451 out.writeUTF(a.arg2); 452 } 453 } 454 out.close(); 455 byte[] data = stream.toByteArray(); 456 rec.addRecord(data, 0, data.length); 457 rec.closeRecordStore(); 458 } 459 catch (Exception e) { 460 e.printStackTrace(); 461 } 462 } 463 464 public void displayHelp() { 465 String help = ""; 466 for (int i = 0; i < 128; i++) { 467 Object o = bindings.get(new Integer(i)); 468 if (o != null) { 469 Action action = (Action) o; 470 String line = getKeyName(i - 64) + " - " + 471 action.funct + " " + 472 action.arg0 + " " + 473 action.arg1 + " " + 474 action.arg2; 475 help += line + "\n\r"; 476 if (Telnet.socket != null ) 477 Telnet.console.append(line); 478 } 479 } 480 if (Telnet.socket != null) { 481 Telnet.setDisplay(Telnet.console); 482 } 483 else { 484 buffer.deleteArea(0, 0, buffer.width, buffer.height); 485 buffer.R = 0; 486 buffer.C = 0; 487 Telnet.emulation.putString(help); 488 redraw(); 489 } 490 } 491 492 /** 493 * Types key specified as string argument 494 * @param code - string kode of key e.g. CTRL+x 495 * @return true if code was parsed and key was typed 496 */ 497 public int getModifiers(String code) { 498 int modifiers = 0; 499 if (code.indexOf("ctrl") != -1) 500 modifiers |= vt320.KEY_CONTROL; 501 if (code.indexOf("shift") != -1) 502 modifiers |= vt320.KEY_SHIFT; 503 if (code.indexOf("alt") != -1) 504 modifiers |= vt320.KEY_ALT; 505 return modifiers; 506 } 507 508 } |