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