Home | History | Annotate | Download | only in view
      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.text.method.MetaKeyKeyListener;
     20 import android.util.SparseIntArray;
     21 import android.os.RemoteException;
     22 import android.os.ServiceManager;
     23 import android.os.SystemClock;
     24 import android.util.SparseArray;
     25 
     26 import java.lang.Character;
     27 import java.lang.ref.WeakReference;
     28 
     29 /**
     30  * Describes the keys provided by a device and their associated labels.
     31  */
     32 public 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 &egrave;.
    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