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 17 package android.view; 18 19 import android.os.Parcel; 20 import android.os.Parcelable; 21 import android.text.method.MetaKeyKeyListener; 22 import android.util.AndroidRuntimeException; 23 import android.util.SparseIntArray; 24 import android.hardware.input.InputManager; 25 26 import java.lang.Character; 27 import java.text.Normalizer; 28 29 /** 30 * Describes the keys provided by a keyboard device and their associated labels. 31 */ 32 public class KeyCharacterMap implements Parcelable { 33 /** 34 * The id of the device's primary built in keyboard is always 0. 35 * 36 * @deprecated This constant should no longer be used because there is no 37 * guarantee that a device has a built-in keyboard that can be used for 38 * typing text. There might not be a built-in keyboard, the built-in keyboard 39 * might be a {@link #NUMERIC} or {@link #SPECIAL_FUNCTION} keyboard, or there 40 * might be multiple keyboards installed including external keyboards. 41 * When interpreting key presses received from the framework, applications should 42 * use the device id specified in the {@link KeyEvent} received. 43 * When synthesizing key presses for delivery elsewhere or when translating key presses 44 * from unknown keyboards, applications should use the special {@link #VIRTUAL_KEYBOARD} 45 * device id. 46 */ 47 @Deprecated 48 public static final int BUILT_IN_KEYBOARD = 0; 49 50 /** 51 * The id of a generic virtual keyboard with a full layout that can be used to 52 * synthesize key events. Typically used with {@link #getEvents}. 53 */ 54 public static final int VIRTUAL_KEYBOARD = -1; 55 56 /** 57 * A numeric (12-key) keyboard. 58 * <p> 59 * A numeric keyboard supports text entry using a multi-tap approach. 60 * It may be necessary to tap a key multiple times to generate the desired letter 61 * or symbol. 62 * </p><p> 63 * This type of keyboard is generally designed for thumb typing. 64 * </p> 65 */ 66 public static final int NUMERIC = 1; 67 68 /** 69 * A keyboard with all the letters, but with more than one letter per key. 70 * <p> 71 * This type of keyboard is generally designed for thumb typing. 72 * </p> 73 */ 74 public static final int PREDICTIVE = 2; 75 76 /** 77 * A keyboard with all the letters, and maybe some numbers. 78 * <p> 79 * An alphabetic keyboard supports text entry directly but may have a condensed 80 * layout with a small form factor. In contrast to a {@link #FULL full keyboard}, some 81 * symbols may only be accessible using special on-screen character pickers. 82 * In addition, to improve typing speed and accuracy, the framework provides 83 * special affordances for alphabetic keyboards such as auto-capitalization 84 * and toggled / locked shift and alt keys. 85 * </p><p> 86 * This type of keyboard is generally designed for thumb typing. 87 * </p> 88 */ 89 public static final int ALPHA = 3; 90 91 /** 92 * A full PC-style keyboard. 93 * <p> 94 * A full keyboard behaves like a PC keyboard. All symbols are accessed directly 95 * by pressing keys on the keyboard without on-screen support or affordances such 96 * as auto-capitalization. 97 * </p><p> 98 * This type of keyboard is generally designed for full two hand typing. 99 * </p> 100 */ 101 public static final int FULL = 4; 102 103 /** 104 * A keyboard that is only used to control special functions rather than for typing. 105 * <p> 106 * A special function keyboard consists only of non-printing keys such as 107 * HOME and POWER that are not actually used for typing. 108 * </p> 109 */ 110 public static final int SPECIAL_FUNCTION = 5; 111 112 /** 113 * This private-use character is used to trigger Unicode character 114 * input by hex digits. 115 */ 116 public static final char HEX_INPUT = '\uEF00'; 117 118 /** 119 * This private-use character is used to bring up a character picker for 120 * miscellaneous symbols. 121 */ 122 public static final char PICKER_DIALOG_INPUT = '\uEF01'; 123 124 /** 125 * Modifier keys may be chorded with character keys. 126 * 127 * @see {#link #getModifierBehavior()} for more details. 128 */ 129 public static final int MODIFIER_BEHAVIOR_CHORDED = 0; 130 131 /** 132 * Modifier keys may be chorded with character keys or they may toggle 133 * into latched or locked states when pressed independently. 134 * 135 * @see {#link #getModifierBehavior()} for more details. 136 */ 137 public static final int MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED = 1; 138 139 /* 140 * This bit will be set in the return value of {@link #get(int, int)} if the 141 * key is a "dead key." 142 */ 143 public static final int COMBINING_ACCENT = 0x80000000; 144 145 /** 146 * Mask the return value from {@link #get(int, int)} with this value to get 147 * a printable representation of the accent character of a "dead key." 148 */ 149 public static final int COMBINING_ACCENT_MASK = 0x7FFFFFFF; 150 151 /* Characters used to display placeholders for dead keys. */ 152 private static final int ACCENT_ACUTE = '\u00B4'; 153 private static final int ACCENT_BREVE = '\u02D8'; 154 private static final int ACCENT_CARON = '\u02C7'; 155 private static final int ACCENT_CEDILLA = '\u00B8'; 156 private static final int ACCENT_CIRCUMFLEX = '\u02C6'; 157 private static final int ACCENT_COMMA_ABOVE = '\u1FBD'; 158 private static final int ACCENT_COMMA_ABOVE_RIGHT = '\u02BC'; 159 private static final int ACCENT_DOT_ABOVE = '\u02D9'; 160 private static final int ACCENT_DOT_BELOW = '.'; // approximate 161 private static final int ACCENT_DOUBLE_ACUTE = '\u02DD'; 162 private static final int ACCENT_GRAVE = '\u02CB'; 163 private static final int ACCENT_HOOK_ABOVE = '\u02C0'; 164 private static final int ACCENT_HORN = '\''; // approximate 165 private static final int ACCENT_MACRON = '\u00AF'; 166 private static final int ACCENT_MACRON_BELOW = '\u02CD'; 167 private static final int ACCENT_OGONEK = '\u02DB'; 168 private static final int ACCENT_REVERSED_COMMA_ABOVE = '\u02BD'; 169 private static final int ACCENT_RING_ABOVE = '\u02DA'; 170 private static final int ACCENT_STROKE = '-'; // approximate 171 private static final int ACCENT_TILDE = '\u02DC'; 172 private static final int ACCENT_TURNED_COMMA_ABOVE = '\u02BB'; 173 private static final int ACCENT_UMLAUT = '\u00A8'; 174 private static final int ACCENT_VERTICAL_LINE_ABOVE = '\u02C8'; 175 private static final int ACCENT_VERTICAL_LINE_BELOW = '\u02CC'; 176 177 /* Legacy dead key display characters used in previous versions of the API. 178 * We still support these characters by mapping them to their non-legacy version. */ 179 private static final int ACCENT_GRAVE_LEGACY = '`'; 180 private static final int ACCENT_CIRCUMFLEX_LEGACY = '^'; 181 private static final int ACCENT_TILDE_LEGACY = '~'; 182 183 /** 184 * Maps Unicode combining diacritical to display-form dead key. 185 */ 186 private static final SparseIntArray sCombiningToAccent = new SparseIntArray(); 187 private static final SparseIntArray sAccentToCombining = new SparseIntArray(); 188 static { 189 addCombining('\u0300', ACCENT_GRAVE); 190 addCombining('\u0301', ACCENT_ACUTE); 191 addCombining('\u0302', ACCENT_CIRCUMFLEX); 192 addCombining('\u0303', ACCENT_TILDE); 193 addCombining('\u0304', ACCENT_MACRON); 194 addCombining('\u0306', ACCENT_BREVE); 195 addCombining('\u0307', ACCENT_DOT_ABOVE); 196 addCombining('\u0308', ACCENT_UMLAUT); 197 addCombining('\u0309', ACCENT_HOOK_ABOVE); 198 addCombining('\u030A', ACCENT_RING_ABOVE); 199 addCombining('\u030B', ACCENT_DOUBLE_ACUTE); 200 addCombining('\u030C', ACCENT_CARON); 201 addCombining('\u030D', ACCENT_VERTICAL_LINE_ABOVE); 202 //addCombining('\u030E', ACCENT_DOUBLE_VERTICAL_LINE_ABOVE); 203 //addCombining('\u030F', ACCENT_DOUBLE_GRAVE); 204 //addCombining('\u0310', ACCENT_CANDRABINDU); 205 //addCombining('\u0311', ACCENT_INVERTED_BREVE); 206 addCombining('\u0312', ACCENT_TURNED_COMMA_ABOVE); 207 addCombining('\u0313', ACCENT_COMMA_ABOVE); 208 addCombining('\u0314', ACCENT_REVERSED_COMMA_ABOVE); 209 addCombining('\u0315', ACCENT_COMMA_ABOVE_RIGHT); 210 addCombining('\u031B', ACCENT_HORN); 211 addCombining('\u0323', ACCENT_DOT_BELOW); 212 //addCombining('\u0326', ACCENT_COMMA_BELOW); 213 addCombining('\u0327', ACCENT_CEDILLA); 214 addCombining('\u0328', ACCENT_OGONEK); 215 addCombining('\u0329', ACCENT_VERTICAL_LINE_BELOW); 216 addCombining('\u0331', ACCENT_MACRON_BELOW); 217 addCombining('\u0335', ACCENT_STROKE); 218 //addCombining('\u0342', ACCENT_PERISPOMENI); 219 //addCombining('\u0344', ACCENT_DIALYTIKA_TONOS); 220 //addCombining('\u0345', ACCENT_YPOGEGRAMMENI); 221 222 // One-way mappings to equivalent preferred accents. 223 sCombiningToAccent.append('\u0340', ACCENT_GRAVE); 224 sCombiningToAccent.append('\u0341', ACCENT_ACUTE); 225 sCombiningToAccent.append('\u0343', ACCENT_COMMA_ABOVE); 226 227 // One-way legacy mappings to preserve compatibility with older applications. 228 sAccentToCombining.append(ACCENT_GRAVE_LEGACY, '\u0300'); 229 sAccentToCombining.append(ACCENT_CIRCUMFLEX_LEGACY, '\u0302'); 230 sAccentToCombining.append(ACCENT_TILDE_LEGACY, '\u0303'); 231 } 232 233 private static void addCombining(int combining, int accent) { 234 sCombiningToAccent.append(combining, accent); 235 sAccentToCombining.append(accent, combining); 236 } 237 238 /** 239 * Maps combinations of (display-form) combining key and second character 240 * to combined output character. 241 * These mappings are derived from the Unicode NFC tables as needed. 242 */ 243 private static final SparseIntArray sDeadKeyCache = new SparseIntArray(); 244 private static final StringBuilder sDeadKeyBuilder = new StringBuilder(); 245 static { 246 // Non-standard decompositions. 247 // Stroke modifier for Finnish multilingual keyboard and others. 248 addDeadKey(ACCENT_STROKE, 'D', '\u0110'); 249 addDeadKey(ACCENT_STROKE, 'G', '\u01e4'); 250 addDeadKey(ACCENT_STROKE, 'H', '\u0126'); 251 addDeadKey(ACCENT_STROKE, 'I', '\u0197'); 252 addDeadKey(ACCENT_STROKE, 'L', '\u0141'); 253 addDeadKey(ACCENT_STROKE, 'O', '\u00d8'); 254 addDeadKey(ACCENT_STROKE, 'T', '\u0166'); 255 addDeadKey(ACCENT_STROKE, 'd', '\u0111'); 256 addDeadKey(ACCENT_STROKE, 'g', '\u01e5'); 257 addDeadKey(ACCENT_STROKE, 'h', '\u0127'); 258 addDeadKey(ACCENT_STROKE, 'i', '\u0268'); 259 addDeadKey(ACCENT_STROKE, 'l', '\u0142'); 260 addDeadKey(ACCENT_STROKE, 'o', '\u00f8'); 261 addDeadKey(ACCENT_STROKE, 't', '\u0167'); 262 } 263 264 private static void addDeadKey(int accent, int c, int result) { 265 final int combining = sAccentToCombining.get(accent); 266 if (combining == 0) { 267 throw new IllegalStateException("Invalid dead key declaration."); 268 } 269 final int combination = (combining << 16) | c; 270 sDeadKeyCache.put(combination, result); 271 } 272 273 public static final Parcelable.Creator<KeyCharacterMap> CREATOR = 274 new Parcelable.Creator<KeyCharacterMap>() { 275 public KeyCharacterMap createFromParcel(Parcel in) { 276 return new KeyCharacterMap(in); 277 } 278 public KeyCharacterMap[] newArray(int size) { 279 return new KeyCharacterMap[size]; 280 } 281 }; 282 283 private int mPtr; 284 285 private static native int nativeReadFromParcel(Parcel in); 286 private static native void nativeWriteToParcel(int ptr, Parcel out); 287 private static native void nativeDispose(int ptr); 288 289 private static native char nativeGetCharacter(int ptr, int keyCode, int metaState); 290 private static native boolean nativeGetFallbackAction(int ptr, int keyCode, int metaState, 291 FallbackAction outFallbackAction); 292 private static native char nativeGetNumber(int ptr, int keyCode); 293 private static native char nativeGetMatch(int ptr, int keyCode, char[] chars, int metaState); 294 private static native char nativeGetDisplayLabel(int ptr, int keyCode); 295 private static native int nativeGetKeyboardType(int ptr); 296 private static native KeyEvent[] nativeGetEvents(int ptr, char[] chars); 297 298 private KeyCharacterMap(Parcel in) { 299 if (in == null) { 300 throw new IllegalArgumentException("parcel must not be null"); 301 } 302 mPtr = nativeReadFromParcel(in); 303 if (mPtr == 0) { 304 throw new RuntimeException("Could not read KeyCharacterMap from parcel."); 305 } 306 } 307 308 // Called from native 309 private KeyCharacterMap(int ptr) { 310 mPtr = ptr; 311 } 312 313 @Override 314 protected void finalize() throws Throwable { 315 if (mPtr != 0) { 316 nativeDispose(mPtr); 317 mPtr = 0; 318 } 319 } 320 321 /** 322 * Loads the key character maps for the keyboard with the specified device id. 323 * 324 * @param deviceId The device id of the keyboard. 325 * @return The associated key character map. 326 * @throws {@link UnavailableException} if the key character map 327 * could not be loaded because it was malformed or the default key character map 328 * is missing from the system. 329 */ 330 public static KeyCharacterMap load(int deviceId) { 331 final InputManager im = InputManager.getInstance(); 332 InputDevice inputDevice = im.getInputDevice(deviceId); 333 if (inputDevice == null) { 334 inputDevice = im.getInputDevice(VIRTUAL_KEYBOARD); 335 if (inputDevice == null) { 336 throw new UnavailableException( 337 "Could not load key character map for device " + deviceId); 338 } 339 } 340 return inputDevice.getKeyCharacterMap(); 341 } 342 343 /** 344 * Gets the Unicode character generated by the specified key and meta 345 * key state combination. 346 * <p> 347 * Returns the Unicode character that the specified key would produce 348 * when the specified meta bits (see {@link MetaKeyKeyListener}) 349 * were active. 350 * </p><p> 351 * Returns 0 if the key is not one that is used to type Unicode 352 * characters. 353 * </p><p> 354 * If the return value has bit {@link #COMBINING_ACCENT} set, the 355 * key is a "dead key" that should be combined with another to 356 * actually produce a character -- see {@link #getDeadChar} -- 357 * after masking with {@link #COMBINING_ACCENT_MASK}. 358 * </p> 359 * 360 * @param keyCode The key code. 361 * @param metaState The meta key modifier state. 362 * @return The associated character or combining accent, or 0 if none. 363 */ 364 public int get(int keyCode, int metaState) { 365 metaState = KeyEvent.normalizeMetaState(metaState); 366 char ch = nativeGetCharacter(mPtr, keyCode, metaState); 367 368 int map = sCombiningToAccent.get(ch); 369 if (map != 0) { 370 return map | COMBINING_ACCENT; 371 } else { 372 return ch; 373 } 374 } 375 376 /** 377 * Gets the fallback action to perform if the application does not 378 * handle the specified key. 379 * <p> 380 * When an application does not handle a particular key, the system may 381 * translate the key to an alternate fallback key (specified in the 382 * fallback action) and dispatch it to the application. 383 * The event containing the fallback key is flagged 384 * with {@link KeyEvent#FLAG_FALLBACK}. 385 * </p> 386 * 387 * @param keyCode The key code. 388 * @param metaState The meta key modifier state. 389 * @return The fallback action, or null if none. Remember to recycle the fallback action. 390 * 391 * @hide 392 */ 393 public FallbackAction getFallbackAction(int keyCode, int metaState) { 394 FallbackAction action = FallbackAction.obtain(); 395 metaState = KeyEvent.normalizeMetaState(metaState); 396 if (nativeGetFallbackAction(mPtr, keyCode, metaState, action)) { 397 action.metaState = KeyEvent.normalizeMetaState(action.metaState); 398 return action; 399 } 400 action.recycle(); 401 return null; 402 } 403 404 /** 405 * Gets the number or symbol associated with the key. 406 * <p> 407 * The character value is returned, not the numeric value. 408 * If the key is not a number, but is a symbol, the symbol is retuned. 409 * </p><p> 410 * This method is intended to to support dial pads and other numeric or 411 * symbolic entry on keyboards where certain keys serve dual function 412 * as alphabetic and symbolic keys. This method returns the number 413 * or symbol associated with the key independent of whether the user 414 * has pressed the required modifier. 415 * </p><p> 416 * For example, on one particular keyboard the keys on the top QWERTY row generate 417 * numbers when ALT is pressed such that ALT-Q maps to '1'. So for that keyboard 418 * when {@link #getNumber} is called with {@link KeyEvent#KEYCODE_Q} it returns '1' 419 * so that the user can type numbers without pressing ALT when it makes sense. 420 * </p> 421 * 422 * @param keyCode The key code. 423 * @return The associated numeric or symbolic character, or 0 if none. 424 */ 425 public char getNumber(int keyCode) { 426 return nativeGetNumber(mPtr, keyCode); 427 } 428 429 /** 430 * Gets the first character in the character array that can be generated 431 * by the specified key code. 432 * <p> 433 * This is a convenience function that returns the same value as 434 * {@link #getMatch(int,char[],int) getMatch(keyCode, chars, 0)}. 435 * </p> 436 * 437 * @param keyCode The keycode. 438 * @param chars The array of matching characters to consider. 439 * @return The matching associated character, or 0 if none. 440 */ 441 public char getMatch(int keyCode, char[] chars) { 442 return getMatch(keyCode, chars, 0); 443 } 444 445 /** 446 * Gets the first character in the character array that can be generated 447 * by the specified key code. If there are multiple choices, prefers 448 * the one that would be generated with the specified meta key modifier state. 449 * 450 * @param keyCode The key code. 451 * @param chars The array of matching characters to consider. 452 * @param metaState The preferred meta key modifier state. 453 * @return The matching associated character, or 0 if none. 454 */ 455 public char getMatch(int keyCode, char[] chars, int metaState) { 456 if (chars == null) { 457 throw new IllegalArgumentException("chars must not be null."); 458 } 459 460 metaState = KeyEvent.normalizeMetaState(metaState); 461 return nativeGetMatch(mPtr, keyCode, chars, metaState); 462 } 463 464 /** 465 * Gets the primary character for this key. 466 * In other words, the label that is physically printed on it. 467 * 468 * @param keyCode The key code. 469 * @return The display label character, or 0 if none (eg. for non-printing keys). 470 */ 471 public char getDisplayLabel(int keyCode) { 472 return nativeGetDisplayLabel(mPtr, keyCode); 473 } 474 475 /** 476 * Get the character that is produced by putting accent on the character c. 477 * For example, getDeadChar('`', 'e') returns è. 478 * 479 * @param accent The accent character. eg. '`' 480 * @param c The basic character. 481 * @return The combined character, or 0 if the characters cannot be combined. 482 */ 483 public static int getDeadChar(int accent, int c) { 484 int combining = sAccentToCombining.get(accent); 485 if (combining == 0) { 486 return 0; 487 } 488 489 final int combination = (combining << 16) | c; 490 int combined; 491 synchronized (sDeadKeyCache) { 492 combined = sDeadKeyCache.get(combination, -1); 493 if (combined == -1) { 494 sDeadKeyBuilder.setLength(0); 495 sDeadKeyBuilder.append((char)c); 496 sDeadKeyBuilder.append((char)combining); 497 String result = Normalizer.normalize(sDeadKeyBuilder, Normalizer.Form.NFC); 498 combined = result.length() == 1 ? result.charAt(0) : 0; 499 sDeadKeyCache.put(combination, combined); 500 } 501 } 502 return combined; 503 } 504 505 /** 506 * Describes the character mappings associated with a key. 507 * 508 * @deprecated instead use {@link KeyCharacterMap#getDisplayLabel(int)}, 509 * {@link KeyCharacterMap#getNumber(int)} and {@link KeyCharacterMap#get(int, int)}. 510 */ 511 @Deprecated 512 public static class KeyData { 513 public static final int META_LENGTH = 4; 514 515 /** 516 * The display label (see {@link #getDisplayLabel}). 517 */ 518 public char displayLabel; 519 /** 520 * The "number" value (see {@link #getNumber}). 521 */ 522 public char number; 523 /** 524 * The character that will be generated in various meta states 525 * (the same ones used for {@link #get} and defined as 526 * {@link KeyEvent#META_SHIFT_ON} and {@link KeyEvent#META_ALT_ON}). 527 * <table> 528 * <tr><th>Index</th><th align="left">Value</th></tr> 529 * <tr><td>0</td><td>no modifiers</td></tr> 530 * <tr><td>1</td><td>caps</td></tr> 531 * <tr><td>2</td><td>alt</td></tr> 532 * <tr><td>3</td><td>caps + alt</td></tr> 533 * </table> 534 */ 535 public char[] meta = new char[META_LENGTH]; 536 } 537 538 /** 539 * Get the character conversion data for a given key code. 540 * 541 * @param keyCode The keyCode to query. 542 * @param results A {@link KeyData} instance that will be filled with the results. 543 * @return True if the key was mapped. If the key was not mapped, results is not modified. 544 * 545 * @deprecated instead use {@link KeyCharacterMap#getDisplayLabel(int)}, 546 * {@link KeyCharacterMap#getNumber(int)} or {@link KeyCharacterMap#get(int, int)}. 547 */ 548 @Deprecated 549 public boolean getKeyData(int keyCode, KeyData results) { 550 if (results.meta.length < KeyData.META_LENGTH) { 551 throw new IndexOutOfBoundsException( 552 "results.meta.length must be >= " + KeyData.META_LENGTH); 553 } 554 555 char displayLabel = nativeGetDisplayLabel(mPtr, keyCode); 556 if (displayLabel == 0) { 557 return false; 558 } 559 560 results.displayLabel = displayLabel; 561 results.number = nativeGetNumber(mPtr, keyCode); 562 results.meta[0] = nativeGetCharacter(mPtr, keyCode, 0); 563 results.meta[1] = nativeGetCharacter(mPtr, keyCode, KeyEvent.META_SHIFT_ON); 564 results.meta[2] = nativeGetCharacter(mPtr, keyCode, KeyEvent.META_ALT_ON); 565 results.meta[3] = nativeGetCharacter(mPtr, keyCode, 566 KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON); 567 return true; 568 } 569 570 /** 571 * Get an array of KeyEvent objects that if put into the input stream 572 * could plausibly generate the provided sequence of characters. It is 573 * not guaranteed that the sequence is the only way to generate these 574 * events or that it is optimal. 575 * <p> 576 * This function is primarily offered for instrumentation and testing purposes. 577 * It may fail to map characters to key codes. In particular, the key character 578 * map for the {@link #BUILT_IN_KEYBOARD built-in keyboard} device id may be empty. 579 * Consider using the key character map associated with the 580 * {@link #VIRTUAL_KEYBOARD virtual keyboard} device id instead. 581 * </p><p> 582 * For robust text entry, do not use this function. Instead construct a 583 * {@link KeyEvent} with action code {@link KeyEvent#ACTION_MULTIPLE} that contains 584 * the desired string using {@link KeyEvent#KeyEvent(long, String, int, int)}. 585 * </p> 586 * 587 * @param chars The sequence of characters to generate. 588 * @return An array of {@link KeyEvent} objects, or null if the given char array 589 * can not be generated using the current key character map. 590 */ 591 public KeyEvent[] getEvents(char[] chars) { 592 if (chars == null) { 593 throw new IllegalArgumentException("chars must not be null."); 594 } 595 return nativeGetEvents(mPtr, chars); 596 } 597 598 /** 599 * Returns true if the specified key produces a glyph. 600 * 601 * @param keyCode The key code. 602 * @return True if the key is a printing key. 603 */ 604 public boolean isPrintingKey(int keyCode) { 605 int type = Character.getType(nativeGetDisplayLabel(mPtr, keyCode)); 606 607 switch (type) 608 { 609 case Character.SPACE_SEPARATOR: 610 case Character.LINE_SEPARATOR: 611 case Character.PARAGRAPH_SEPARATOR: 612 case Character.CONTROL: 613 case Character.FORMAT: 614 return false; 615 default: 616 return true; 617 } 618 } 619 620 /** 621 * Gets the keyboard type. 622 * Returns {@link #NUMERIC}, {@link #PREDICTIVE}, {@link #ALPHA}, {@link #FULL} 623 * or {@link #SPECIAL_FUNCTION}. 624 * <p> 625 * Different keyboard types have different semantics. Refer to the documentation 626 * associated with the keyboard type constants for details. 627 * </p> 628 * 629 * @return The keyboard type. 630 */ 631 public int getKeyboardType() { 632 return nativeGetKeyboardType(mPtr); 633 } 634 635 /** 636 * Gets a constant that describes the behavior of this keyboard's modifier keys 637 * such as {@link KeyEvent#KEYCODE_SHIFT_LEFT}. 638 * <p> 639 * Currently there are two behaviors that may be combined: 640 * </p> 641 * <ul> 642 * <li>Chorded behavior: When the modifier key is pressed together with one or more 643 * character keys, the keyboard inserts the modified keys and 644 * then resets the modifier state when the modifier key is released.</li> 645 * <li>Toggled behavior: When the modifier key is pressed and released on its own 646 * it first toggles into a latched state. When latched, the modifier will apply 647 * to next character key that is pressed and will then reset itself to the initial state. 648 * If the modifier is already latched and the modifier key is pressed and release on 649 * its own again, then it toggles into a locked state. When locked, the modifier will 650 * apply to all subsequent character keys that are pressed until unlocked by pressing 651 * the modifier key on its own one more time to reset it to the initial state. 652 * Toggled behavior is useful for small profile keyboards designed for thumb typing. 653 * </ul> 654 * <p> 655 * This function currently returns {@link #MODIFIER_BEHAVIOR_CHORDED} when the 656 * {@link #getKeyboardType() keyboard type} is {@link #FULL} or {@link #SPECIAL_FUNCTION} and 657 * {@link #MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED} otherwise. 658 * In the future, the function may also take into account global keyboard 659 * accessibility settings, other user preferences, or new device capabilities. 660 * </p> 661 * 662 * @return The modifier behavior for this keyboard. 663 * 664 * @see {@link #MODIFIER_BEHAVIOR_CHORDED} 665 * @see {@link #MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED} 666 */ 667 public int getModifierBehavior() { 668 switch (getKeyboardType()) { 669 case FULL: 670 case SPECIAL_FUNCTION: 671 return MODIFIER_BEHAVIOR_CHORDED; 672 default: 673 return MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED; 674 } 675 } 676 677 /** 678 * Queries the framework about whether any physical keys exist on the 679 * any keyboard attached to the device that are capable of producing the given key code. 680 * 681 * @param keyCode The key code to query. 682 * @return True if at least one attached keyboard supports the specified key code. 683 */ 684 public static boolean deviceHasKey(int keyCode) { 685 return InputManager.getInstance().deviceHasKeys(new int[] { keyCode })[0]; 686 } 687 688 /** 689 * Queries the framework about whether any physical keys exist on the 690 * any keyboard attached to the device that are capable of producing the given 691 * array of key codes. 692 * 693 * @param keyCodes The array of key codes to query. 694 * @return A new array of the same size as the key codes array whose elements 695 * are set to true if at least one attached keyboard supports the corresponding key code 696 * at the same index in the key codes array. 697 */ 698 public static boolean[] deviceHasKeys(int[] keyCodes) { 699 return InputManager.getInstance().deviceHasKeys(keyCodes); 700 } 701 702 @Override 703 public void writeToParcel(Parcel out, int flags) { 704 if (out == null) { 705 throw new IllegalArgumentException("parcel must not be null"); 706 } 707 nativeWriteToParcel(mPtr, out); 708 } 709 710 @Override 711 public int describeContents() { 712 return 0; 713 } 714 715 /** 716 * Thrown by {@link KeyCharacterMap#load} when a key character map could not be loaded. 717 */ 718 public static class UnavailableException extends AndroidRuntimeException { 719 public UnavailableException(String msg) { 720 super(msg); 721 } 722 } 723 724 /** 725 * Specifies a substitute key code and meta state as a fallback action 726 * for an unhandled key. 727 * @hide 728 */ 729 public static final class FallbackAction { 730 private static final int MAX_RECYCLED = 10; 731 private static final Object sRecycleLock = new Object(); 732 private static FallbackAction sRecycleBin; 733 private static int sRecycledCount; 734 735 private FallbackAction next; 736 737 public int keyCode; 738 public int metaState; 739 740 private FallbackAction() { 741 } 742 743 public static FallbackAction obtain() { 744 final FallbackAction target; 745 synchronized (sRecycleLock) { 746 if (sRecycleBin == null) { 747 target = new FallbackAction(); 748 } else { 749 target = sRecycleBin; 750 sRecycleBin = target.next; 751 sRecycledCount--; 752 target.next = null; 753 } 754 } 755 return target; 756 } 757 758 public void recycle() { 759 synchronized (sRecycleLock) { 760 if (sRecycledCount < MAX_RECYCLED) { 761 next = sRecycleBin; 762 sRecycleBin = this; 763 sRecycledCount += 1; 764 } else { 765 next = null; 766 } 767 } 768 } 769 } 770 } 771