Mercurial > 510Connectbot
annotate src/com/five_ten_sg/connectbot/service/TerminalKeyListener.java @ 48:1e931ef5f776 tn5250
start tn5250 integration
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Wed, 11 Jun 2014 10:11:29 -0700 |
parents | 80dcebe51af2 |
children | 8887bff45dee |
rev | line source |
---|---|
0 | 1 /* |
2 * ConnectBot: simple, powerful, open-source SSH client for Android | |
3 * Copyright 2010 Kenny Root, Jeffrey Sharkey | |
4 * | |
5 * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 * you may not use this file except in compliance with the License. | |
7 * You may obtain a copy of the License at | |
8 * | |
9 * http://www.apache.org/licenses/LICENSE-2.0 | |
10 * | |
11 * Unless required by applicable law or agreed to in writing, software | |
12 * distributed under the License is distributed on an "AS IS" BASIS, | |
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 * See the License for the specific language governing permissions and | |
15 * limitations under the License. | |
16 */ | |
17 package com.five_ten_sg.connectbot.service; | |
18 | |
19 import java.io.IOException; | |
48
1e931ef5f776
start tn5250 integration
Carl Byington <carl@five-ten-sg.com>
parents:
45
diff
changeset
|
20 import java.nio.charset.Charset; |
0 | 21 import java.lang.ref.WeakReference; |
22 import java.util.List; | |
23 | |
24 import com.five_ten_sg.connectbot.R; | |
25 import com.five_ten_sg.connectbot.TerminalView; | |
26 import com.five_ten_sg.connectbot.bean.SelectionArea; | |
27 import com.five_ten_sg.connectbot.util.PreferenceConstants; | |
28 import android.app.Dialog; | |
29 import android.content.Context; | |
30 import android.content.Intent; | |
31 import android.content.SharedPreferences; | |
32 import android.content.SharedPreferences.OnSharedPreferenceChangeListener; | |
33 import android.content.res.Configuration; | |
34 import android.net.Uri; | |
35 import android.preference.PreferenceManager; | |
36 import android.text.ClipboardManager; | |
37 import android.util.Log; | |
38 import android.view.Gravity; | |
39 import android.view.KeyCharacterMap; | |
40 import android.view.KeyEvent; | |
41 import android.view.View; | |
42 import android.view.View.OnKeyListener; | |
43 import android.widget.AdapterView; | |
44 import android.widget.AdapterView.OnItemClickListener; | |
45 import android.widget.ArrayAdapter; | |
46 import android.widget.ListView; | |
47 import android.widget.TextView; | |
48 import android.widget.Toast; | |
49 import de.mud.terminal.VDUBuffer; | |
50 import de.mud.terminal.vt320; | |
51 | |
52 /** | |
53 * @author kenny | |
54 * | |
55 */ | |
56 @SuppressWarnings("deprecation") // for ClipboardManager | |
57 public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceChangeListener { | |
58 private static final String TAG = "ConnectBot.OnKeyListener"; | |
59 | |
60 public final static int META_CTRL_ON = 0x01; | |
61 public final static int META_CTRL_LOCK = 0x02; | |
62 public final static int META_ALT_ON = 0x04; | |
63 public final static int META_ALT_LOCK = 0x08; | |
64 public final static int META_SHIFT_ON = 0x10; | |
65 public final static int META_SHIFT_LOCK = 0x20; | |
66 public final static int META_SLASH = 0x40; | |
67 public final static int META_TAB = 0x80; | |
68 | |
69 // The bit mask of momentary and lock states for each | |
70 public final static int META_CTRL_MASK = META_CTRL_ON | META_CTRL_LOCK; | |
71 public final static int META_ALT_MASK = META_ALT_ON | META_ALT_LOCK; | |
72 public final static int META_SHIFT_MASK = META_SHIFT_ON | META_SHIFT_LOCK; | |
73 | |
74 // backport constants from api level 11 | |
75 public final static int KEYCODE_ESCAPE = 111; | |
76 public final static int HC_META_CTRL_ON = 4096; | |
77 public final static int KEYCODE_PAGE_UP = 92; | |
78 public final static int KEYCODE_PAGE_DOWN = 93; | |
79 | |
80 // All the transient key codes | |
81 public final static int META_TRANSIENT = META_CTRL_ON | META_ALT_ON | |
82 | META_SHIFT_ON; | |
83 | |
84 private final TerminalManager manager; | |
85 private final TerminalBridge bridge; | |
86 private final vt320 buffer; | |
48
1e931ef5f776
start tn5250 integration
Carl Byington <carl@five-ten-sg.com>
parents:
45
diff
changeset
|
87 private String encoding; |
0 | 88 |
89 private String keymode = null; | |
90 private boolean hardKeyboard = false; | |
91 private String customKeyboard = null; | |
92 | |
93 private int metaState = 0; | |
94 | |
95 private int mDeadKey = 0; | |
96 | |
97 // TODO add support for the new API. | |
98 private ClipboardManager clipboard = null; | |
99 | |
100 private boolean selectingForCopy = false; | |
101 private final SelectionArea selectionArea; | |
102 | |
103 | |
104 private final SharedPreferences prefs; | |
105 | |
106 private Toast debugToast = null; | |
107 private Toast metakeyToast = null; | |
108 | |
109 public TerminalKeyListener(TerminalManager manager, | |
110 TerminalBridge bridge, | |
111 vt320 buffer, | |
112 String encoding) { | |
113 this.manager = manager; | |
114 this.bridge = bridge; | |
115 this.buffer = buffer; | |
116 this.encoding = encoding; | |
117 selectionArea = new SelectionArea(); | |
118 prefs = PreferenceManager.getDefaultSharedPreferences(manager); | |
119 prefs.registerOnSharedPreferenceChangeListener(this); | |
120 hardKeyboard = (manager.res.getConfiguration().keyboard | |
121 == Configuration.KEYBOARD_QWERTY); | |
122 updateKeymode(); | |
123 updateCustomKeymap(); | |
124 } | |
125 | |
126 public void sendEscape() { | |
127 buffer.write(0x1b); | |
128 } | |
129 | |
130 /** | |
131 * Handle onKey() events coming down from a {@link com.five_ten_sg.connectbot.TerminalView} above us. | |
132 * Modify the keys to make more sense to a host then pass it to the vt320. | |
133 */ | |
134 public boolean onKey(View v, int keyCode, KeyEvent event) { | |
135 try { | |
136 // skip keys if we aren't connected yet or have been disconnected | |
137 if (bridge.isDisconnected() || bridge.transport == null) | |
138 return false; | |
139 | |
140 final boolean hardKeyboardHidden = manager.hardKeyboardHidden; | |
141 | |
142 // Ignore all key-up events except for the special keys | |
143 if (event.getAction() == KeyEvent.ACTION_UP) { | |
144 // There's nothing here for virtual keyboard users. | |
145 if (!hardKeyboard || (hardKeyboard && hardKeyboardHidden)) | |
146 return false; | |
147 | |
148 // if keycode debugging enabled, log and print the pressed key | |
149 if (prefs.getBoolean(PreferenceConstants.DEBUG_KEYCODES, false)) { | |
150 String keyCodeString = String.format(": %d", keyCode); | |
151 String toastText = v.getContext().getString(R.string.keycode_pressed) + keyCodeString; | |
152 | |
153 if (debugToast == null) | |
154 debugToast = Toast.makeText(v.getContext(), toastText, Toast.LENGTH_LONG); | |
155 else | |
156 debugToast.setText(toastText); | |
157 | |
158 debugToast.show(); | |
159 } | |
160 | |
161 if (fullKeyboard()) { | |
162 switch (keyCode) { | |
163 case KeyEvent.KEYCODE_CTRL_LEFT: | |
164 case KeyEvent.KEYCODE_CTRL_RIGHT: | |
165 metaKeyUp(META_CTRL_ON); | |
166 return true; | |
167 | |
168 case KeyEvent.KEYCODE_ALT_LEFT: | |
169 case KeyEvent.KEYCODE_ALT_RIGHT: | |
170 metaKeyUp(META_ALT_ON); | |
171 return true; | |
172 | |
173 case KeyEvent.KEYCODE_SHIFT_LEFT: | |
174 case KeyEvent.KEYCODE_SHIFT_RIGHT: | |
175 metaKeyUp(META_SHIFT_ON); | |
176 return true; | |
177 | |
178 default: | |
179 } | |
180 } | |
181 else if (PreferenceConstants.KEYMODE_RIGHT.equals(keymode)) { | |
182 if (keyCode == KeyEvent.KEYCODE_ALT_RIGHT | |
183 && (metaState & META_SLASH) != 0) { | |
184 metaState &= ~(META_SLASH | META_TRANSIENT); | |
185 buffer.write('/'); | |
186 return true; | |
187 } | |
188 else if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT | |
189 && (metaState & META_TAB) != 0) { | |
190 metaState &= ~(META_TAB | META_TRANSIENT); | |
191 buffer.write(0x09); | |
192 return true; | |
193 } | |
194 } | |
195 else if (PreferenceConstants.KEYMODE_LEFT.equals(keymode)) { | |
196 if (keyCode == KeyEvent.KEYCODE_ALT_LEFT | |
197 && (metaState & META_SLASH) != 0) { | |
198 metaState &= ~(META_SLASH | META_TRANSIENT); | |
199 buffer.write('/'); | |
200 return true; | |
201 } | |
202 else if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT | |
203 && (metaState & META_TAB) != 0) { | |
204 metaState &= ~(META_TAB | META_TRANSIENT); | |
205 buffer.write(0x09); | |
206 return true; | |
207 } | |
208 } | |
209 | |
210 return false; | |
211 } | |
212 | |
213 bridge.resetScrollPosition(); | |
214 | |
215 if (keyCode == KeyEvent.KEYCODE_UNKNOWN && | |
216 event.getAction() == KeyEvent.ACTION_MULTIPLE) { | |
217 byte[] input = event.getCharacters().getBytes(encoding); | |
218 buffer.write(input); | |
219 return true; | |
220 } | |
221 | |
222 int curMetaState = event.getMetaState(); | |
223 final int orgMetaState = curMetaState; | |
224 | |
225 if ((metaState & META_SHIFT_MASK) != 0) { | |
226 curMetaState |= KeyEvent.META_SHIFT_ON; | |
227 } | |
228 | |
229 if ((metaState & META_ALT_MASK) != 0) { | |
230 curMetaState |= KeyEvent.META_ALT_ON; | |
231 } | |
232 | |
233 int uchar = event.getUnicodeChar(curMetaState); | |
234 | |
235 // no hard keyboard? ALT-k should pass through to below | |
236 if ((orgMetaState & KeyEvent.META_ALT_ON) != 0 && | |
237 (!hardKeyboard || hardKeyboardHidden)) { | |
238 uchar = 0; | |
239 } | |
240 | |
241 if ((uchar & KeyCharacterMap.COMBINING_ACCENT) != 0) { | |
242 mDeadKey = uchar & KeyCharacterMap.COMBINING_ACCENT_MASK; | |
243 return true; | |
244 } | |
245 | |
246 if (mDeadKey != 0 && uchar != 0) { | |
247 uchar = KeyCharacterMap.getDeadChar(mDeadKey, uchar); | |
248 mDeadKey = 0; | |
249 } | |
250 | |
251 // handle customized keymaps | |
252 if (customKeymapAction(v, keyCode, event)) | |
253 return true; | |
254 | |
255 if (v != null) { | |
256 //Show up the CharacterPickerDialog when the SYM key is pressed | |
257 if ((isSymKey(keyCode) || uchar == KeyCharacterMap.PICKER_DIALOG_INPUT)) { | |
258 bridge.showCharPickerDialog(); | |
259 | |
260 if (metaState == 4) { // reset fn-key state | |
261 metaState = 0; | |
262 bridge.redraw(); | |
263 } | |
264 | |
265 return true; | |
266 } | |
267 else if (keyCode == KeyEvent.KEYCODE_SEARCH) { | |
268 //Show up the URL scan dialog when the search key is pressed | |
269 urlScan(v); | |
270 return true; | |
271 } | |
272 } | |
273 | |
274 // otherwise pass through to existing session | |
275 // print normal keys | |
276 if (uchar > 0x00 && keyCode != KeyEvent.KEYCODE_ENTER) { | |
277 metaState &= ~(META_SLASH | META_TAB); | |
278 // Remove shift and alt modifiers | |
279 final int lastMetaState = metaState; | |
280 metaState &= ~(META_SHIFT_ON | META_ALT_ON); | |
281 | |
282 if (metaState != lastMetaState) { | |
283 bridge.redraw(); | |
284 } | |
285 | |
286 if ((metaState & META_CTRL_MASK) != 0) { | |
287 metaState &= ~META_CTRL_ON; | |
288 bridge.redraw(); | |
289 | |
290 // If there is no hard keyboard or there is a hard keyboard currently hidden, | |
291 // CTRL-1 through CTRL-9 will send F1 through F9 | |
292 if ((!hardKeyboard || (hardKeyboard && hardKeyboardHidden)) | |
293 && sendFunctionKey(keyCode)) | |
294 return true; | |
295 | |
296 uchar = keyAsControl(uchar); | |
297 } | |
298 | |
299 // handle pressing f-keys | |
300 if ((hardKeyboard && !hardKeyboardHidden) | |
301 && (curMetaState & KeyEvent.META_ALT_ON) != 0 | |
302 && (curMetaState & KeyEvent.META_SHIFT_ON) != 0 | |
303 && sendFunctionKey(keyCode)) | |
304 return true; | |
305 | |
306 if (uchar < 0x80) | |
307 buffer.write(uchar); | |
308 else | |
309 // TODO write encoding routine that doesn't allocate each time | |
310 buffer.write(new String(Character.toChars(uchar)) | |
311 .getBytes(encoding)); | |
312 | |
313 return true; | |
314 } | |
315 | |
316 // send ctrl and meta-keys as appropriate | |
317 if (!hardKeyboard || hardKeyboardHidden) { | |
318 int k = event.getUnicodeChar(0); | |
319 int k0 = k; | |
320 boolean sendCtrl = false; | |
321 boolean sendMeta = false; | |
322 | |
323 if (k != 0) { | |
324 if ((orgMetaState & HC_META_CTRL_ON) != 0) { | |
325 k = keyAsControl(k); | |
326 | |
327 if (k != k0) | |
328 sendCtrl = true; | |
329 | |
330 // send F1-F10 via CTRL-1 through CTRL-0 | |
331 if (!sendCtrl && sendFunctionKey(keyCode)) | |
332 return true; | |
333 } | |
334 else if ((orgMetaState & KeyEvent.META_ALT_ON) != 0) { | |
335 sendMeta = true; | |
336 buffer.write(0x1b); | |
337 } | |
338 | |
339 if (sendMeta || sendCtrl) { | |
340 buffer.write(k); | |
341 return true; | |
342 } | |
343 } | |
344 } | |
345 | |
346 // handle meta and f-keys for full hardware keyboard | |
347 if (hardKeyboard && !hardKeyboardHidden && fullKeyboard()) { | |
348 int k = event.getUnicodeChar(orgMetaState & KeyEvent.META_SHIFT_ON); | |
349 int k0 = k; | |
350 | |
351 if (k != 0) { | |
352 if ((orgMetaState & HC_META_CTRL_ON) != 0) { | |
353 k = keyAsControl(k); | |
354 | |
355 if (k != k0) | |
356 buffer.write(k); | |
357 | |
358 return true; | |
359 } | |
360 else if ((orgMetaState & KeyEvent.META_ALT_ON) != 0) { | |
361 buffer.write(0x1b); | |
362 buffer.write(k); | |
363 return true; | |
364 } | |
365 } | |
366 | |
367 if (sendFullSpecialKey(keyCode)) | |
368 return true; | |
369 } | |
370 | |
371 // try handling keymode shortcuts | |
372 if (hardKeyboard && !hardKeyboardHidden && | |
373 event.getRepeatCount() == 0) { | |
374 if (PreferenceConstants.KEYMODE_RIGHT.equals(keymode)) { | |
375 switch (keyCode) { | |
376 case KeyEvent.KEYCODE_ALT_RIGHT: | |
377 metaState |= META_SLASH; | |
378 return true; | |
379 | |
380 case KeyEvent.KEYCODE_SHIFT_RIGHT: | |
381 metaState |= META_TAB; | |
382 return true; | |
383 | |
384 case KeyEvent.KEYCODE_SHIFT_LEFT: | |
385 metaPress(META_SHIFT_ON); | |
386 return true; | |
387 | |
388 case KeyEvent.KEYCODE_ALT_LEFT: | |
389 metaPress(META_ALT_ON); | |
390 return true; | |
391 } | |
392 } | |
393 else if (PreferenceConstants.KEYMODE_LEFT.equals(keymode)) { | |
394 switch (keyCode) { | |
395 case KeyEvent.KEYCODE_ALT_LEFT: | |
396 metaState |= META_SLASH; | |
397 return true; | |
398 | |
399 case KeyEvent.KEYCODE_SHIFT_LEFT: | |
400 metaState |= META_TAB; | |
401 return true; | |
402 | |
403 case KeyEvent.KEYCODE_SHIFT_RIGHT: | |
404 metaPress(META_SHIFT_ON); | |
405 return true; | |
406 | |
407 case KeyEvent.KEYCODE_ALT_RIGHT: | |
408 metaPress(META_ALT_ON); | |
409 return true; | |
410 } | |
411 } | |
412 else { | |
413 switch (keyCode) { | |
414 case KeyEvent.KEYCODE_ALT_RIGHT: | |
415 case KeyEvent.KEYCODE_ALT_LEFT: | |
416 metaPress(META_ALT_ON); | |
417 return true; | |
418 | |
419 case KeyEvent.KEYCODE_SHIFT_LEFT: | |
420 case KeyEvent.KEYCODE_SHIFT_RIGHT: | |
421 metaPress(META_SHIFT_ON); | |
422 return true; | |
423 } | |
424 } | |
425 | |
426 // Handle hardware CTRL keys | |
427 if (keyCode == KeyEvent.KEYCODE_CTRL_LEFT || | |
428 keyCode == KeyEvent.KEYCODE_CTRL_RIGHT) { | |
429 ctrlKeySpecial(); | |
430 return true; | |
431 } | |
432 } | |
433 | |
434 // look for special chars | |
435 switch (keyCode) { | |
436 case KEYCODE_ESCAPE: | |
437 buffer.write(0x1b); | |
438 return true; | |
439 | |
440 case KeyEvent.KEYCODE_TAB: | |
441 buffer.write(0x09); | |
442 return true; | |
443 | |
444 case KEYCODE_PAGE_DOWN: | |
445 buffer.keyPressed(vt320.KEY_PAGE_DOWN, ' ', getStateForBuffer()); | |
446 metaState &= ~META_TRANSIENT; | |
447 bridge.tryKeyVibrate(); | |
448 return true; | |
449 | |
450 case KEYCODE_PAGE_UP: | |
451 buffer.keyPressed(vt320.KEY_PAGE_UP, ' ', getStateForBuffer()); | |
452 metaState &= ~META_TRANSIENT; | |
453 bridge.tryKeyVibrate(); | |
454 return true; | |
455 | |
456 case KeyEvent.KEYCODE_MOVE_HOME: | |
457 buffer.keyPressed(vt320.KEY_HOME, ' ', getStateForBuffer()); | |
458 metaState &= ~META_TRANSIENT; | |
459 bridge.tryKeyVibrate(); | |
460 return true; | |
461 | |
462 case KeyEvent.KEYCODE_MOVE_END: | |
463 buffer.keyPressed(vt320.KEY_END, ' ', getStateForBuffer()); | |
464 metaState &= ~META_TRANSIENT; | |
465 bridge.tryKeyVibrate(); | |
466 return true; | |
467 | |
468 case KeyEvent.KEYCODE_CAMERA: | |
469 // check to see which shortcut the camera button triggers | |
470 String hwbuttonShortcut = manager.prefs.getString( | |
471 PreferenceConstants.CAMERA, | |
472 PreferenceConstants.HWBUTTON_SCREEN_CAPTURE); | |
473 return (handleShortcut(v, hwbuttonShortcut)); | |
474 | |
475 case KeyEvent.KEYCODE_VOLUME_UP: | |
42
7ac846a07ed4
start tn5250 integration
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
476 // check to see which shortcut the volume button triggers |
0 | 477 hwbuttonShortcut = manager.prefs.getString( |
478 PreferenceConstants.VOLUP, | |
479 PreferenceConstants.HWBUTTON_CTRL); | |
480 return (handleShortcut(v, hwbuttonShortcut)); | |
481 | |
482 case KeyEvent.KEYCODE_VOLUME_DOWN: | |
483 // check to see which shortcut the camera button triggers | |
484 hwbuttonShortcut = manager.prefs.getString( | |
485 PreferenceConstants.VOLDN, | |
486 PreferenceConstants.HWBUTTON_TAB); | |
487 return (handleShortcut(v, hwbuttonShortcut)); | |
488 | |
489 case KeyEvent.KEYCODE_SEARCH: | |
42
7ac846a07ed4
start tn5250 integration
Carl Byington <carl@five-ten-sg.com>
parents:
0
diff
changeset
|
490 // check to see which shortcut the search button triggers |
0 | 491 hwbuttonShortcut = manager.prefs.getString( |
492 PreferenceConstants.SEARCH, | |
493 PreferenceConstants.HWBUTTON_ESC); | |
494 return (handleShortcut(v, hwbuttonShortcut)); | |
495 | |
496 case KeyEvent.KEYCODE_DEL: | |
497 if ((metaState & META_ALT_MASK) != 0) { | |
498 buffer.keyPressed(vt320.KEY_INSERT, ' ', | |
499 getStateForBuffer()); | |
500 } | |
501 else { | |
502 buffer.keyPressed(vt320.KEY_BACK_SPACE, ' ', | |
503 getStateForBuffer()); | |
504 } | |
505 | |
506 metaState &= ~META_TRANSIENT; | |
507 return true; | |
508 | |
509 case KeyEvent.KEYCODE_ENTER: | |
510 buffer.write('\r'); | |
511 metaState &= ~META_TRANSIENT; | |
512 return true; | |
513 | |
514 case KeyEvent.KEYCODE_DPAD_LEFT: | |
515 if (selectingForCopy) { | |
516 selectionArea.decrementColumn(); | |
517 bridge.redraw(); | |
518 } | |
519 else { | |
520 if ((metaState & META_ALT_MASK) != 0) { | |
521 buffer.keyPressed(vt320.KEY_HOME, ' ', | |
522 getStateForBuffer()); | |
523 } | |
524 else { | |
525 buffer.keyPressed(vt320.KEY_LEFT, ' ', | |
526 getStateForBuffer()); | |
527 } | |
528 | |
529 metaState &= ~META_TRANSIENT; | |
530 bridge.tryKeyVibrate(); | |
531 } | |
532 | |
533 return true; | |
534 | |
535 case KeyEvent.KEYCODE_DPAD_UP: | |
536 if (selectingForCopy) { | |
537 selectionArea.decrementRow(); | |
538 bridge.redraw(); | |
539 } | |
540 else { | |
541 if ((metaState & META_ALT_MASK) != 0) { | |
542 buffer.keyPressed(vt320.KEY_PAGE_UP, ' ', | |
543 getStateForBuffer()); | |
544 } | |
545 else { | |
546 buffer.keyPressed(vt320.KEY_UP, ' ', | |
547 getStateForBuffer()); | |
548 } | |
549 | |
550 metaState &= ~META_TRANSIENT; | |
551 bridge.tryKeyVibrate(); | |
552 } | |
553 | |
554 return true; | |
555 | |
556 case KeyEvent.KEYCODE_DPAD_DOWN: | |
557 if (selectingForCopy) { | |
558 selectionArea.incrementRow(); | |
559 bridge.redraw(); | |
560 } | |
561 else { | |
562 if ((metaState & META_ALT_MASK) != 0) { | |
563 buffer.keyPressed(vt320.KEY_PAGE_DOWN, ' ', | |
564 getStateForBuffer()); | |
565 } | |
566 else { | |
567 buffer.keyPressed(vt320.KEY_DOWN, ' ', | |
568 getStateForBuffer()); | |
569 } | |
570 | |
571 metaState &= ~META_TRANSIENT; | |
572 bridge.tryKeyVibrate(); | |
573 } | |
574 | |
575 return true; | |
576 | |
577 case KeyEvent.KEYCODE_DPAD_RIGHT: | |
578 if (selectingForCopy) { | |
579 selectionArea.incrementColumn(); | |
580 bridge.redraw(); | |
581 } | |
582 else { | |
583 if ((metaState & META_ALT_MASK) != 0) { | |
584 buffer.keyPressed(vt320.KEY_END, ' ', | |
585 getStateForBuffer()); | |
586 } | |
587 else { | |
588 buffer.keyPressed(vt320.KEY_RIGHT, ' ', | |
589 getStateForBuffer()); | |
590 } | |
591 | |
592 metaState &= ~META_TRANSIENT; | |
593 bridge.tryKeyVibrate(); | |
594 } | |
595 | |
596 return true; | |
597 | |
598 case KeyEvent.KEYCODE_DPAD_CENTER: | |
599 ctrlKeySpecial(); | |
600 return true; | |
601 } | |
602 } | |
603 catch (IOException e) { | |
604 Log.e(TAG, "Problem while trying to handle an onKey() event", e); | |
605 | |
606 try { | |
607 bridge.transport.flush(); | |
608 } | |
609 catch (IOException ioe) { | |
610 Log.d(TAG, "Our transport was closed, dispatching disconnect event"); | |
611 bridge.dispatchDisconnect(false); | |
612 } | |
613 } | |
614 catch (NullPointerException npe) { | |
615 Log.d(TAG, "Input before connection established ignored."); | |
616 return true; | |
617 } | |
618 | |
619 return false; | |
620 } | |
621 | |
622 private boolean handleShortcut(View v, String shortcut) { | |
623 if (PreferenceConstants.HWBUTTON_SCREEN_CAPTURE.equals(shortcut)) { | |
624 bridge.captureScreen(); | |
625 } | |
626 else if (PreferenceConstants.HWBUTTON_CTRL.equals(shortcut)) { | |
627 showMetakeyToast(v, PreferenceConstants.HWBUTTON_CTRL); | |
628 metaPress(META_CTRL_ON); | |
629 } | |
630 else if (PreferenceConstants.HWBUTTON_TAB.equals(shortcut)) { | |
631 buffer.write(0x09); | |
632 } | |
633 else if (PreferenceConstants.HWBUTTON_CTRLA_SPACE.equals(shortcut)) { | |
634 buffer.write(0x01); | |
635 buffer.write(' '); | |
636 } | |
637 else if (PreferenceConstants.HWBUTTON_CTRLA.equals(shortcut)) { | |
638 buffer.write(0x01); | |
639 } | |
640 else if (PreferenceConstants.HWBUTTON_ESC.equals(shortcut)) { | |
641 showMetakeyToast(v, PreferenceConstants.HWBUTTON_ESC); | |
642 buffer.write(0x1b); | |
643 } | |
644 else if (PreferenceConstants.HWBUTTON_ESC_A.equals(shortcut)) { | |
645 buffer.write(0x1b); | |
646 buffer.write('a'); | |
647 } | |
648 else { | |
649 return (false); | |
650 } | |
651 | |
652 return (true); | |
653 } | |
654 | |
655 private void showMetakeyToast(View v, String keyname) { | |
656 if (metakeyToast == null) | |
657 metakeyToast = Toast.makeText(v.getContext(), keyname, Toast.LENGTH_LONG); | |
658 else | |
659 metakeyToast.setText(keyname); | |
660 | |
661 metakeyToast.setGravity(Gravity.TOP | Gravity.RIGHT, 0, 0); | |
662 metakeyToast.show(); | |
663 } | |
664 | |
665 public int keyAsControl(int key) { | |
666 // Support CTRL-a through CTRL-z | |
667 if (key >= 0x60 && key <= 0x7A) | |
668 key -= 0x60; | |
669 // Support CTRL-A through CTRL-_ | |
670 else if (key >= 0x40 && key <= 0x5F) | |
671 key -= 0x40; | |
672 // CTRL-space sends NULL | |
673 else if (key == 0x20) | |
674 key = 0x00; | |
675 // CTRL-? sends DEL | |
676 else if (key == 0x3F) | |
677 key = 0x7F; | |
678 | |
679 return key; | |
680 } | |
681 | |
682 /** | |
683 * @param key | |
684 * @return successful | |
685 */ | |
686 private boolean sendFunctionKey(int keyCode) { | |
687 switch (keyCode) { | |
688 case KeyEvent.KEYCODE_1: | |
689 buffer.keyPressed(vt320.KEY_F1, ' ', 0); | |
690 return true; | |
691 | |
692 case KeyEvent.KEYCODE_2: | |
693 buffer.keyPressed(vt320.KEY_F2, ' ', 0); | |
694 return true; | |
695 | |
696 case KeyEvent.KEYCODE_3: | |
697 buffer.keyPressed(vt320.KEY_F3, ' ', 0); | |
698 return true; | |
699 | |
700 case KeyEvent.KEYCODE_4: | |
701 buffer.keyPressed(vt320.KEY_F4, ' ', 0); | |
702 return true; | |
703 | |
704 case KeyEvent.KEYCODE_5: | |
705 buffer.keyPressed(vt320.KEY_F5, ' ', 0); | |
706 return true; | |
707 | |
708 case KeyEvent.KEYCODE_6: | |
709 buffer.keyPressed(vt320.KEY_F6, ' ', 0); | |
710 return true; | |
711 | |
712 case KeyEvent.KEYCODE_7: | |
713 buffer.keyPressed(vt320.KEY_F7, ' ', 0); | |
714 return true; | |
715 | |
716 case KeyEvent.KEYCODE_8: | |
717 buffer.keyPressed(vt320.KEY_F8, ' ', 0); | |
718 return true; | |
719 | |
720 case KeyEvent.KEYCODE_9: | |
721 buffer.keyPressed(vt320.KEY_F9, ' ', 0); | |
722 return true; | |
723 | |
724 case KeyEvent.KEYCODE_0: | |
725 buffer.keyPressed(vt320.KEY_F10, ' ', 0); | |
726 return true; | |
727 | |
728 default: | |
729 return false; | |
730 } | |
731 } | |
732 | |
733 private boolean sendFullSpecialKey(int keyCode) { | |
734 switch (keyCode) { | |
735 case KeyEvent.KEYCODE_F1: | |
736 buffer.keyPressed(vt320.KEY_F1, ' ', 0); | |
737 return true; | |
738 | |
739 case KeyEvent.KEYCODE_F2: | |
740 buffer.keyPressed(vt320.KEY_F2, ' ', 0); | |
741 return true; | |
742 | |
743 case KeyEvent.KEYCODE_F3: | |
744 buffer.keyPressed(vt320.KEY_F3, ' ', 0); | |
745 return true; | |
746 | |
747 case KeyEvent.KEYCODE_F4: | |
748 buffer.keyPressed(vt320.KEY_F4, ' ', 0); | |
749 return true; | |
750 | |
751 case KeyEvent.KEYCODE_F5: | |
752 buffer.keyPressed(vt320.KEY_F5, ' ', 0); | |
753 return true; | |
754 | |
755 case KeyEvent.KEYCODE_F6: | |
756 buffer.keyPressed(vt320.KEY_F6, ' ', 0); | |
757 return true; | |
758 | |
759 case KeyEvent.KEYCODE_F7: | |
760 buffer.keyPressed(vt320.KEY_F7, ' ', 0); | |
761 return true; | |
762 | |
763 case KeyEvent.KEYCODE_F8: | |
764 buffer.keyPressed(vt320.KEY_F8, ' ', 0); | |
765 return true; | |
766 | |
767 case KeyEvent.KEYCODE_F9: | |
768 buffer.keyPressed(vt320.KEY_F9, ' ', 0); | |
769 return true; | |
770 | |
771 case KeyEvent.KEYCODE_F10: | |
772 buffer.keyPressed(vt320.KEY_F10, ' ', 0); | |
773 return true; | |
774 | |
775 case KeyEvent.KEYCODE_F11: | |
776 buffer.keyPressed(vt320.KEY_F10, ' ', 0); | |
777 return true; | |
778 | |
779 case KeyEvent.KEYCODE_F12: | |
780 buffer.keyPressed(vt320.KEY_F10, ' ', 0); | |
781 return true; | |
782 | |
783 case KeyEvent.KEYCODE_INSERT: | |
784 buffer.keyPressed(vt320.KEY_INSERT, ' ', 0); | |
785 return true; | |
786 | |
787 case KeyEvent.KEYCODE_FORWARD_DEL: | |
788 buffer.keyPressed(vt320.KEY_DELETE, ' ', 0); | |
789 return true; | |
790 | |
791 /* | |
792 case KeyEvent.KEYCODE_PAGE_UP: | |
793 buffer.keyPressed(vt320.KEY_PAGE_UP, ' ', 0); | |
794 return true; | |
795 case KeyEvent.KEYCODE_PAGE_DOWN: | |
796 buffer.keyPressed(vt320.KEY_PAGE_DOWN, ' ', 0); | |
797 return true; | |
798 case KeyEvent.KEYCODE_MOVE_HOME: | |
799 buffer.keyPressed(vt320.KEY_HOME, ' ', getStateForBuffer()); | |
800 return true; | |
801 case KeyEvent.KEYCODE_MOVE_END: | |
802 buffer.keyPressed(vt320.KEY_END, ' ', getStateForBuffer()); | |
803 return true; | |
804 */ | |
805 default: | |
806 return false; | |
807 } | |
808 } | |
809 | |
810 /** | |
811 * Handle meta key presses for full hardware keyboard | |
812 */ | |
813 private void metaKeyDown(int code) { | |
814 if ((metaState & code) == 0) { | |
815 metaState |= code; | |
816 bridge.redraw(); | |
817 } | |
818 } | |
819 | |
820 private void metaKeyUp(int code) { | |
821 if ((metaState & code) != 0) { | |
822 metaState &= ~code; | |
823 bridge.redraw(); | |
824 } | |
825 } | |
826 | |
827 /** | |
828 * Handle meta key presses where the key can be locked on. | |
829 * <p> | |
830 * 1st press: next key to have meta state<br /> | |
831 * 2nd press: meta state is locked on<br /> | |
832 * 3rd press: disable meta state | |
833 * | |
834 * @param code | |
835 */ | |
836 public void metaPress(int code) { | |
837 if ((metaState & (code << 1)) != 0) { | |
838 metaState &= ~(code << 1); | |
839 } | |
840 else if ((metaState & code) != 0) { | |
841 metaState &= ~code; | |
842 | |
843 if (!fullKeyboard()) | |
844 metaState |= code << 1; | |
845 } | |
846 else | |
847 metaState |= code; | |
848 | |
849 bridge.redraw(); | |
850 } | |
851 | |
852 public void setTerminalKeyMode(String keymode) { | |
853 this.keymode = keymode; | |
854 } | |
855 | |
856 private int getStateForBuffer() { | |
857 int bufferState = 0; | |
858 | |
859 if ((metaState & META_CTRL_MASK) != 0) | |
860 bufferState |= vt320.KEY_CONTROL; | |
861 | |
862 if ((metaState & META_SHIFT_MASK) != 0) | |
863 bufferState |= vt320.KEY_SHIFT; | |
864 | |
865 if ((metaState & META_ALT_MASK) != 0) | |
866 bufferState |= vt320.KEY_ALT; | |
867 | |
868 return bufferState; | |
869 } | |
870 | |
871 public int getMetaState() { | |
872 return metaState; | |
873 } | |
874 | |
875 public int getDeadKey() { | |
876 return mDeadKey; | |
877 } | |
878 | |
879 public void setClipboardManager(ClipboardManager clipboard) { | |
880 this.clipboard = clipboard; | |
881 } | |
882 | |
883 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, | |
884 String key) { | |
885 if (PreferenceConstants.KEYMODE.equals(key)) { | |
886 updateKeymode(); | |
887 } | |
888 else if (PreferenceConstants.CUSTOM_KEYMAP.equals(key)) { | |
889 updateCustomKeymap(); | |
890 } | |
891 } | |
892 | |
893 private void updateKeymode() { | |
894 keymode = prefs.getString(PreferenceConstants.KEYMODE, PreferenceConstants.KEYMODE_RIGHT); | |
895 } | |
896 | |
897 private void updateCustomKeymap() { | |
898 customKeyboard = prefs.getString(PreferenceConstants.CUSTOM_KEYMAP, | |
899 PreferenceConstants.CUSTOM_KEYMAP_DISABLED); | |
900 } | |
901 | |
902 public void setCharset(String encoding) { | |
903 this.encoding = encoding; | |
904 } | |
905 | |
48
1e931ef5f776
start tn5250 integration
Carl Byington <carl@five-ten-sg.com>
parents:
45
diff
changeset
|
906 public Charset getCharset() { |
1e931ef5f776
start tn5250 integration
Carl Byington <carl@five-ten-sg.com>
parents:
45
diff
changeset
|
907 return Charset.forName(encoding); |
45
80dcebe51af2
start tn5250 integration
Carl Byington <carl@five-ten-sg.com>
parents:
42
diff
changeset
|
908 } |
0 | 909 |
910 private void ctrlKeySpecial() { | |
911 if (selectingForCopy) { | |
912 if (selectionArea.isSelectingOrigin()) | |
913 selectionArea.finishSelectingOrigin(); | |
914 else { | |
915 if (clipboard != null) { | |
916 // copy selected area to clipboard | |
917 String copiedText = selectionArea.copyFrom(buffer); | |
918 clipboard.setText(copiedText); | |
919 selectingForCopy = false; | |
920 selectionArea.reset(); | |
921 } | |
922 } | |
923 } | |
924 else { | |
925 if ((metaState & META_CTRL_ON) != 0) { | |
926 buffer.write(0x1b); | |
927 metaState &= ~META_CTRL_ON; | |
928 } | |
929 else | |
930 metaPress(META_CTRL_ON); | |
931 } | |
932 | |
933 bridge.redraw(); | |
934 } | |
935 | |
936 private boolean customKeymapAction(View v, int keyCode, KeyEvent event) { | |
937 if (bridge == null || customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_DISABLED)) | |
938 return false; | |
939 | |
940 byte c = 0x00; | |
941 int termKey = 0; | |
942 | |
943 if (fullKeyboard()) { | |
944 switch (keyCode) { | |
945 case KeyEvent.KEYCODE_CTRL_LEFT: | |
946 case KeyEvent.KEYCODE_CTRL_RIGHT: | |
947 metaKeyDown(META_CTRL_ON); | |
948 return true; | |
949 | |
950 case KeyEvent.KEYCODE_ALT_LEFT: | |
951 case KeyEvent.KEYCODE_ALT_RIGHT: | |
952 metaKeyDown(META_ALT_ON); | |
953 return true; | |
954 | |
955 case KeyEvent.KEYCODE_SHIFT_LEFT: | |
956 case KeyEvent.KEYCODE_SHIFT_RIGHT: | |
957 metaKeyDown(META_SHIFT_ON); | |
958 return true; | |
959 | |
960 case KeyEvent.KEYCODE_BACK: | |
961 if (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_ASUS_TF)) { | |
962 // Check to see whether this is the back button on the | |
963 // screen (-1) or the Asus Transformer Keyboard Dock. | |
964 // Treat the HW button as ESC. | |
965 if (event.getDeviceId() > 0) { | |
966 buffer.write(0x1b); | |
967 return true; | |
968 } | |
969 } | |
970 | |
971 default: | |
972 } | |
973 } | |
974 | |
975 if (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_ASUS_TF)) { | |
976 if ((metaState & META_ALT_MASK) != 0 | |
977 && (metaState & META_SHIFT_MASK) != 0 | |
978 && sendFunctionKey(keyCode)) | |
979 return true; | |
980 } | |
981 else if (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_SE_XPPRO)) { | |
982 // Sony Ericsson Xperia pro (MK16i) and Xperia mini Pro (SK17i) | |
983 // Language key acts as CTRL | |
984 if (keyCode == KeyEvent.KEYCODE_SWITCH_CHARSET) { | |
985 ctrlKeySpecial(); | |
986 return true; | |
987 } | |
988 | |
989 if ((metaState & META_ALT_MASK) != 0) { | |
990 if ((metaState & META_SHIFT_MASK) != 0) { | |
991 // ALT + shift + key | |
992 switch (keyCode) { | |
993 case KeyEvent.KEYCODE_U: | |
994 c = 0x5B; | |
995 break; | |
996 | |
997 case KeyEvent.KEYCODE_I: | |
998 c = 0x5D; | |
999 break; | |
1000 | |
1001 case KeyEvent.KEYCODE_O: | |
1002 c = 0x7B; | |
1003 break; | |
1004 | |
1005 case KeyEvent.KEYCODE_P: | |
1006 c = 0x7D; | |
1007 break; | |
1008 } | |
1009 } | |
1010 else { | |
1011 // ALT + key | |
1012 switch (keyCode) { | |
1013 case KeyEvent.KEYCODE_S: | |
1014 c = 0x7c; | |
1015 break; | |
1016 | |
1017 case KeyEvent.KEYCODE_Z: | |
1018 c = 0x5c; | |
1019 break; | |
1020 | |
1021 case KeyEvent.KEYCODE_DEL: | |
1022 termKey = vt320.KEY_DELETE; | |
1023 break; | |
1024 } | |
1025 } | |
1026 } | |
1027 else if ((metaState & META_SHIFT_MASK) != 0) { | |
1028 // shift + key | |
1029 switch (keyCode) { | |
1030 case KeyEvent.KEYCODE_AT: | |
1031 c = 0x3c; | |
1032 break; | |
1033 | |
1034 case KeyEvent.KEYCODE_COMMA: | |
1035 c = 0x3e; | |
1036 break; | |
1037 | |
1038 case KeyEvent.KEYCODE_PERIOD: | |
1039 c = 0x5e; | |
1040 break; | |
1041 | |
1042 case KeyEvent.KEYCODE_GRAVE: | |
1043 c = 0x60; | |
1044 break; | |
1045 | |
1046 case KeyEvent.KEYCODE_APOSTROPHE: | |
1047 c = 0x7e; | |
1048 break; | |
1049 | |
1050 case KeyEvent.KEYCODE_DEL: | |
1051 termKey = vt320.KEY_BACK_SPACE; | |
1052 break; | |
1053 } | |
1054 } | |
1055 } | |
1056 else if (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_SGH_I927)) { | |
1057 // Samsung Captivate Glide (SGH-i927) | |
1058 if (keyCode == 115) { | |
1059 // .com key = ESC | |
1060 c = 0x1b; | |
1061 return true; | |
1062 } | |
1063 else if (keyCode == 116) { | |
1064 // Microphone key = TAB | |
1065 c = 0x09; | |
1066 } | |
1067 else if ((metaState & META_ALT_MASK) != 0 && (metaState & META_SHIFT_MASK) != 0) { | |
1068 switch (keyCode) { | |
1069 case KeyEvent.KEYCODE_O: | |
1070 c = 0x5B; | |
1071 break; | |
1072 | |
1073 case KeyEvent.KEYCODE_P: | |
1074 c = 0x5D; | |
1075 break; | |
1076 | |
1077 case KeyEvent.KEYCODE_A: | |
1078 c = 0x3C; | |
1079 break; | |
1080 | |
1081 case KeyEvent.KEYCODE_D: | |
1082 c = 0x3E; | |
1083 break; | |
1084 } | |
1085 } | |
1086 } | |
1087 else if (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_SGH_I927_ICS)) { | |
1088 // Samsung Captivate Glide (SGH-i927) Ice Cream Sandwich (4.0.x) | |
1089 if (keyCode == 226) { | |
1090 // .com key = ESC | |
1091 c = 0x1b; | |
1092 } | |
1093 else if (keyCode == 220) { | |
1094 // Microphone key = TAB | |
1095 c = 0x09; | |
1096 } | |
1097 else if ((metaState & META_ALT_MASK) != 0 && (metaState & META_SHIFT_MASK) != 0) { | |
1098 switch (keyCode) { | |
1099 case KeyEvent.KEYCODE_O: | |
1100 c = 0x5B; | |
1101 break; | |
1102 | |
1103 case KeyEvent.KEYCODE_P: | |
1104 c = 0x5D; | |
1105 break; | |
1106 | |
1107 case KeyEvent.KEYCODE_A: | |
1108 c = 0x3C; | |
1109 break; | |
1110 | |
1111 case KeyEvent.KEYCODE_D: | |
1112 c = 0x3E; | |
1113 break; | |
1114 } | |
1115 } | |
1116 } | |
1117 | |
1118 if ((c != 0x00) || termKey != 0) { | |
1119 if (c != 0x00) | |
1120 buffer.write(c); | |
1121 else | |
1122 buffer.keyPressed(termKey, ' ', 0); | |
1123 | |
1124 metaState &= ~(META_SHIFT_ON | META_ALT_ON); | |
1125 bridge.redraw(); | |
1126 return true; | |
1127 } | |
1128 | |
1129 return false; | |
1130 } | |
1131 | |
1132 public void urlScan(View v) { | |
1133 //final TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); | |
1134 List<String> urls = bridge.scanForURLs(); | |
1135 Dialog urlDialog = new Dialog(v.getContext()); | |
1136 urlDialog.setTitle(R.string.console_menu_urlscan); | |
1137 ListView urlListView = new ListView(v.getContext()); | |
1138 URLItemListener urlListener = new URLItemListener(v.getContext()); | |
1139 urlListView.setOnItemClickListener(urlListener); | |
1140 urlListView.setAdapter(new ArrayAdapter<String> (v.getContext(), android.R.layout.simple_list_item_1, urls)); | |
1141 urlDialog.setContentView(urlListView); | |
1142 urlDialog.show(); | |
1143 } | |
1144 | |
1145 public boolean isSymKey(int keyCode) { | |
1146 if (keyCode == KeyEvent.KEYCODE_SYM || | |
1147 keyCode == KeyEvent.KEYCODE_PICTSYMBOLS) | |
1148 return true; | |
1149 | |
1150 if (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_SGH_I927_ICS) && | |
1151 keyCode == 227) | |
1152 return true; | |
1153 | |
1154 return false; | |
1155 } | |
1156 | |
1157 private boolean fullKeyboard() { | |
1158 if (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_FULL) || | |
1159 (customKeyboard.equals(PreferenceConstants.CUSTOM_KEYMAP_ASUS_TF))) | |
1160 return true; | |
1161 | |
1162 return false; | |
1163 } | |
1164 | |
1165 private class URLItemListener implements OnItemClickListener { | |
1166 private WeakReference<Context> contextRef; | |
1167 | |
1168 URLItemListener(Context context) { | |
1169 this.contextRef = new WeakReference<Context> (context); | |
1170 } | |
1171 | |
1172 public void onItemClick(AdapterView<?> arg0, View view, int position, | |
1173 long id) { | |
1174 Context context = contextRef.get(); | |
1175 | |
1176 if (context == null) | |
1177 return; | |
1178 | |
1179 try { | |
1180 TextView urlView = (TextView) view; | |
1181 String url = urlView.getText().toString(); | |
1182 | |
1183 if (url.indexOf("://") < 0) | |
1184 url = "http://" + url; | |
1185 | |
1186 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); | |
1187 context.startActivity(intent); | |
1188 } | |
1189 catch (Exception e) { | |
1190 Log.e(TAG, "couldn't open URL", e); | |
1191 // We should probably tell the user that we couldn't find a | |
1192 // handler... | |
1193 } | |
1194 } | |
1195 } | |
1196 } | |
1197 |