FreeRDP
KeyboardMapper.java
1 /*
2  Android Keyboard Mapping
3 
4  Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
5 
6  This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
7  If a copy of the MPL was not distributed with this file, You can obtain one at
8  http://mozilla.org/MPL/2.0/.
9 */
10 
11 package com.freerdp.freerdpcore.utils;
12 
13 import android.content.Context;
14 import android.view.KeyEvent;
15 
16 import com.freerdp.freerdpcore.R;
17 
18 public class KeyboardMapper
19 {
20  public static final int KEYBOARD_TYPE_FUNCTIONKEYS = 1;
21  public static final int KEYBOARD_TYPE_NUMPAD = 2;
22  public static final int KEYBOARD_TYPE_CURSOR = 3;
23 
24  // defines key states for modifier keys - locked means on and no auto-release if an other key is
25  // pressed
26  public static final int KEYSTATE_ON = 1;
27  public static final int KEYSTATE_LOCKED = 2;
28  public static final int KEYSTATE_OFF = 3;
29  final static int VK_LBUTTON = 0x01;
30  final static int VK_RBUTTON = 0x02;
31  final static int VK_CANCEL = 0x03;
32  final static int VK_MBUTTON = 0x04;
33  final static int VK_XBUTTON1 = 0x05;
34  final static int VK_XBUTTON2 = 0x06;
35  final static int VK_BACK = 0x08;
36  final static int VK_TAB = 0x09;
37  final static int VK_CLEAR = 0x0C;
38  final static int VK_RETURN = 0x0D;
39  final static int VK_SHIFT = 0x10;
40  final static int VK_CONTROL = 0x11;
41  final static int VK_MENU = 0x12;
42  final static int VK_PAUSE = 0x13;
43  final static int VK_CAPITAL = 0x14;
44  final static int VK_KANA = 0x15;
45  final static int VK_HANGUEL = 0x15;
46  final static int VK_HANGUL = 0x15;
47  final static int VK_JUNJA = 0x17;
48  final static int VK_FINAL = 0x18;
49  final static int VK_HANJA = 0x19;
50  final static int VK_KANJI = 0x19;
51  final static int VK_ESCAPE = 0x1B;
52  final static int VK_CONVERT = 0x1C;
53  final static int VK_NONCONVERT = 0x1D;
54  final static int VK_ACCEPT = 0x1E;
55  final static int VK_MODECHANGE = 0x1F;
56  final static int VK_SPACE = 0x20;
57  final static int VK_PRIOR = 0x21;
58  final static int VK_NEXT = 0x22;
59  final static int VK_END = 0x23;
60  final static int VK_HOME = 0x24;
61  final static int VK_LEFT = 0x25;
62  final static int VK_UP = 0x26;
63  final static int VK_RIGHT = 0x27;
64  final static int VK_DOWN = 0x28;
65  final static int VK_SELECT = 0x29;
66  final static int VK_PRINT = 0x2A;
67  final static int VK_EXECUTE = 0x2B;
68  final static int VK_SNAPSHOT = 0x2C;
69  final static int VK_INSERT = 0x2D;
70  final static int VK_DELETE = 0x2E;
71  final static int VK_HELP = 0x2F;
72  final static int VK_KEY_0 = 0x30;
73  final static int VK_KEY_1 = 0x31;
74  final static int VK_KEY_2 = 0x32;
75  final static int VK_KEY_3 = 0x33;
76  final static int VK_KEY_4 = 0x34;
77  final static int VK_KEY_5 = 0x35;
78  final static int VK_KEY_6 = 0x36;
79  final static int VK_KEY_7 = 0x37;
80  final static int VK_KEY_8 = 0x38;
81  final static int VK_KEY_9 = 0x39;
82  final static int VK_KEY_A = 0x41;
83  final static int VK_KEY_B = 0x42;
84  final static int VK_KEY_C = 0x43;
85  final static int VK_KEY_D = 0x44;
86  final static int VK_KEY_E = 0x45;
87  final static int VK_KEY_F = 0x46;
88  final static int VK_KEY_G = 0x47;
89  final static int VK_KEY_H = 0x48;
90  final static int VK_KEY_I = 0x49;
91  final static int VK_KEY_J = 0x4A;
92  final static int VK_KEY_K = 0x4B;
93  final static int VK_KEY_L = 0x4C;
94  final static int VK_KEY_M = 0x4D;
95  final static int VK_KEY_N = 0x4E;
96  final static int VK_KEY_O = 0x4F;
97  final static int VK_KEY_P = 0x50;
98  final static int VK_KEY_Q = 0x51;
99  final static int VK_KEY_R = 0x52;
100  final static int VK_KEY_S = 0x53;
101  final static int VK_KEY_T = 0x54;
102  final static int VK_KEY_U = 0x55;
103  final static int VK_KEY_V = 0x56;
104  final static int VK_KEY_W = 0x57;
105  final static int VK_KEY_X = 0x58;
106  final static int VK_KEY_Y = 0x59;
107  final static int VK_KEY_Z = 0x5A;
108  final static int VK_LWIN = 0x5B;
109  final static int VK_RWIN = 0x5C;
110  final static int VK_APPS = 0x5D;
111  final static int VK_SLEEP = 0x5F;
112  final static int VK_NUMPAD0 = 0x60;
113  final static int VK_NUMPAD1 = 0x61;
114  final static int VK_NUMPAD2 = 0x62;
115  final static int VK_NUMPAD3 = 0x63;
116  final static int VK_NUMPAD4 = 0x64;
117  final static int VK_NUMPAD5 = 0x65;
118  final static int VK_NUMPAD6 = 0x66;
119  final static int VK_NUMPAD7 = 0x67;
120  final static int VK_NUMPAD8 = 0x68;
121  final static int VK_NUMPAD9 = 0x69;
122  final static int VK_MULTIPLY = 0x6A;
123  final static int VK_ADD = 0x6B;
124  final static int VK_SEPARATOR = 0x6C;
125  final static int VK_SUBTRACT = 0x6D;
126  final static int VK_DECIMAL = 0x6E;
127  final static int VK_DIVIDE = 0x6F;
128  final static int VK_F1 = 0x70;
129  final static int VK_F2 = 0x71;
130  final static int VK_F3 = 0x72;
131  final static int VK_F4 = 0x73;
132  final static int VK_F5 = 0x74;
133  final static int VK_F6 = 0x75;
134  final static int VK_F7 = 0x76;
135  final static int VK_F8 = 0x77;
136  final static int VK_F9 = 0x78;
137  final static int VK_F10 = 0x79;
138  final static int VK_F11 = 0x7A;
139  final static int VK_F12 = 0x7B;
140  final static int VK_F13 = 0x7C;
141  final static int VK_F14 = 0x7D;
142  final static int VK_F15 = 0x7E;
143  final static int VK_F16 = 0x7F;
144  final static int VK_F17 = 0x80;
145  final static int VK_F18 = 0x81;
146  final static int VK_F19 = 0x82;
147  final static int VK_F20 = 0x83;
148  final static int VK_F21 = 0x84;
149  final static int VK_F22 = 0x85;
150  final static int VK_F23 = 0x86;
151  final static int VK_F24 = 0x87;
152  final static int VK_NUMLOCK = 0x90;
153  final static int VK_SCROLL = 0x91;
154  final static int VK_LSHIFT = 0xA0;
155  final static int VK_RSHIFT = 0xA1;
156  final static int VK_LCONTROL = 0xA2;
157  final static int VK_RCONTROL = 0xA3;
158  final static int VK_LMENU = 0xA4;
159  final static int VK_RMENU = 0xA5;
160  final static int VK_BROWSER_BACK = 0xA6;
161  final static int VK_BROWSER_FORWARD = 0xA7;
162  final static int VK_BROWSER_REFRESH = 0xA8;
163  final static int VK_BROWSER_STOP = 0xA9;
164  final static int VK_BROWSER_SEARCH = 0xAA;
165  final static int VK_BROWSER_FAVORITES = 0xAB;
166  final static int VK_BROWSER_HOME = 0xAC;
167  final static int VK_VOLUME_MUTE = 0xAD;
168  final static int VK_VOLUME_DOWN = 0xAE;
169  final static int VK_VOLUME_UP = 0xAF;
170  final static int VK_MEDIA_NEXT_TRACK = 0xB0;
171  final static int VK_MEDIA_PREV_TRACK = 0xB1;
172  final static int VK_MEDIA_STOP = 0xB2;
173  final static int VK_MEDIA_PLAY_PAUSE = 0xB3;
174  final static int VK_LAUNCH_MAIL = 0xB4;
175  final static int VK_LAUNCH_MEDIA_SELECT = 0xB5;
176  final static int VK_LAUNCH_APP1 = 0xB6;
177  final static int VK_LAUNCH_APP2 = 0xB7;
178  final static int VK_OEM_1 = 0xBA;
179  final static int VK_OEM_PLUS = 0xBB;
180  final static int VK_OEM_COMMA = 0xBC;
181  final static int VK_OEM_MINUS = 0xBD;
182  final static int VK_OEM_PERIOD = 0xBE;
183  final static int VK_OEM_2 = 0xBF;
184  final static int VK_OEM_3 = 0xC0;
185  final static int VK_ABNT_C1 = 0xC1;
186  final static int VK_ABNT_C2 = 0xC2;
187  final static int VK_OEM_4 = 0xDB;
188  final static int VK_OEM_5 = 0xDC;
189  final static int VK_OEM_6 = 0xDD;
190  final static int VK_OEM_7 = 0xDE;
191  final static int VK_OEM_8 = 0xDF;
192  final static int VK_OEM_102 = 0xE2;
193  final static int VK_PROCESSKEY = 0xE5;
194  final static int VK_PACKET = 0xE7;
195  final static int VK_ATTN = 0xF6;
196  final static int VK_CRSEL = 0xF7;
197  final static int VK_EXSEL = 0xF8;
198  final static int VK_EREOF = 0xF9;
199  final static int VK_PLAY = 0xFA;
200  final static int VK_ZOOM = 0xFB;
201  final static int VK_NONAME = 0xFC;
202  final static int VK_PA1 = 0xFD;
203  final static int VK_OEM_CLEAR = 0xFE;
204  final static int VK_UNICODE = 0x80000000;
205  final static int VK_EXT_KEY = 0x00000100;
206  // key codes to switch between custom keyboard
207  private final static int EXTKEY_KBFUNCTIONKEYS = 0x1100;
208  private final static int EXTKEY_KBNUMPAD = 0x1101;
209  private final static int EXTKEY_KBCURSOR = 0x1102;
210  // this flag indicates if we got a VK or a unicode character in our translation map
211  private static final int KEY_FLAG_UNICODE = 0x80000000;
212  // this flag indicates if the key is a toggle key (remains down when pressed and goes up if
213  // pressed again)
214  private static final int KEY_FLAG_TOGGLE = 0x40000000;
215  private static int[] keymapAndroid;
216  private static int[] keymapExt;
217  private static boolean initialized = false;
218  private KeyProcessingListener listener = null;
219  private boolean shiftPressed = false;
220  private boolean ctrlPressed = false;
221  private boolean altPressed = false;
222  private boolean winPressed = false;
223  private long lastModifierTime;
224  private int lastModifierKeyCode = -1;
225  private boolean isShiftLocked = false;
226  private boolean isCtrlLocked = false;
227  private boolean isAltLocked = false;
228  private boolean isWinLocked = false;
229 
230  public void init(Context context)
231  {
232  if (initialized == true)
233  return;
234 
235  keymapAndroid = new int[256];
236 
237  keymapAndroid[KeyEvent.KEYCODE_0] = VK_KEY_0;
238  keymapAndroid[KeyEvent.KEYCODE_1] = VK_KEY_1;
239  keymapAndroid[KeyEvent.KEYCODE_2] = VK_KEY_2;
240  keymapAndroid[KeyEvent.KEYCODE_3] = VK_KEY_3;
241  keymapAndroid[KeyEvent.KEYCODE_4] = VK_KEY_4;
242  keymapAndroid[KeyEvent.KEYCODE_5] = VK_KEY_5;
243  keymapAndroid[KeyEvent.KEYCODE_6] = VK_KEY_6;
244  keymapAndroid[KeyEvent.KEYCODE_7] = VK_KEY_7;
245  keymapAndroid[KeyEvent.KEYCODE_8] = VK_KEY_8;
246  keymapAndroid[KeyEvent.KEYCODE_9] = VK_KEY_9;
247 
248  keymapAndroid[KeyEvent.KEYCODE_A] = VK_KEY_A;
249  keymapAndroid[KeyEvent.KEYCODE_B] = VK_KEY_B;
250  keymapAndroid[KeyEvent.KEYCODE_C] = VK_KEY_C;
251  keymapAndroid[KeyEvent.KEYCODE_D] = VK_KEY_D;
252  keymapAndroid[KeyEvent.KEYCODE_E] = VK_KEY_E;
253  keymapAndroid[KeyEvent.KEYCODE_F] = VK_KEY_F;
254  keymapAndroid[KeyEvent.KEYCODE_G] = VK_KEY_G;
255  keymapAndroid[KeyEvent.KEYCODE_H] = VK_KEY_H;
256  keymapAndroid[KeyEvent.KEYCODE_I] = VK_KEY_I;
257  keymapAndroid[KeyEvent.KEYCODE_J] = VK_KEY_J;
258  keymapAndroid[KeyEvent.KEYCODE_K] = VK_KEY_K;
259  keymapAndroid[KeyEvent.KEYCODE_L] = VK_KEY_L;
260  keymapAndroid[KeyEvent.KEYCODE_M] = VK_KEY_M;
261  keymapAndroid[KeyEvent.KEYCODE_N] = VK_KEY_N;
262  keymapAndroid[KeyEvent.KEYCODE_O] = VK_KEY_O;
263  keymapAndroid[KeyEvent.KEYCODE_P] = VK_KEY_P;
264  keymapAndroid[KeyEvent.KEYCODE_Q] = VK_KEY_Q;
265  keymapAndroid[KeyEvent.KEYCODE_R] = VK_KEY_R;
266  keymapAndroid[KeyEvent.KEYCODE_S] = VK_KEY_S;
267  keymapAndroid[KeyEvent.KEYCODE_T] = VK_KEY_T;
268  keymapAndroid[KeyEvent.KEYCODE_U] = VK_KEY_U;
269  keymapAndroid[KeyEvent.KEYCODE_V] = VK_KEY_V;
270  keymapAndroid[KeyEvent.KEYCODE_W] = VK_KEY_W;
271  keymapAndroid[KeyEvent.KEYCODE_X] = VK_KEY_X;
272  keymapAndroid[KeyEvent.KEYCODE_Y] = VK_KEY_Y;
273  keymapAndroid[KeyEvent.KEYCODE_Z] = VK_KEY_Z;
274 
275  keymapAndroid[KeyEvent.KEYCODE_DEL] = VK_BACK;
276  keymapAndroid[KeyEvent.KEYCODE_ENTER] = VK_RETURN;
277  keymapAndroid[KeyEvent.KEYCODE_SPACE] = VK_SPACE;
278  keymapAndroid[KeyEvent.KEYCODE_TAB] = VK_TAB;
279  // keymapAndroid[KeyEvent.KEYCODE_SHIFT_LEFT] = VK_LSHIFT;
280  // keymapAndroid[KeyEvent.KEYCODE_SHIFT_RIGHT] = VK_RSHIFT;
281 
282  // keymapAndroid[KeyEvent.KEYCODE_DPAD_DOWN] = VK_DOWN;
283  // keymapAndroid[KeyEvent.KEYCODE_DPAD_LEFT] = VK_LEFT;
284  // keymapAndroid[KeyEvent.KEYCODE_DPAD_RIGHT] = VK_RIGHT;
285  // keymapAndroid[KeyEvent.KEYCODE_DPAD_UP] = VK_UP;
286 
287  // keymapAndroid[KeyEvent.KEYCODE_COMMA] = VK_OEM_COMMA;
288  // keymapAndroid[KeyEvent.KEYCODE_PERIOD] = VK_OEM_PERIOD;
289  // keymapAndroid[KeyEvent.KEYCODE_MINUS] = VK_OEM_MINUS;
290  // keymapAndroid[KeyEvent.KEYCODE_PLUS] = VK_OEM_PLUS;
291 
292  // keymapAndroid[KeyEvent.KEYCODE_ALT_LEFT] = VK_LMENU;
293  // keymapAndroid[KeyEvent.KEYCODE_ALT_RIGHT] = VK_RMENU;
294 
295  // keymapAndroid[KeyEvent.KEYCODE_AT] = (KEY_FLAG_UNICODE | 64);
296  // keymapAndroid[KeyEvent.KEYCODE_APOSTROPHE] = (KEY_FLAG_UNICODE | 39);
297  // keymapAndroid[KeyEvent.KEYCODE_BACKSLASH] = (KEY_FLAG_UNICODE | 92);
298  // keymapAndroid[KeyEvent.KEYCODE_COMMA] = (KEY_FLAG_UNICODE | 44);
299  // keymapAndroid[KeyEvent.KEYCODE_EQUALS] = (KEY_FLAG_UNICODE | 61);
300  // keymapAndroid[KeyEvent.KEYCODE_GRAVE] = (KEY_FLAG_UNICODE | 96);
301  // keymapAndroid[KeyEvent.KEYCODE_LEFT_BRACKET] = (KEY_FLAG_UNICODE | 91);
302  // keymapAndroid[KeyEvent.KEYCODE_RIGHT_BRACKET] = (KEY_FLAG_UNICODE | 93);
303  // keymapAndroid[KeyEvent.KEYCODE_MINUS] = (KEY_FLAG_UNICODE | 45);
304  // keymapAndroid[KeyEvent.KEYCODE_PERIOD] = (KEY_FLAG_UNICODE | 46);
305  // keymapAndroid[KeyEvent.KEYCODE_PLUS] = (KEY_FLAG_UNICODE | 43);
306  // keymapAndroid[KeyEvent.KEYCODE_POUND] = (KEY_FLAG_UNICODE | 35);
307  // keymapAndroid[KeyEvent.KEYCODE_SEMICOLON] = (KEY_FLAG_UNICODE | 59);
308  // keymapAndroid[KeyEvent.KEYCODE_SLASH] = (KEY_FLAG_UNICODE | 47);
309  // keymapAndroid[KeyEvent.KEYCODE_STAR] = (KEY_FLAG_UNICODE | 42);
310 
311  // special keys mapping
312  keymapExt = new int[256];
313  keymapExt[context.getResources().getInteger(R.integer.keycode_F1)] = VK_F1;
314  keymapExt[context.getResources().getInteger(R.integer.keycode_F2)] = VK_F2;
315  keymapExt[context.getResources().getInteger(R.integer.keycode_F3)] = VK_F3;
316  keymapExt[context.getResources().getInteger(R.integer.keycode_F4)] = VK_F4;
317  keymapExt[context.getResources().getInteger(R.integer.keycode_F5)] = VK_F5;
318  keymapExt[context.getResources().getInteger(R.integer.keycode_F6)] = VK_F6;
319  keymapExt[context.getResources().getInteger(R.integer.keycode_F7)] = VK_F7;
320  keymapExt[context.getResources().getInteger(R.integer.keycode_F8)] = VK_F8;
321  keymapExt[context.getResources().getInteger(R.integer.keycode_F9)] = VK_F9;
322  keymapExt[context.getResources().getInteger(R.integer.keycode_F10)] = VK_F10;
323  keymapExt[context.getResources().getInteger(R.integer.keycode_F11)] = VK_F11;
324  keymapExt[context.getResources().getInteger(R.integer.keycode_F12)] = VK_F12;
325  keymapExt[context.getResources().getInteger(R.integer.keycode_tab)] = VK_TAB;
326  keymapExt[context.getResources().getInteger(R.integer.keycode_print)] = VK_PRINT;
327  keymapExt[context.getResources().getInteger(R.integer.keycode_insert)] =
328  VK_INSERT | VK_EXT_KEY;
329  keymapExt[context.getResources().getInteger(R.integer.keycode_delete)] =
330  VK_DELETE | VK_EXT_KEY;
331  keymapExt[context.getResources().getInteger(R.integer.keycode_home)] = VK_HOME | VK_EXT_KEY;
332  keymapExt[context.getResources().getInteger(R.integer.keycode_end)] = VK_END | VK_EXT_KEY;
333  keymapExt[context.getResources().getInteger(R.integer.keycode_pgup)] =
334  VK_PRIOR | VK_EXT_KEY;
335  keymapExt[context.getResources().getInteger(R.integer.keycode_pgdn)] = VK_NEXT | VK_EXT_KEY;
336 
337  // numpad mapping
338  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_0)] = VK_NUMPAD0;
339  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_1)] = VK_NUMPAD1;
340  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_2)] = VK_NUMPAD2;
341  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_3)] = VK_NUMPAD3;
342  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_4)] = VK_NUMPAD4;
343  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_5)] = VK_NUMPAD5;
344  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_6)] = VK_NUMPAD6;
345  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_7)] = VK_NUMPAD7;
346  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_8)] = VK_NUMPAD8;
347  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_9)] = VK_NUMPAD9;
348  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_numlock)] = VK_NUMLOCK;
349  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_add)] = VK_ADD;
350  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_comma)] = VK_DECIMAL;
351  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_divide)] =
352  VK_DIVIDE | VK_EXT_KEY;
353  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_enter)] =
354  VK_RETURN | VK_EXT_KEY;
355  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_multiply)] =
356  VK_MULTIPLY;
357  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_subtract)] =
358  VK_SUBTRACT;
359  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_equals)] =
360  (KEY_FLAG_UNICODE | 61);
361  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_left_paren)] =
362  (KEY_FLAG_UNICODE | 40);
363  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_right_paren)] =
364  (KEY_FLAG_UNICODE | 41);
365 
366  // cursor key codes
367  keymapExt[context.getResources().getInteger(R.integer.keycode_up)] = VK_UP | VK_EXT_KEY;
368  keymapExt[context.getResources().getInteger(R.integer.keycode_down)] = VK_DOWN | VK_EXT_KEY;
369  keymapExt[context.getResources().getInteger(R.integer.keycode_left)] = VK_LEFT | VK_EXT_KEY;
370  keymapExt[context.getResources().getInteger(R.integer.keycode_right)] =
371  VK_RIGHT | VK_EXT_KEY;
372  keymapExt[context.getResources().getInteger(R.integer.keycode_enter)] =
373  VK_RETURN | VK_EXT_KEY;
374  keymapExt[context.getResources().getInteger(R.integer.keycode_backspace)] = VK_BACK;
375 
376  // shared keys
377  keymapExt[context.getResources().getInteger(R.integer.keycode_win)] = VK_LWIN | VK_EXT_KEY;
378  keymapExt[context.getResources().getInteger(R.integer.keycode_menu)] = VK_APPS | VK_EXT_KEY;
379  keymapExt[context.getResources().getInteger(R.integer.keycode_esc)] = VK_ESCAPE;
380 
381  /* keymapExt[context.getResources().getInteger(R.integer.keycode_modifier_ctrl)] =
382  VK_LCONTROL; keymapExt[context.getResources().getInteger(R.integer.keycode_modifier_alt)]
383  = VK_LMENU;
384  keymapExt[context.getResources().getInteger(R.integer.keycode_modifier_shift)] =
385  VK_LSHIFT;
386  */
387  // get custom keyboard key codes
388  keymapExt[context.getResources().getInteger(R.integer.keycode_specialkeys_keyboard)] =
389  EXTKEY_KBFUNCTIONKEYS;
390  keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_keyboard)] =
391  EXTKEY_KBNUMPAD;
392  keymapExt[context.getResources().getInteger(R.integer.keycode_cursor_keyboard)] =
393  EXTKEY_KBCURSOR;
394 
395  keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_shift)] =
396  (KEY_FLAG_TOGGLE | VK_LSHIFT);
397  keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_ctrl)] =
398  (KEY_FLAG_TOGGLE | VK_LCONTROL);
399  keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_alt)] =
400  (KEY_FLAG_TOGGLE | VK_LMENU);
401  keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_win)] =
402  (KEY_FLAG_TOGGLE | VK_LWIN);
403 
404  initialized = true;
405  }
406 
407  public void reset(KeyProcessingListener listener)
408  {
409  shiftPressed = false;
410  ctrlPressed = false;
411  altPressed = false;
412  winPressed = false;
413  setKeyProcessingListener(listener);
414  }
415 
416  public void setKeyProcessingListener(KeyProcessingListener listener)
417  {
418  this.listener = listener;
419  }
420 
421  public boolean processAndroidKeyEvent(KeyEvent event)
422  {
423  switch (event.getAction())
424  {
425  // we only process down events
426  case KeyEvent.ACTION_UP:
427  {
428  return false;
429  }
430 
431  case KeyEvent.ACTION_DOWN:
432  {
433  boolean modifierActive = isModifierPressed();
434  // if a modifier is pressed we will send a VK event (if possible) so that key
435  // combinations will be recognized correctly. Otherwise we will send the unicode
436  // key. At the end we will reset all modifiers and notifiy our listener.
437  int vkcode = getVirtualKeyCode(event.getKeyCode());
438  if ((vkcode & KEY_FLAG_UNICODE) != 0)
439  listener.processUnicodeKey(vkcode & (~KEY_FLAG_UNICODE));
440  // if we got a valid vkcode send it - except for letters/numbers if a modifier is
441  // active
442  else if (vkcode > 0 &&
443  (event.getMetaState() & (KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON |
444  KeyEvent.META_SYM_ON)) == 0)
445  {
446  listener.processVirtualKey(vkcode, true);
447  listener.processVirtualKey(vkcode, false);
448  }
449  else if (event.isShiftPressed() && vkcode != 0)
450  {
451  listener.processVirtualKey(VK_LSHIFT, true);
452  listener.processVirtualKey(vkcode, true);
453  listener.processVirtualKey(vkcode, false);
454  listener.processVirtualKey(VK_LSHIFT, false);
455  }
456  else if (event.getUnicodeChar() != 0)
457  listener.processUnicodeKey(event.getUnicodeChar());
458  else
459  return false;
460 
461  // reset any pending toggle states if a modifier was pressed
462  if (modifierActive)
463  resetModifierKeysAfterInput(false);
464  return true;
465  }
466 
467  case KeyEvent.ACTION_MULTIPLE:
468  {
469  String str = event.getCharacters();
470  for (int i = 0; i < str.length(); i++)
471  listener.processUnicodeKey(str.charAt(i));
472  return true;
473  }
474 
475  default:
476  break;
477  }
478  return false;
479  }
480 
481  public void processCustomKeyEvent(int keycode)
482  {
483  int extCode = getExtendedKeyCode(keycode);
484  if (extCode == 0)
485  return;
486 
487  // toggle button pressed?
488  if ((extCode & KEY_FLAG_TOGGLE) != 0)
489  {
490  processToggleButton(extCode & (~KEY_FLAG_TOGGLE));
491  return;
492  }
493 
494  // keyboard switch button pressed?
495  if (extCode == EXTKEY_KBFUNCTIONKEYS || extCode == EXTKEY_KBNUMPAD ||
496  extCode == EXTKEY_KBCURSOR)
497  {
498  switchKeyboard(extCode);
499  return;
500  }
501 
502  // nope - see if we got a unicode or vk
503  if ((extCode & KEY_FLAG_UNICODE) != 0)
504  listener.processUnicodeKey(extCode & (~KEY_FLAG_UNICODE));
505  else
506  {
507  listener.processVirtualKey(extCode, true);
508  listener.processVirtualKey(extCode, false);
509  }
510 
511  resetModifierKeysAfterInput(false);
512  }
513 
514  public void sendAltF4()
515  {
516  listener.processVirtualKey(VK_LMENU, true);
517  listener.processVirtualKey(VK_F4, true);
518  listener.processVirtualKey(VK_F4, false);
519  listener.processVirtualKey(VK_LMENU, false);
520  }
521 
522  private boolean isModifierPressed()
523  {
524  return (shiftPressed || ctrlPressed || altPressed || winPressed);
525  }
526 
527  public int getModifierState(int keycode)
528  {
529  int modifierCode = getExtendedKeyCode(keycode);
530 
531  // check and get real modifier keycode
532  if ((modifierCode & KEY_FLAG_TOGGLE) == 0)
533  return -1;
534  modifierCode = modifierCode & (~KEY_FLAG_TOGGLE);
535 
536  switch (modifierCode)
537  {
538  case VK_LSHIFT:
539  {
540  return (shiftPressed ? (isShiftLocked ? KEYSTATE_LOCKED : KEYSTATE_ON)
541  : KEYSTATE_OFF);
542  }
543  case VK_LCONTROL:
544  {
545  return (ctrlPressed ? (isCtrlLocked ? KEYSTATE_LOCKED : KEYSTATE_ON)
546  : KEYSTATE_OFF);
547  }
548  case VK_LMENU:
549  {
550  return (altPressed ? (isAltLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) : KEYSTATE_OFF);
551  }
552  case VK_LWIN:
553  {
554  return (winPressed ? (isWinLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) : KEYSTATE_OFF);
555  }
556  }
557 
558  return -1;
559  }
560 
561  private int getVirtualKeyCode(int keycode)
562  {
563  if (keycode >= 0 && keycode <= 0xFF)
564  return keymapAndroid[keycode];
565  return 0;
566  }
567 
568  private int getExtendedKeyCode(int keycode)
569  {
570  if (keycode >= 0 && keycode <= 0xFF)
571  return keymapExt[keycode];
572  return 0;
573  }
574 
575  private void processToggleButton(int keycode)
576  {
577  switch (keycode)
578  {
579  case VK_LSHIFT:
580  {
581  if (!checkToggleModifierLock(VK_LSHIFT))
582  {
583  isShiftLocked = false;
584  shiftPressed = !shiftPressed;
585  listener.processVirtualKey(VK_LSHIFT, shiftPressed);
586  }
587  else
588  isShiftLocked = true;
589  break;
590  }
591  case VK_LCONTROL:
592  {
593  if (!checkToggleModifierLock(VK_LCONTROL))
594  {
595  isCtrlLocked = false;
596  ctrlPressed = !ctrlPressed;
597  listener.processVirtualKey(VK_LCONTROL, ctrlPressed);
598  }
599  else
600  isCtrlLocked = true;
601  break;
602  }
603  case VK_LMENU:
604  {
605  if (!checkToggleModifierLock(VK_LMENU))
606  {
607  isAltLocked = false;
608  altPressed = !altPressed;
609  listener.processVirtualKey(VK_LMENU, altPressed);
610  }
611  else
612  isAltLocked = true;
613  break;
614  }
615  case VK_LWIN:
616  {
617  if (!checkToggleModifierLock(VK_LWIN))
618  {
619  isWinLocked = false;
620  winPressed = !winPressed;
621  listener.processVirtualKey(VK_LWIN | VK_EXT_KEY, winPressed);
622  }
623  else
624  isWinLocked = true;
625  break;
626  }
627  }
628  listener.modifiersChanged();
629  }
630 
631  public void clearlAllModifiers()
632  {
633  resetModifierKeysAfterInput(true);
634  }
635 
636  private void resetModifierKeysAfterInput(boolean force)
637  {
638  if (shiftPressed && (!isShiftLocked || force))
639  {
640  listener.processVirtualKey(VK_LSHIFT, false);
641  shiftPressed = false;
642  }
643  if (ctrlPressed && (!isCtrlLocked || force))
644  {
645  listener.processVirtualKey(VK_LCONTROL, false);
646  ctrlPressed = false;
647  }
648  if (altPressed && (!isAltLocked || force))
649  {
650  listener.processVirtualKey(VK_LMENU, false);
651  altPressed = false;
652  }
653  if (winPressed && (!isWinLocked || force))
654  {
655  listener.processVirtualKey(VK_LWIN | VK_EXT_KEY, false);
656  winPressed = false;
657  }
658 
659  if (listener != null)
660  listener.modifiersChanged();
661  }
662 
663  private void switchKeyboard(int keycode)
664  {
665  switch (keycode)
666  {
667  case EXTKEY_KBFUNCTIONKEYS:
668  {
669  listener.switchKeyboard(KEYBOARD_TYPE_FUNCTIONKEYS);
670  break;
671  }
672 
673  case EXTKEY_KBNUMPAD:
674  {
675  listener.switchKeyboard(KEYBOARD_TYPE_NUMPAD);
676  break;
677  }
678 
679  case EXTKEY_KBCURSOR:
680  {
681  listener.switchKeyboard(KEYBOARD_TYPE_CURSOR);
682  break;
683  }
684 
685  default:
686  break;
687  }
688  }
689 
690  private boolean checkToggleModifierLock(int keycode)
691  {
692  long now = System.currentTimeMillis();
693 
694  // was the same modifier hit?
695  if (lastModifierKeyCode != keycode)
696  {
697  lastModifierKeyCode = keycode;
698  lastModifierTime = now;
699  return false;
700  }
701 
702  // within a certain time interval?
703  if (lastModifierTime + 800 > now)
704  {
705  lastModifierTime = 0;
706  return true;
707  }
708  else
709  {
710  lastModifierTime = now;
711  return false;
712  }
713  }
714 
715  // interface that gets called for input handling
716  public interface KeyProcessingListener {
717  abstract void processVirtualKey(int virtualKeyCode, boolean down);
718 
719  abstract void processUnicodeKey(int unicodeKey);
720 
721  abstract void switchKeyboard(int keyboardType);
722 
723  abstract void modifiersChanged();
724  }
725 }