1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view; 18 19import android.text.method.MetaKeyKeyListener; 20import android.util.SparseIntArray; 21import android.os.RemoteException; 22import android.os.ServiceManager; 23import android.os.SystemClock; 24import android.util.SparseArray; 25 26import java.lang.Character; 27import java.lang.ref.WeakReference; 28 29/** 30 * Describes the keys provided by a device and their associated labels. 31 */ 32public class KeyCharacterMap 33{ 34 /** 35 * The id of the device's primary built in keyboard is always 0. 36 */ 37 public static final int BUILT_IN_KEYBOARD = 0; 38 39 /** A numeric (12-key) keyboard. */ 40 public static final int NUMERIC = 1; 41 42 /** A keyboard with all the letters, but with more than one letter 43 * per key. */ 44 public static final int PREDICTIVE = 2; 45 46 /** A keyboard with all the letters, and maybe some numbers. */ 47 public static final int ALPHA = 3; 48 49 /** 50 * This private-use character is used to trigger Unicode character 51 * input by hex digits. 52 */ 53 public static final char HEX_INPUT = '\uEF00'; 54 55 /** 56 * This private-use character is used to bring up a character picker for 57 * miscellaneous symbols. 58 */ 59 public static final char PICKER_DIALOG_INPUT = '\uEF01'; 60 61 private static Object sLock = new Object(); 62 private static SparseArray<WeakReference<KeyCharacterMap>> sInstances 63 = new SparseArray<WeakReference<KeyCharacterMap>>(); 64 65 /** 66 * Loads the key character maps for the keyboard with the specified device id. 67 * @param keyboard The device id of the keyboard. 68 * @return The associated key character map. 69 */ 70 public static KeyCharacterMap load(int keyboard) 71 { 72 synchronized (sLock) { 73 KeyCharacterMap result; 74 WeakReference<KeyCharacterMap> ref = sInstances.get(keyboard); 75 if (ref != null) { 76 result = ref.get(); 77 if (result != null) { 78 return result; 79 } 80 } 81 result = new KeyCharacterMap(keyboard); 82 sInstances.put(keyboard, new WeakReference<KeyCharacterMap>(result)); 83 return result; 84 } 85 } 86 87 private KeyCharacterMap(int keyboardDevice) 88 { 89 mKeyboardDevice = keyboardDevice; 90 mPointer = ctor_native(keyboardDevice); 91 } 92 93 /** 94 * <p> 95 * Returns the Unicode character that the specified key would produce 96 * when the specified meta bits (see {@link MetaKeyKeyListener}) 97 * were active. 98 * </p><p> 99 * Returns 0 if the key is not one that is used to type Unicode 100 * characters. 101 * </p><p> 102 * If the return value has bit {@link #COMBINING_ACCENT} set, the 103 * key is a "dead key" that should be combined with another to 104 * actually produce a character -- see {@link #getDeadChar} -- 105 * after masking with {@link #COMBINING_ACCENT_MASK}. 106 * </p> 107 */ 108 public int get(int keyCode, int meta) 109 { 110 if ((meta & MetaKeyKeyListener.META_CAP_LOCKED) != 0) { 111 meta |= KeyEvent.META_SHIFT_ON; 112 } 113 if ((meta & MetaKeyKeyListener.META_ALT_LOCKED) != 0) { 114 meta |= KeyEvent.META_ALT_ON; 115 } 116 117 // Ignore caps lock on keys where alt and shift have the same effect. 118 if ((meta & MetaKeyKeyListener.META_CAP_LOCKED) != 0) { 119 if (get_native(mPointer, keyCode, KeyEvent.META_SHIFT_ON) == 120 get_native(mPointer, keyCode, KeyEvent.META_ALT_ON)) { 121 meta &= ~KeyEvent.META_SHIFT_ON; 122 } 123 } 124 125 int ret = get_native(mPointer, keyCode, meta); 126 int map = COMBINING.get(ret); 127 128 if (map != 0) { 129 return map; 130 } else { 131 return ret; 132 } 133 } 134 135 /** 136 * Gets the number or symbol associated with the key. The character value 137 * is returned, not the numeric value. If the key is not a number, but is 138 * a symbol, the symbol is retuned. 139 */ 140 public char getNumber(int keyCode) 141 { 142 return getNumber_native(mPointer, keyCode); 143 } 144 145 /** 146 * The same as {@link #getMatch(int,char[],int) getMatch(keyCode, chars, 0)}. 147 */ 148 public char getMatch(int keyCode, char[] chars) 149 { 150 return getMatch(keyCode, chars, 0); 151 } 152 153 /** 154 * If one of the chars in the array can be generated by keyCode, 155 * return the char; otherwise return '\0'. 156 * @param keyCode the key code to look at 157 * @param chars the characters to try to find 158 * @param modifiers the modifier bits to prefer. If any of these bits 159 * are set, if there are multiple choices, that could 160 * work, the one for this modifier will be set. 161 */ 162 public char getMatch(int keyCode, char[] chars, int modifiers) 163 { 164 if (chars == null) { 165 // catch it here instead of in native 166 throw new NullPointerException(); 167 } 168 return getMatch_native(mPointer, keyCode, chars, modifiers); 169 } 170 171 /** 172 * Get the primary character for this key. In other words, the label 173 * that is physically printed on it. 174 */ 175 public char getDisplayLabel(int keyCode) 176 { 177 return getDisplayLabel_native(mPointer, keyCode); 178 } 179 180 /** 181 * Get the character that is produced by putting accent on the character 182 * c. 183 * For example, getDeadChar('`', 'e') returns è. 184 */ 185 public static int getDeadChar(int accent, int c) 186 { 187 return DEAD.get((accent << 16) | c); 188 } 189 190 public static class KeyData { 191 public static final int META_LENGTH = 4; 192 193 /** 194 * The display label (see {@link #getDisplayLabel}). 195 */ 196 public char displayLabel; 197 /** 198 * The "number" value (see {@link #getNumber}). 199 */ 200 public char number; 201 /** 202 * The character that will be generated in various meta states 203 * (the same ones used for {@link #get} and defined as 204 * {@link KeyEvent#META_SHIFT_ON} and {@link KeyEvent#META_ALT_ON}). 205 * <table> 206 * <tr><th>Index</th><th align="left">Value</th></tr> 207 * <tr><td>0</td><td>no modifiers</td></tr> 208 * <tr><td>1</td><td>caps</td></tr> 209 * <tr><td>2</td><td>alt</td></tr> 210 * <tr><td>3</td><td>caps + alt</td></tr> 211 * </table> 212 */ 213 public char[] meta = new char[META_LENGTH]; 214 } 215 216 /** 217 * Get the characters conversion data for a given keyCode. 218 * 219 * @param keyCode the keyCode to look for 220 * @param results a {@link KeyData} that will be filled with the results. 221 * 222 * @return whether the key was mapped or not. If the key was not mapped, 223 * results is not modified. 224 */ 225 public boolean getKeyData(int keyCode, KeyData results) 226 { 227 if (results.meta.length >= KeyData.META_LENGTH) { 228 return getKeyData_native(mPointer, keyCode, results); 229 } else { 230 throw new IndexOutOfBoundsException("results.meta.length must be >= " + 231 KeyData.META_LENGTH); 232 } 233 } 234 235 /** 236 * Get an array of KeyEvent objects that if put into the input stream 237 * could plausibly generate the provided sequence of characters. It is 238 * not guaranteed that the sequence is the only way to generate these 239 * events or that it is optimal. 240 * 241 * @return an array of KeyEvent objects, or null if the given char array 242 * can not be generated using the current key character map. 243 */ 244 public KeyEvent[] getEvents(char[] chars) 245 { 246 if (chars == null) { 247 throw new NullPointerException(); 248 } 249 250 long[] keys = getEvents_native(mPointer, chars); 251 if (keys == null) { 252 return null; 253 } 254 255 // how big should the array be 256 int len = keys.length*2; 257 int N = keys.length; 258 for (int i=0; i<N; i++) { 259 int mods = (int)(keys[i] >> 32); 260 if ((mods & KeyEvent.META_ALT_ON) != 0) { 261 len += 2; 262 } 263 if ((mods & KeyEvent.META_SHIFT_ON) != 0) { 264 len += 2; 265 } 266 if ((mods & KeyEvent.META_SYM_ON) != 0) { 267 len += 2; 268 } 269 } 270 271 // create the events 272 KeyEvent[] rv = new KeyEvent[len]; 273 int index = 0; 274 long now = SystemClock.uptimeMillis(); 275 int device = mKeyboardDevice; 276 for (int i=0; i<N; i++) { 277 int mods = (int)(keys[i] >> 32); 278 int meta = 0; 279 280 if ((mods & KeyEvent.META_ALT_ON) != 0) { 281 meta |= KeyEvent.META_ALT_ON; 282 rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, 283 KeyEvent.KEYCODE_ALT_LEFT, 0, meta, device, 0); 284 index++; 285 } 286 if ((mods & KeyEvent.META_SHIFT_ON) != 0) { 287 meta |= KeyEvent.META_SHIFT_ON; 288 rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, 289 KeyEvent.KEYCODE_SHIFT_LEFT, 0, meta, device, 0); 290 index++; 291 } 292 if ((mods & KeyEvent.META_SYM_ON) != 0) { 293 meta |= KeyEvent.META_SYM_ON; 294 rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, 295 KeyEvent.KEYCODE_SYM, 0, meta, device, 0); 296 index++; 297 } 298 299 int key = (int)(keys[i]); 300 rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, 301 key, 0, meta, device, 0); 302 index++; 303 rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_UP, 304 key, 0, meta, device, 0); 305 index++; 306 307 if ((mods & KeyEvent.META_ALT_ON) != 0) { 308 meta &= ~KeyEvent.META_ALT_ON; 309 rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_UP, 310 KeyEvent.KEYCODE_ALT_LEFT, 0, meta, device, 0); 311 index++; 312 } 313 if ((mods & KeyEvent.META_SHIFT_ON) != 0) { 314 meta &= ~KeyEvent.META_SHIFT_ON; 315 rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_UP, 316 KeyEvent.KEYCODE_SHIFT_LEFT, 0, meta, device, 0); 317 index++; 318 } 319 if ((mods & KeyEvent.META_SYM_ON) != 0) { 320 meta &= ~KeyEvent.META_SYM_ON; 321 rv[index] = new KeyEvent(now, now, KeyEvent.ACTION_UP, 322 KeyEvent.KEYCODE_SYM, 0, meta, device, 0); 323 index++; 324 } 325 } 326 327 return rv; 328 } 329 330 /** 331 * Does this character key produce a glyph? 332 */ 333 public boolean isPrintingKey(int keyCode) 334 { 335 int type = Character.getType(get(keyCode, 0)); 336 337 switch (type) 338 { 339 case Character.SPACE_SEPARATOR: 340 case Character.LINE_SEPARATOR: 341 case Character.PARAGRAPH_SEPARATOR: 342 case Character.CONTROL: 343 case Character.FORMAT: 344 return false; 345 default: 346 return true; 347 } 348 } 349 350 protected void finalize() throws Throwable 351 { 352 dtor_native(mPointer); 353 } 354 355 /** 356 * Returns {@link #NUMERIC}, {@link #PREDICTIVE} or {@link #ALPHA}. 357 */ 358 public int getKeyboardType() 359 { 360 return getKeyboardType_native(mPointer); 361 } 362 363 /** 364 * Queries the framework about whether any physical keys exist on the 365 * device that are capable of producing the given key codes. 366 */ 367 public static boolean deviceHasKey(int keyCode) { 368 int[] codeArray = new int[1]; 369 codeArray[0] = keyCode; 370 boolean[] ret = deviceHasKeys(codeArray); 371 return ret[0]; 372 } 373 374 public static boolean[] deviceHasKeys(int[] keyCodes) { 375 boolean[] ret = new boolean[keyCodes.length]; 376 IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); 377 try { 378 wm.hasKeys(keyCodes, ret); 379 } catch (RemoteException e) { 380 // no fallback; just return the empty array 381 } 382 return ret; 383 } 384 385 private int mPointer; 386 private int mKeyboardDevice; 387 388 private static native int ctor_native(int id); 389 private static native void dtor_native(int ptr); 390 private static native char get_native(int ptr, int keycode, 391 int meta); 392 private static native char getNumber_native(int ptr, int keycode); 393 private static native char getMatch_native(int ptr, int keycode, 394 char[] chars, int modifiers); 395 private static native char getDisplayLabel_native(int ptr, int keycode); 396 private static native boolean getKeyData_native(int ptr, int keycode, 397 KeyData results); 398 private static native int getKeyboardType_native(int ptr); 399 private static native long[] getEvents_native(int ptr, char[] str); 400 401 /** 402 * Maps Unicode combining diacritical to display-form dead key 403 * (display character shifted left 16 bits). 404 */ 405 private static SparseIntArray COMBINING = new SparseIntArray(); 406 407 /** 408 * Maps combinations of (display-form) dead key and second character 409 * to combined output character. 410 */ 411 private static SparseIntArray DEAD = new SparseIntArray(); 412 413 /* 414 * TODO: Change the table format to support full 21-bit-wide 415 * accent characters and combined characters if ever necessary. 416 */ 417 private static final int ACUTE = '\u00B4' << 16; 418 private static final int GRAVE = '`' << 16; 419 private static final int CIRCUMFLEX = '^' << 16; 420 private static final int TILDE = '~' << 16; 421 private static final int UMLAUT = '\u00A8' << 16; 422 423 /* 424 * This bit will be set in the return value of {@link #get(int, int)} if the 425 * key is a "dead key." 426 */ 427 public static final int COMBINING_ACCENT = 0x80000000; 428 /** 429 * Mask the return value from {@link #get(int, int)} with this value to get 430 * a printable representation of the accent character of a "dead key." 431 */ 432 public static final int COMBINING_ACCENT_MASK = 0x7FFFFFFF; 433 434 static { 435 COMBINING.put('\u0300', (GRAVE >> 16) | COMBINING_ACCENT); 436 COMBINING.put('\u0301', (ACUTE >> 16) | COMBINING_ACCENT); 437 COMBINING.put('\u0302', (CIRCUMFLEX >> 16) | COMBINING_ACCENT); 438 COMBINING.put('\u0303', (TILDE >> 16) | COMBINING_ACCENT); 439 COMBINING.put('\u0308', (UMLAUT >> 16) | COMBINING_ACCENT); 440 441 DEAD.put(ACUTE | 'A', '\u00C1'); 442 DEAD.put(ACUTE | 'C', '\u0106'); 443 DEAD.put(ACUTE | 'E', '\u00C9'); 444 DEAD.put(ACUTE | 'G', '\u01F4'); 445 DEAD.put(ACUTE | 'I', '\u00CD'); 446 DEAD.put(ACUTE | 'K', '\u1E30'); 447 DEAD.put(ACUTE | 'L', '\u0139'); 448 DEAD.put(ACUTE | 'M', '\u1E3E'); 449 DEAD.put(ACUTE | 'N', '\u0143'); 450 DEAD.put(ACUTE | 'O', '\u00D3'); 451 DEAD.put(ACUTE | 'P', '\u1E54'); 452 DEAD.put(ACUTE | 'R', '\u0154'); 453 DEAD.put(ACUTE | 'S', '\u015A'); 454 DEAD.put(ACUTE | 'U', '\u00DA'); 455 DEAD.put(ACUTE | 'W', '\u1E82'); 456 DEAD.put(ACUTE | 'Y', '\u00DD'); 457 DEAD.put(ACUTE | 'Z', '\u0179'); 458 DEAD.put(ACUTE | 'a', '\u00E1'); 459 DEAD.put(ACUTE | 'c', '\u0107'); 460 DEAD.put(ACUTE | 'e', '\u00E9'); 461 DEAD.put(ACUTE | 'g', '\u01F5'); 462 DEAD.put(ACUTE | 'i', '\u00ED'); 463 DEAD.put(ACUTE | 'k', '\u1E31'); 464 DEAD.put(ACUTE | 'l', '\u013A'); 465 DEAD.put(ACUTE | 'm', '\u1E3F'); 466 DEAD.put(ACUTE | 'n', '\u0144'); 467 DEAD.put(ACUTE | 'o', '\u00F3'); 468 DEAD.put(ACUTE | 'p', '\u1E55'); 469 DEAD.put(ACUTE | 'r', '\u0155'); 470 DEAD.put(ACUTE | 's', '\u015B'); 471 DEAD.put(ACUTE | 'u', '\u00FA'); 472 DEAD.put(ACUTE | 'w', '\u1E83'); 473 DEAD.put(ACUTE | 'y', '\u00FD'); 474 DEAD.put(ACUTE | 'z', '\u017A'); 475 DEAD.put(CIRCUMFLEX | 'A', '\u00C2'); 476 DEAD.put(CIRCUMFLEX | 'C', '\u0108'); 477 DEAD.put(CIRCUMFLEX | 'E', '\u00CA'); 478 DEAD.put(CIRCUMFLEX | 'G', '\u011C'); 479 DEAD.put(CIRCUMFLEX | 'H', '\u0124'); 480 DEAD.put(CIRCUMFLEX | 'I', '\u00CE'); 481 DEAD.put(CIRCUMFLEX | 'J', '\u0134'); 482 DEAD.put(CIRCUMFLEX | 'O', '\u00D4'); 483 DEAD.put(CIRCUMFLEX | 'S', '\u015C'); 484 DEAD.put(CIRCUMFLEX | 'U', '\u00DB'); 485 DEAD.put(CIRCUMFLEX | 'W', '\u0174'); 486 DEAD.put(CIRCUMFLEX | 'Y', '\u0176'); 487 DEAD.put(CIRCUMFLEX | 'Z', '\u1E90'); 488 DEAD.put(CIRCUMFLEX | 'a', '\u00E2'); 489 DEAD.put(CIRCUMFLEX | 'c', '\u0109'); 490 DEAD.put(CIRCUMFLEX | 'e', '\u00EA'); 491 DEAD.put(CIRCUMFLEX | 'g', '\u011D'); 492 DEAD.put(CIRCUMFLEX | 'h', '\u0125'); 493 DEAD.put(CIRCUMFLEX | 'i', '\u00EE'); 494 DEAD.put(CIRCUMFLEX | 'j', '\u0135'); 495 DEAD.put(CIRCUMFLEX | 'o', '\u00F4'); 496 DEAD.put(CIRCUMFLEX | 's', '\u015D'); 497 DEAD.put(CIRCUMFLEX | 'u', '\u00FB'); 498 DEAD.put(CIRCUMFLEX | 'w', '\u0175'); 499 DEAD.put(CIRCUMFLEX | 'y', '\u0177'); 500 DEAD.put(CIRCUMFLEX | 'z', '\u1E91'); 501 DEAD.put(GRAVE | 'A', '\u00C0'); 502 DEAD.put(GRAVE | 'E', '\u00C8'); 503 DEAD.put(GRAVE | 'I', '\u00CC'); 504 DEAD.put(GRAVE | 'N', '\u01F8'); 505 DEAD.put(GRAVE | 'O', '\u00D2'); 506 DEAD.put(GRAVE | 'U', '\u00D9'); 507 DEAD.put(GRAVE | 'W', '\u1E80'); 508 DEAD.put(GRAVE | 'Y', '\u1EF2'); 509 DEAD.put(GRAVE | 'a', '\u00E0'); 510 DEAD.put(GRAVE | 'e', '\u00E8'); 511 DEAD.put(GRAVE | 'i', '\u00EC'); 512 DEAD.put(GRAVE | 'n', '\u01F9'); 513 DEAD.put(GRAVE | 'o', '\u00F2'); 514 DEAD.put(GRAVE | 'u', '\u00F9'); 515 DEAD.put(GRAVE | 'w', '\u1E81'); 516 DEAD.put(GRAVE | 'y', '\u1EF3'); 517 DEAD.put(TILDE | 'A', '\u00C3'); 518 DEAD.put(TILDE | 'E', '\u1EBC'); 519 DEAD.put(TILDE | 'I', '\u0128'); 520 DEAD.put(TILDE | 'N', '\u00D1'); 521 DEAD.put(TILDE | 'O', '\u00D5'); 522 DEAD.put(TILDE | 'U', '\u0168'); 523 DEAD.put(TILDE | 'V', '\u1E7C'); 524 DEAD.put(TILDE | 'Y', '\u1EF8'); 525 DEAD.put(TILDE | 'a', '\u00E3'); 526 DEAD.put(TILDE | 'e', '\u1EBD'); 527 DEAD.put(TILDE | 'i', '\u0129'); 528 DEAD.put(TILDE | 'n', '\u00F1'); 529 DEAD.put(TILDE | 'o', '\u00F5'); 530 DEAD.put(TILDE | 'u', '\u0169'); 531 DEAD.put(TILDE | 'v', '\u1E7D'); 532 DEAD.put(TILDE | 'y', '\u1EF9'); 533 DEAD.put(UMLAUT | 'A', '\u00C4'); 534 DEAD.put(UMLAUT | 'E', '\u00CB'); 535 DEAD.put(UMLAUT | 'H', '\u1E26'); 536 DEAD.put(UMLAUT | 'I', '\u00CF'); 537 DEAD.put(UMLAUT | 'O', '\u00D6'); 538 DEAD.put(UMLAUT | 'U', '\u00DC'); 539 DEAD.put(UMLAUT | 'W', '\u1E84'); 540 DEAD.put(UMLAUT | 'X', '\u1E8C'); 541 DEAD.put(UMLAUT | 'Y', '\u0178'); 542 DEAD.put(UMLAUT | 'a', '\u00E4'); 543 DEAD.put(UMLAUT | 'e', '\u00EB'); 544 DEAD.put(UMLAUT | 'h', '\u1E27'); 545 DEAD.put(UMLAUT | 'i', '\u00EF'); 546 DEAD.put(UMLAUT | 'o', '\u00F6'); 547 DEAD.put(UMLAUT | 't', '\u1E97'); 548 DEAD.put(UMLAUT | 'u', '\u00FC'); 549 DEAD.put(UMLAUT | 'w', '\u1E85'); 550 DEAD.put(UMLAUT | 'x', '\u1E8D'); 551 DEAD.put(UMLAUT | 'y', '\u00FF'); 552 } 553} 554