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