comparison src/com/five_ten_sg/connectbot/transport/TN5250.java @ 53:e872762ec105 tn5250

start tn5250 integration
author Carl Byington <carl@five-ten-sg.com>
date Wed, 11 Jun 2014 13:37:02 -0700
parents 0e3fc85d0586
children a7e660661e08
comparison
equal deleted inserted replaced
52:0e3fc85d0586 53:e872762ec105
40 import com.five_ten_sg.connectbot.util.HostDatabase; 40 import com.five_ten_sg.connectbot.util.HostDatabase;
41 import com.five_ten_sg.connectbot.util.PreferenceConstants; 41 import com.five_ten_sg.connectbot.util.PreferenceConstants;
42 import android.content.Context; 42 import android.content.Context;
43 import android.net.Uri; 43 import android.net.Uri;
44 import android.util.Log; 44 import android.util.Log;
45 import android.view.KeyCharacterMap;
45 import android.view.KeyEvent; 46 import android.view.KeyEvent;
46 import android.view.View; 47 import android.view.View;
47 import de.mud.terminal.vt320; 48 import de.mud.terminal.vt320;
48 49
49 50
66 hostmask = Pattern.compile("^([0-9a-z.-]+)(:(\\d+))?$", Pattern.CASE_INSENSITIVE); 67 hostmask = Pattern.compile("^([0-9a-z.-]+)(:(\\d+))?$", Pattern.CASE_INSENSITIVE);
67 } 68 }
68 69
69 70
70 class vt320x5250 extends vt320 { 71 class vt320x5250 extends vt320 {
72 private HashMap<Integer, String> mnemonics;
73
74 public vt320x5250(int width, int height) {
75 super(width, height);
76 mnemonics = new HashMap<Integer, String>();
77 mnemonics.put(KEY_PAUSE , "[attn]");
78 mnemonics.put(KEY_F1 , "[pf1]");
79 mnemonics.put(KEY_F2 , "[pf2]");
80 mnemonics.put(KEY_F3 , "[pf3]");
81 mnemonics.put(KEY_F4 , "[pf4]");
82 mnemonics.put(KEY_F5 , "[pf5]");
83 mnemonics.put(KEY_F6 , "[pf6]");
84 mnemonics.put(KEY_F7 , "[pf7]");
85 mnemonics.put(KEY_F8 , "[pf8]");
86 mnemonics.put(KEY_F9 , "[pf9]");
87 mnemonics.put(KEY_F10 , "[pf10]");
88 mnemonics.put(KEY_F11 , "[pf11]");
89 mnemonics.put(KEY_F12 , "[pf12]");
90 mnemonics.put(KEY_UP , "[up]");
91 mnemonics.put(KEY_DOWN , "[down]");
92 mnemonics.put(KEY_LEFT , "[left]");
93 mnemonics.put(KEY_RIGHT , "[right]");
94 mnemonics.put(KEY_PAGE_DOWN , "[pgdown]");
95 mnemonics.put(KEY_PAGE_UP , "[pgup]");
96 mnemonics.put(KEY_INSERT , "[insert]");
97 mnemonics.put(KEY_DELETE , "[delete]");
98 mnemonics.put(KEY_BACK_SPACE , "[backspace]");
99 mnemonics.put(KEY_HOME , "[home]");
100 mnemonics.put(KEY_END , "[end]");
101 mnemonics.put(KEY_NUM_LOCK , "");
102 mnemonics.put(KEY_CAPS_LOCK , "");
103 mnemonics.put(KEY_SHIFT , "");
104 mnemonics.put(KEY_CONTROL , "");
105 mnemonics.put(KEY_ALT , "");
106 mnemonics.put(KEY_ENTER , "");
107 mnemonics.put(KEY_NUMPAD0 , "0");
108 mnemonics.put(KEY_NUMPAD1 , "1");
109 mnemonics.put(KEY_NUMPAD2 , "2");
110 mnemonics.put(KEY_NUMPAD3 , "3");
111 mnemonics.put(KEY_NUMPAD4 , "4");
112 mnemonics.put(KEY_NUMPAD5 , "5");
113 mnemonics.put(KEY_NUMPAD6 , "6");
114 mnemonics.put(KEY_NUMPAD7 , "7");
115 mnemonics.put(KEY_NUMPAD8 , "8");
116 mnemonics.put(KEY_NUMPAD9 , "9");
117 mnemonics.put(KEY_DECIMAL , ".");
118 mnemonics.put(KEY_ADD , "+");
119 mnemonics.put(KEY_ESCAPE , "");
120 mnemonics.put(KEY_TAB , "[tab]");
121 }
122
71 @Override 123 @Override
72 public void debug(String s) { 124 public void debug(String s) {
73 Log.d(TAG, s); 125 Log.d(TAG, s);
74 } 126 }
127
128 // terminal key listener sending to the host
75 @Override 129 @Override
76 public void write(byte[] b) { 130 public void write(byte[] b) {
77 screen52.sendKeys(new String(b)); 131 screen52.sendKeys(new String(b));
78 } 132 }
79 @Override 133 @Override
80 public void write(int b) { 134 public void write(int b) {
81 screen52.sendKeys(new String(new byte[] {(byte)b})); 135 screen52.sendKeys(new String(new byte[] {(byte)b}));
82 } 136 }
83 // bridge.monitor placement of new characters 137 @Override
138 public void keyPressed(int keyCode, char keyChar, int modifiers) {
139 String s;
140 if (mnemonics.containsKey(keyCode)) {
141 s = mnemonics.get(keyCode);
142 if (s != "") screen52.sendKeys(s);
143 }
144 }
145 // 5250 writing to the screen
84 @Override 146 @Override
85 public void putChar(int c, int l, char ch, int attributes) { 147 public void putChar(int c, int l, char ch, int attributes) {
86 if (bridge.monitor != null) bridge.monitor.screenChanged(l, c); 148 if (bridge.monitor != null) bridge.monitor.screenChanged(l, c);
87 super.putChar(c, l, ch, attributes); 149 super.putChar(c, l, ch, attributes);
88 } 150 }
92 super.setCursorPosition(c, l); 154 super.setCursorPosition(c, l);
93 } 155 }
94 }; 156 };
95 157
96 158
97 class Terminal5250KeyListener extends TerminalKeyListener {
98 public Terminal5250KeyListener(TerminalManager manager,
99 TerminalBridge bridge,
100 vt320 buffer,
101 String encoding) {
102 super(manager, bridge, buffer, encoding);
103 }
104
105 /**
106 * Handle onKey() events coming down from a {@link com.five_ten_sg.connectbot.TerminalView} above us.
107 * Modify the keys to make more sense to a host then pass it to the 5250.
108 */
109 public boolean onKey(View v, int keyCode, KeyEvent event) {
110 try {
111 // skip keys if we aren't connected yet or have been disconnected
112 if (bridge.isDisconnected()) return false;
113
114 // Ignore all key-up events except for the special keys
115 if (event.getAction() == KeyEvent.ACTION_UP) {
116 // There's nothing here for virtual keyboard users.
117 if (!hardKeyboard || hardKeyboardHidden) return false;
118
119 // if keycode debugging enabled, log and print the pressed key
120 if (prefs.getBoolean(PreferenceConstants.DEBUG_KEYCODES, false)) {
121 String keyCodeString = String.format(": %d", keyCode);
122 String toastText = v.getContext().getString(R.string.keycode_pressed) + keyCodeString;
123 Log.d(TAG, toastText);
124 }
125
126 if (fullKeyboard()) {
127 switch (keyCode) {
128 case KeyEvent.KEYCODE_CTRL_LEFT:
129 case KeyEvent.KEYCODE_CTRL_RIGHT:
130 metaKeyUp(META_CTRL_ON);
131 return true;
132
133 case KeyEvent.KEYCODE_ALT_LEFT:
134 case KeyEvent.KEYCODE_ALT_RIGHT:
135 metaKeyUp(META_ALT_ON);
136 return true;
137
138 case KeyEvent.KEYCODE_SHIFT_LEFT:
139 case KeyEvent.KEYCODE_SHIFT_RIGHT:
140 metaKeyUp(META_SHIFT_ON);
141 return true;
142
143 default:
144 }
145 }
146 else if (PreferenceConstants.KEYMODE_RIGHT.equals(keymode)) {
147 if (keyCode == KeyEvent.KEYCODE_ALT_RIGHT
148 && (metaState & META_SLASH) != 0) {
149 metaState &= ~(META_SLASH | META_TRANSIENT);
150 buffer.write('/');
151 return true;
152 }
153 else if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT
154 && (metaState & META_TAB) != 0) {
155 metaState &= ~(META_TAB | META_TRANSIENT);
156 sendEncoded("[tab]");
157 return true;
158 }
159 }
160 else if (PreferenceConstants.KEYMODE_LEFT.equals(keymode)) {
161 if (keyCode == KeyEvent.KEYCODE_ALT_LEFT
162 && (metaState & META_SLASH) != 0) {
163 metaState &= ~(META_SLASH | META_TRANSIENT);
164 buffer.write('/');
165 return true;
166 }
167 else if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
168 && (metaState & META_TAB) != 0) {
169 metaState &= ~(META_TAB | META_TRANSIENT);
170 sendEncoded("[tab]");
171 return true;
172 }
173 }
174
175 return false;
176 }
177
178 bridge.resetScrollPosition();
179
180 if (keyCode == KeyEvent.KEYCODE_UNKNOWN &&
181 event.getAction() == KeyEvent.ACTION_MULTIPLE) {
182 byte[] input = event.getCharacters().getBytes(encoding);
183 buffer.write(input);
184 return true;
185 }
186
187 int curMetaState = event.getMetaState();
188 final int orgMetaState = curMetaState;
189
190 if ((metaState & META_SHIFT_MASK) != 0) {
191 curMetaState |= KeyEvent.META_SHIFT_ON;
192 }
193
194 if ((metaState & META_ALT_MASK) != 0) {
195 curMetaState |= KeyEvent.META_ALT_ON;
196 }
197
198 int uchar = event.getUnicodeChar(curMetaState);
199
200 // no hard keyboard? ALT-k should pass through to below
201 if ((orgMetaState & KeyEvent.META_ALT_ON) != 0 &&
202 (!hardKeyboard || hardKeyboardHidden)) {
203 uchar = 0;
204 }
205
206 if ((uchar & KeyCharacterMap.COMBINING_ACCENT) != 0) {
207 mDeadKey = uchar & KeyCharacterMap.COMBINING_ACCENT_MASK;
208 return true;
209 }
210
211 if (mDeadKey != 0 && uchar != 0) {
212 uchar = KeyCharacterMap.getDeadChar(mDeadKey, uchar);
213 mDeadKey = 0;
214 }
215
216 // handle customized keymaps
217 if (customKeymapAction(v, keyCode, event))
218 return true;
219
220 if (v != null) {
221 //Show up the CharacterPickerDialog when the SYM key is pressed
222 if ((isSymKey(keyCode) || uchar == KeyCharacterMap.PICKER_DIALOG_INPUT)) {
223 bridge.showCharPickerDialog();
224
225 if (metaState == 4) { // reset fn-key state
226 metaState = 0;
227 bridge.redraw();
228 }
229
230 return true;
231 }
232 else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
233 //Show up the URL scan dialog when the search key is pressed
234 urlScan(v);
235 return true;
236 }
237 }
238
239 // otherwise pass through to existing session
240 // print normal keys
241 if (uchar > 0x00 && keyCode != KeyEvent.KEYCODE_ENTER) {
242 metaState &= ~(META_SLASH | META_TAB);
243 // Remove shift and alt modifiers
244 final int lastMetaState = metaState;
245 metaState &= ~(META_SHIFT_ON | META_ALT_ON);
246
247 if (metaState != lastMetaState) {
248 bridge.redraw();
249 }
250
251 if ((metaState & META_CTRL_MASK) != 0) {
252 metaState &= ~META_CTRL_ON;
253 bridge.redraw();
254
255 // If there is no hard keyboard or there is a hard keyboard currently hidden,
256 // CTRL-1 through CTRL-9 will send F1 through F9
257 if ((!hardKeyboard || hardKeyboardHidden) && sendFunctionKey(keyCode))
258 return true;
259
260 uchar = keyAsControl(uchar);
261 }
262
263 // handle pressing f-keys
264 if ((hardKeyboard && !hardKeyboardHidden)
265 && (curMetaState & KeyEvent.META_ALT_ON) != 0
266 && (curMetaState & KeyEvent.META_SHIFT_ON) != 0
267 && sendFunctionKey(keyCode))
268 return true;
269
270 if (uchar < 0x80)
271 buffer.write(uchar);
272 else
273 sendEncoded(new String(Character.toChars(uchar)));
274
275 return true;
276 }
277
278 // send ctrl and meta-keys as appropriate
279 if (!hardKeyboard || hardKeyboardHidden) {
280 int k = event.getUnicodeChar(0);
281 int k0 = k;
282 boolean sendCtrl = false;
283 boolean sendMeta = false;
284
285 if (k != 0) {
286 if ((orgMetaState & HC_META_CTRL_ON) != 0) {
287 k = keyAsControl(k);
288
289 if (k != k0)
290 sendCtrl = true;
291
292 // send F1-F10 via CTRL-1 through CTRL-0
293 if (!sendCtrl && sendFunctionKey(keyCode))
294 return true;
295 }
296 else if ((orgMetaState & KeyEvent.META_ALT_ON) != 0) {
297 sendMeta = true;
298 buffer.write(0x1b);
299 }
300
301 if (sendMeta || sendCtrl) {
302 buffer.write(k);
303 return true;
304 }
305 }
306 }
307
308 // handle meta and f-keys for full hardware keyboard
309 if (hardKeyboard && !hardKeyboardHidden && fullKeyboard()) {
310 int k = event.getUnicodeChar(orgMetaState & KeyEvent.META_SHIFT_ON);
311 int k0 = k;
312
313 if (k != 0) {
314 if ((orgMetaState & HC_META_CTRL_ON) != 0) {
315 k = keyAsControl(k);
316
317 if (k != k0)
318 buffer.write(k);
319
320 return true;
321 }
322 else if ((orgMetaState & KeyEvent.META_ALT_ON) != 0) {
323 buffer.write(0x1b);
324 buffer.write(k);
325 return true;
326 }
327 }
328
329 if (sendFullSpecialKey(keyCode))
330 return true;
331 }
332
333 // try handling keymode shortcuts
334 if (hardKeyboard && !hardKeyboardHidden &&
335 event.getRepeatCount() == 0) {
336 if (PreferenceConstants.KEYMODE_RIGHT.equals(keymode)) {
337 switch (keyCode) {
338 case KeyEvent.KEYCODE_ALT_RIGHT:
339 metaState |= META_SLASH;
340 return true;
341
342 case KeyEvent.KEYCODE_SHIFT_RIGHT:
343 metaState |= META_TAB;
344 return true;
345
346 case KeyEvent.KEYCODE_SHIFT_LEFT:
347 metaPress(META_SHIFT_ON);
348 return true;
349
350 case KeyEvent.KEYCODE_ALT_LEFT:
351 metaPress(META_ALT_ON);
352 return true;
353 }
354 }
355 else if (PreferenceConstants.KEYMODE_LEFT.equals(keymode)) {
356 switch (keyCode) {
357 case KeyEvent.KEYCODE_ALT_LEFT:
358 metaState |= META_SLASH;
359 return true;
360
361 case KeyEvent.KEYCODE_SHIFT_LEFT:
362 metaState |= META_TAB;
363 return true;
364
365 case KeyEvent.KEYCODE_SHIFT_RIGHT:
366 metaPress(META_SHIFT_ON);
367 return true;
368
369 case KeyEvent.KEYCODE_ALT_RIGHT:
370 metaPress(META_ALT_ON);
371 return true;
372 }
373 }
374 else {
375 switch (keyCode) {
376 case KeyEvent.KEYCODE_ALT_RIGHT:
377 case KeyEvent.KEYCODE_ALT_LEFT:
378 metaPress(META_ALT_ON);
379 return true;
380
381 case KeyEvent.KEYCODE_SHIFT_LEFT:
382 case KeyEvent.KEYCODE_SHIFT_RIGHT:
383 metaPress(META_SHIFT_ON);
384 return true;
385 }
386 }
387
388 // Handle hardware CTRL keys
389 if (keyCode == KeyEvent.KEYCODE_CTRL_LEFT ||
390 keyCode == KeyEvent.KEYCODE_CTRL_RIGHT) {
391 ctrlKeySpecial();
392 return true;
393 }
394 }
395
396 // look for special chars
397 switch (keyCode) {
398 case KEYCODE_ESCAPE:
399 buffer.write(0x1b);
400 return true;
401
402 case KeyEvent.KEYCODE_TAB:
403 sendEncoded("[tab]");
404 return true;
405
406 case KEYCODE_PAGE_DOWN:
407 sendEncoded("[pgdown]");
408 metaState &= ~META_TRANSIENT;
409 bridge.tryKeyVibrate();
410 return true;
411
412 case KEYCODE_PAGE_UP:
413 sendEncoded("[pgup]");
414 metaState &= ~META_TRANSIENT;
415 bridge.tryKeyVibrate();
416 return true;
417
418 case KeyEvent.KEYCODE_MOVE_HOME:
419 sendEncoded("[home]");
420 metaState &= ~META_TRANSIENT;
421 bridge.tryKeyVibrate();
422 return true;
423
424 case KeyEvent.KEYCODE_MOVE_END:
425 sendEncoded("[end]"); // does not exist!!
426 metaState &= ~META_TRANSIENT;
427 bridge.tryKeyVibrate();
428 return true;
429
430 case KeyEvent.KEYCODE_CAMERA:
431 // check to see which shortcut the camera button triggers
432 String hwbuttonShortcut = manager.prefs.getString(
433 PreferenceConstants.CAMERA,
434 PreferenceConstants.HWBUTTON_SCREEN_CAPTURE);
435 return (handleShortcut(v, hwbuttonShortcut));
436
437 case KeyEvent.KEYCODE_VOLUME_UP:
438 // check to see which shortcut the volume button triggers
439 hwbuttonShortcut = manager.prefs.getString(
440 PreferenceConstants.VOLUP,
441 PreferenceConstants.HWBUTTON_CTRL);
442 return (handleShortcut(v, hwbuttonShortcut));
443
444 case KeyEvent.KEYCODE_VOLUME_DOWN:
445 // check to see which shortcut the camera button triggers
446 hwbuttonShortcut = manager.prefs.getString(
447 PreferenceConstants.VOLDN,
448 PreferenceConstants.HWBUTTON_TAB);
449 return (handleShortcut(v, hwbuttonShortcut));
450
451 case KeyEvent.KEYCODE_SEARCH:
452 // check to see which shortcut the search button triggers
453 hwbuttonShortcut = manager.prefs.getString(
454 PreferenceConstants.SEARCH,
455 PreferenceConstants.HWBUTTON_ESC);
456 return (handleShortcut(v, hwbuttonShortcut));
457
458 case KeyEvent.KEYCODE_DEL:
459 if ((metaState & META_ALT_MASK) != 0) {
460 sendEncoded("[insert]");
461 }
462 else {
463 sendEncoded("[backspace]");
464 }
465
466 metaState &= ~META_TRANSIENT;
467 return true;
468
469 case KeyEvent.KEYCODE_ENTER:
470 sendEncoded("[enter]");
471 metaState &= ~META_TRANSIENT;
472 return true;
473
474 case KeyEvent.KEYCODE_DPAD_LEFT:
475 if (selectingForCopy) {
476 selectionArea.decrementColumn();
477 bridge.redraw();
478 }
479 else {
480 if ((metaState & META_ALT_MASK) != 0) {
481 sendEncoded("[home]");
482 }
483 else {
484 sendEncoded("[left]");
485 }
486
487 metaState &= ~META_TRANSIENT;
488 bridge.tryKeyVibrate();
489 }
490
491 return true;
492
493 case KeyEvent.KEYCODE_DPAD_UP:
494 if (selectingForCopy) {
495 selectionArea.decrementRow();
496 bridge.redraw();
497 }
498 else {
499 if ((metaState & META_ALT_MASK) != 0) {
500 sendEncoded("[pgup]");
501 }
502 else {
503 sendEncoded("[up]");
504 }
505
506 metaState &= ~META_TRANSIENT;
507 bridge.tryKeyVibrate();
508 }
509
510 return true;
511
512 case KeyEvent.KEYCODE_DPAD_DOWN:
513 if (selectingForCopy) {
514 selectionArea.incrementRow();
515 bridge.redraw();
516 }
517 else {
518 if ((metaState & META_ALT_MASK) != 0) {
519 sendEncoded("[pgdown]");
520 }
521 else {
522 sendEncoded("[down]");
523 }
524
525 metaState &= ~META_TRANSIENT;
526 bridge.tryKeyVibrate();
527 }
528
529 return true;
530
531 case KeyEvent.KEYCODE_DPAD_RIGHT:
532 if (selectingForCopy) {
533 selectionArea.incrementColumn();
534 bridge.redraw();
535 }
536 else {
537 if ((metaState & META_ALT_MASK) != 0) {
538 sendEncoded("[end]"); // does not exist!!
539 }
540 else {
541 sendEncoded("[right]");
542 }
543
544 metaState &= ~META_TRANSIENT;
545 bridge.tryKeyVibrate();
546 }
547
548 return true;
549
550 case KeyEvent.KEYCODE_DPAD_CENTER:
551 ctrlKeySpecial();
552 return true;
553 }
554 }
555 catch (IOException e) {
556 Log.e(TAG, "Problem while trying to handle an onKey() event", e);
557
558 try {
559 flush();
560 }
561 catch (IOException ioe) {
562 Log.d(TAG, "Our transport was closed, dispatching disconnect event");
563 bridge.dispatchDisconnect(false);
564 }
565 }
566 catch (NullPointerException npe) {
567 Log.d(TAG, "Input before connection established ignored.");
568 return true;
569 }
570 }
571
572 };
573
574
575 public TN5250() { 159 public TN5250() {
576 super(); 160 super();
577 } 161 }
578 162
579 163
580 /** 164 /**
581 * @return protocol part of the URI 165 * @return protocol part of the URI
582 */ 166 */
822 // we don't use a relay thread between the transport and the vt320 buffer 406 // we don't use a relay thread between the transport and the vt320 buffer
823 return false; 407 return false;
824 } 408 }
825 409
826 public TerminalKeyListener getTerminalKeyListener() { 410 public TerminalKeyListener getTerminalKeyListener() {
827 return new Terminal5250KeyListener(manager, bridge, buffer, host.getEncoding()); 411 return new TerminalKeyListener(manager, bridge, buffer, host.getEncoding());
828 } 412 }
829 413
830 } 414 }