Home | History | Annotate | Download | only in ui
      1 #define LOG_TAG "KeyCharacterMap"
      2 
      3 #include <ui/KeyCharacterMap.h>
      4 #include <cutils/properties.h>
      5 
      6 #include <utils/Log.h>
      7 #include <sys/types.h>
      8 #include <unistd.h>
      9 #include <stdlib.h>
     10 #include <fcntl.h>
     11 #include <limits.h>
     12 #include <string.h>
     13 
     14 struct Header
     15 {
     16     char magic[8];
     17     unsigned int endian;
     18     unsigned int version;
     19     unsigned int keycount;
     20     unsigned char kbdtype;
     21     char padding[11];
     22 };
     23 
     24 KeyCharacterMap::KeyCharacterMap()
     25 {
     26 }
     27 
     28 KeyCharacterMap::~KeyCharacterMap()
     29 {
     30     free(m_keys);
     31 }
     32 
     33 unsigned short
     34 KeyCharacterMap::get(int keycode, int meta)
     35 {
     36     Key* k = find_key(keycode);
     37     if (k != NULL) {
     38         return k->data[meta & META_MASK];
     39     }
     40     return 0;
     41 }
     42 
     43 unsigned short
     44 KeyCharacterMap::getNumber(int keycode)
     45 {
     46     Key* k = find_key(keycode);
     47     if (k != NULL) {
     48         return k->number;
     49     }
     50     return 0;
     51 }
     52 
     53 unsigned short
     54 KeyCharacterMap::getMatch(int keycode, const unsigned short* chars,
     55                           int charsize, uint32_t modifiers)
     56 {
     57     Key* k = find_key(keycode);
     58     modifiers &= 3; // ignore the SYM key because we don't have keymap entries for it
     59     if (k != NULL) {
     60         const uint16_t* data = k->data;
     61         for (int j=0; j<charsize; j++) {
     62             uint16_t c = chars[j];
     63             for (int i=0; i<(META_MASK + 1); i++) {
     64                 if ((modifiers == 0) || ((modifiers & i) != 0)) {
     65                     if (c == data[i]) {
     66                         return c;
     67                     }
     68                 }
     69             }
     70         }
     71     }
     72     return 0;
     73 }
     74 
     75 unsigned short
     76 KeyCharacterMap::getDisplayLabel(int keycode)
     77 {
     78     Key* k = find_key(keycode);
     79     if (k != NULL) {
     80         return k->display_label;
     81     }
     82     return 0;
     83 }
     84 
     85 bool
     86 KeyCharacterMap::getKeyData(int keycode, unsigned short *displayLabel,
     87                             unsigned short *number, unsigned short* results)
     88 {
     89     Key* k = find_key(keycode);
     90     if (k != NULL) {
     91         memcpy(results, k->data, sizeof(short)*(META_MASK + 1));
     92         *number = k->number;
     93         *displayLabel = k->display_label;
     94         return true;
     95     } else {
     96         return false;
     97     }
     98 }
     99 
    100 bool
    101 KeyCharacterMap::find_char(uint16_t c, uint32_t* key, uint32_t* mods)
    102 {
    103     uint32_t N = m_keyCount;
    104     for (int j=0; j<(META_MASK + 1); j++) {
    105         Key const* keys = m_keys;
    106         for (uint32_t i=0; i<N; i++) {
    107             if (keys->data[j] == c) {
    108                 *key = keys->keycode;
    109                 *mods = j;
    110                 return true;
    111             }
    112             keys++;
    113         }
    114     }
    115     return false;
    116 }
    117 
    118 bool
    119 KeyCharacterMap::getEvents(uint16_t* chars, size_t len,
    120                            Vector<int32_t>* keys, Vector<uint32_t>* modifiers)
    121 {
    122     for (size_t i=0; i<len; i++) {
    123         uint32_t k, mods;
    124         if (find_char(chars[i], &k, &mods)) {
    125             keys->add(k);
    126             modifiers->add(mods);
    127         } else {
    128             return false;
    129         }
    130     }
    131     return true;
    132 }
    133 
    134 KeyCharacterMap::Key*
    135 KeyCharacterMap::find_key(int keycode)
    136 {
    137     Key* keys = m_keys;
    138     int low = 0;
    139     int high = m_keyCount - 1;
    140     int mid;
    141     int n;
    142     while (low <= high) {
    143         mid = (low + high) / 2;
    144         n = keys[mid].keycode;
    145         if (keycode < n) {
    146             high = mid - 1;
    147         } else if (keycode > n) {
    148             low = mid + 1;
    149         } else {
    150             return keys + mid;
    151         }
    152     }
    153     return NULL;
    154 }
    155 
    156 KeyCharacterMap*
    157 KeyCharacterMap::load(int id)
    158 {
    159     KeyCharacterMap* rv = NULL;
    160     char path[PATH_MAX];
    161     char propName[100];
    162     char dev[PROPERTY_VALUE_MAX];
    163     char tmpfn[PROPERTY_VALUE_MAX];
    164     int err;
    165     const char* root = getenv("ANDROID_ROOT");
    166 
    167     sprintf(propName, "hw.keyboards.%u.devname", id);
    168     err = property_get(propName, dev, "");
    169     if (err > 0) {
    170         // replace all the spaces with underscores
    171         strcpy(tmpfn, dev);
    172         for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
    173             *p = '_';
    174         snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn);
    175         //LOGD("load: dev='%s' path='%s'\n", dev, path);
    176         rv = try_file(path);
    177         if (rv != NULL) {
    178             return rv;
    179         }
    180         LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev);
    181     } else {
    182         LOGW("No keyboard for id %d", id);
    183     }
    184 
    185     snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root);
    186     rv = try_file(path);
    187     if (rv == NULL) {
    188         LOGE("Can't find any keycharmaps (also tried %s)", path);
    189         return NULL;
    190     }
    191     LOGW("Using default keymap: %s", path);
    192 
    193     return rv;
    194 }
    195 
    196 KeyCharacterMap*
    197 KeyCharacterMap::try_file(const char* filename)
    198 {
    199     KeyCharacterMap* rv = NULL;
    200     Key* keys;
    201     int fd;
    202     off_t filesize;
    203     Header header;
    204     int err;
    205 
    206     fd = open(filename, O_RDONLY);
    207     if (fd == -1) {
    208         LOGW("Can't open keycharmap file");
    209         return NULL;
    210     }
    211 
    212     filesize = lseek(fd, 0, SEEK_END);
    213     lseek(fd, 0, SEEK_SET);
    214 
    215     // validate the header
    216     if (filesize <= (off_t)sizeof(header)) {
    217         LOGW("Bad keycharmap - filesize=%d\n", (int)filesize);
    218         goto cleanup1;
    219     }
    220 
    221     err = read(fd, &header, sizeof(header));
    222     if (err == -1) {
    223         LOGW("Error reading keycharmap file");
    224         goto cleanup1;
    225     }
    226 
    227     if (0 != memcmp(header.magic, "keychar", 8)) {
    228         LOGW("Bad keycharmap magic token");
    229         goto cleanup1;
    230     }
    231     if (header.endian != 0x12345678) {
    232         LOGW("Bad keycharmap endians");
    233         goto cleanup1;
    234     }
    235     if ((header.version & 0xff) != 2) {
    236         LOGW("Only support keycharmap version 2 (got 0x%08x)", header.version);
    237         goto cleanup1;
    238     }
    239     if (filesize < (off_t)(sizeof(Header)+(sizeof(Key)*header.keycount))) {
    240         LOGW("Bad keycharmap file size\n");
    241         goto cleanup1;
    242     }
    243 
    244     // read the key data
    245     keys = (Key*)malloc(sizeof(Key)*header.keycount);
    246     err = read(fd, keys, sizeof(Key)*header.keycount);
    247     if (err == -1) {
    248         LOGW("Error reading keycharmap file");
    249         free(keys);
    250         goto cleanup1;
    251     }
    252 
    253     // return the object
    254     rv = new KeyCharacterMap;
    255     rv->m_keyCount = header.keycount;
    256     rv->m_keys = keys;
    257     rv->m_type = header.kbdtype;
    258 
    259 cleanup1:
    260     close(fd);
    261 
    262     return rv;
    263 }
    264