Home | History | Annotate | Download | only in ui
      1 #define LOG_TAG "KeyLayoutMap"
      2 
      3 #include "KeyLayoutMap.h"
      4 #include <sys/types.h>
      5 #include <sys/stat.h>
      6 #include <fcntl.h>
      7 #include <unistd.h>
      8 #include <errno.h>
      9 #include <utils/String8.h>
     10 #include <stdlib.h>
     11 #include <ui/KeycodeLabels.h>
     12 #include <utils/Log.h>
     13 
     14 namespace android {
     15 
     16 KeyLayoutMap::KeyLayoutMap()
     17     :m_status(NO_INIT),
     18      m_keys()
     19 {
     20 }
     21 
     22 KeyLayoutMap::~KeyLayoutMap()
     23 {
     24 }
     25 
     26 static String8
     27 next_token(char const** p, int *line)
     28 {
     29     bool begun = false;
     30     const char* begin = *p;
     31     const char* end = *p;
     32     while (true) {
     33         if (*end == '\n') {
     34             (*line)++;
     35         }
     36         switch (*end)
     37         {
     38             case '#':
     39                 if (begun) {
     40                     *p = end;
     41                     return String8(begin, end-begin);
     42                 } else {
     43                     do {
     44                         begin++;
     45                         end++;
     46                     } while (*begin != '\0' && *begin != '\n');
     47                 }
     48             case '\0':
     49             case ' ':
     50             case '\n':
     51             case '\r':
     52             case '\t':
     53                 if (begun || (*end == '\0')) {
     54                     *p = end;
     55                     return String8(begin, end-begin);
     56                 } else {
     57                     begin++;
     58                     end++;
     59                     break;
     60                 }
     61             default:
     62                 end++;
     63                 begun = true;
     64         }
     65     }
     66 }
     67 
     68 static int32_t
     69 token_to_value(const char *literal, const KeycodeLabel *list)
     70 {
     71     while (list->literal) {
     72         if (0 == strcmp(literal, list->literal)) {
     73             return list->value;
     74         }
     75         list++;
     76     }
     77     return list->value;
     78 }
     79 
     80 status_t
     81 KeyLayoutMap::load(const char* filename)
     82 {
     83     int fd = open(filename, O_RDONLY);
     84     if (fd < 0) {
     85         LOGE("error opening file=%s err=%s\n", filename, strerror(errno));
     86         m_status = errno;
     87         return errno;
     88     }
     89 
     90     off_t len = lseek(fd, 0, SEEK_END);
     91     off_t errlen = lseek(fd, 0, SEEK_SET);
     92     if (len < 0 || errlen < 0) {
     93         close(fd);
     94         LOGE("error seeking file=%s err=%s\n", filename, strerror(errno));
     95         m_status = errno;
     96         return errno;
     97     }
     98 
     99     char* buf = (char*)malloc(len+1);
    100     if (read(fd, buf, len) != len) {
    101         LOGE("error reading file=%s err=%s\n", filename, strerror(errno));
    102         m_status = errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
    103         return errno != 0 ? errno : ((int)NOT_ENOUGH_DATA);
    104     }
    105     errno = 0;
    106     buf[len] = '\0';
    107 
    108     int32_t scancode = -1;
    109     int32_t keycode = -1;
    110     uint32_t flags = 0;
    111     uint32_t tmp;
    112     char* end;
    113     status_t err = NO_ERROR;
    114     int line = 1;
    115     char const* p = buf;
    116     enum { BEGIN, SCANCODE, KEYCODE, FLAG } state = BEGIN;
    117     while (true) {
    118         String8 token = next_token(&p, &line);
    119         if (*p == '\0') {
    120             break;
    121         }
    122         switch (state)
    123         {
    124             case BEGIN:
    125                 if (token == "key") {
    126                     state = SCANCODE;
    127                 } else {
    128                     LOGE("%s:%d: expected key, got '%s'\n", filename, line,
    129                             token.string());
    130                     err = BAD_VALUE;
    131                     goto done;
    132                 }
    133                 break;
    134             case SCANCODE:
    135                 scancode = strtol(token.string(), &end, 0);
    136                 if (*end != '\0') {
    137                     LOGE("%s:%d: expected scancode (a number), got '%s'\n",
    138                             filename, line, token.string());
    139                     goto done;
    140                 }
    141                 //LOGI("%s:%d: got scancode %d\n", filename, line, scancode );
    142                 state = KEYCODE;
    143                 break;
    144             case KEYCODE:
    145                 keycode = token_to_value(token.string(), KEYCODES);
    146                 //LOGI("%s:%d: got keycode %d for %s\n", filename, line, keycode, token.string() );
    147                 if (keycode == 0) {
    148                     LOGE("%s:%d: expected keycode, got '%s'\n",
    149                             filename, line, token.string());
    150                     goto done;
    151                 }
    152                 state = FLAG;
    153                 break;
    154             case FLAG:
    155                 if (token == "key") {
    156                     if (scancode != -1) {
    157                         //LOGI("got key decl scancode=%d keycode=%d"
    158                         //       " flags=0x%08x\n", scancode, keycode, flags);
    159                         Key k = { keycode, flags };
    160                         m_keys.add(scancode, k);
    161                         state = SCANCODE;
    162                         scancode = -1;
    163                         keycode = -1;
    164                         flags = 0;
    165                         break;
    166                     }
    167                 }
    168                 tmp = token_to_value(token.string(), FLAGS);
    169                 //LOGI("%s:%d: got flags %x for %s\n", filename, line, tmp, token.string() );
    170                 if (tmp == 0) {
    171                     LOGE("%s:%d: expected flag, got '%s'\n",
    172                             filename, line, token.string());
    173                     goto done;
    174                 }
    175                 flags |= tmp;
    176                 break;
    177         }
    178     }
    179     if (state == FLAG && scancode != -1 ) {
    180         //LOGI("got key decl scancode=%d keycode=%d"
    181         //       " flags=0x%08x\n", scancode, keycode, flags);
    182         Key k = { keycode, flags };
    183         m_keys.add(scancode, k);
    184     }
    185 
    186 done:
    187     free(buf);
    188     close(fd);
    189 
    190     m_status = err;
    191     return err;
    192 }
    193 
    194 status_t
    195 KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags) const
    196 {
    197     if (m_status != NO_ERROR) {
    198         return m_status;
    199     }
    200 
    201     ssize_t index = m_keys.indexOfKey(scancode);
    202     if (index < 0) {
    203         //LOGW("couldn't map scancode=%d\n", scancode);
    204         return NAME_NOT_FOUND;
    205     }
    206 
    207     const Key& k = m_keys.valueAt(index);
    208 
    209     *keycode = k.keycode;
    210     *flags = k.flags;
    211 
    212     //LOGD("mapped scancode=%d to keycode=%d flags=0x%08x\n", scancode,
    213     //        keycode, flags);
    214 
    215     return NO_ERROR;
    216 }
    217 
    218 status_t
    219 KeyLayoutMap::findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const
    220 {
    221     if (m_status != NO_ERROR) {
    222         return m_status;
    223     }
    224 
    225     const size_t N = m_keys.size();
    226     for (size_t i=0; i<N; i++) {
    227         if (m_keys.valueAt(i).keycode == keycode) {
    228             outScancodes->add(m_keys.keyAt(i));
    229         }
    230     }
    231 
    232     return NO_ERROR;
    233 }
    234 
    235 };
    236