| #define LOG_TAG "KeyLayoutMap" | 
 |  | 
 | #include "KeyLayoutMap.h" | 
 | #include <sys/types.h> | 
 | #include <sys/stat.h> | 
 | #include <fcntl.h> | 
 | #include <unistd.h> | 
 | #include <errno.h> | 
 | #include <utils/String8.h> | 
 | #include <stdlib.h> | 
 | #include <ui/KeycodeLabels.h> | 
 | #include <utils/Log.h> | 
 |  | 
 | namespace android { | 
 |  | 
 | KeyLayoutMap::KeyLayoutMap() | 
 |     :m_status(NO_INIT), | 
 |      m_keys() | 
 | { | 
 | } | 
 |  | 
 | KeyLayoutMap::~KeyLayoutMap() | 
 | { | 
 | } | 
 |  | 
 | static String8 | 
 | next_token(char const** p, int *line) | 
 | { | 
 |     bool begun = false; | 
 |     const char* begin = *p; | 
 |     const char* end = *p; | 
 |     while (true) { | 
 |         if (*end == '\n') { | 
 |             (*line)++; | 
 |         } | 
 |         switch (*end) | 
 |         { | 
 |             case '#': | 
 |                 if (begun) { | 
 |                     *p = end; | 
 |                     return String8(begin, end-begin); | 
 |                 } else { | 
 |                     do { | 
 |                         begin++; | 
 |                         end++; | 
 |                     } while (*begin != '\0' && *begin != '\n'); | 
 |                 } | 
 |             case '\0': | 
 |             case ' ': | 
 |             case '\n': | 
 |             case '\r': | 
 |             case '\t': | 
 |                 if (begun || (*end == '\0')) { | 
 |                     *p = end; | 
 |                     return String8(begin, end-begin); | 
 |                 } else { | 
 |                     begin++; | 
 |                     end++; | 
 |                     break; | 
 |                 } | 
 |             default: | 
 |                 end++; | 
 |                 begun = true; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | static int32_t | 
 | token_to_value(const char *literal, const KeycodeLabel *list) | 
 | { | 
 |     while (list->literal) { | 
 |         if (0 == strcmp(literal, list->literal)) { | 
 |             return list->value; | 
 |         } | 
 |         list++; | 
 |     } | 
 |     return list->value; | 
 | } | 
 |  | 
 | status_t | 
 | KeyLayoutMap::load(const char* filename) | 
 | { | 
 |     int fd = open(filename, O_RDONLY); | 
 |     if (fd < 0) { | 
 |         LOGE("error opening file=%s err=%s\n", filename, strerror(errno)); | 
 |         m_status = errno; | 
 |         return errno; | 
 |     } | 
 |  | 
 |     off_t len = lseek(fd, 0, SEEK_END); | 
 |     off_t errlen = lseek(fd, 0, SEEK_SET); | 
 |     if (len < 0 || errlen < 0) { | 
 |         close(fd); | 
 |         LOGE("error seeking file=%s err=%s\n", filename, strerror(errno)); | 
 |         m_status = errno; | 
 |         return errno; | 
 |     } | 
 |  | 
 |     char* buf = (char*)malloc(len+1); | 
 |     if (read(fd, buf, len) != len) { | 
 |         LOGE("error reading file=%s err=%s\n", filename, strerror(errno)); | 
 |         m_status = errno != 0 ? errno : ((int)NOT_ENOUGH_DATA); | 
 |         return errno != 0 ? errno : ((int)NOT_ENOUGH_DATA); | 
 |     } | 
 |     errno = 0; | 
 |     buf[len] = '\0'; | 
 |  | 
 |     int32_t scancode = -1; | 
 |     int32_t keycode = -1; | 
 |     uint32_t flags = 0; | 
 |     uint32_t tmp; | 
 |     char* end; | 
 |     status_t err = NO_ERROR; | 
 |     int line = 1; | 
 |     char const* p = buf; | 
 |     enum { BEGIN, SCANCODE, KEYCODE, FLAG } state = BEGIN; | 
 |     while (true) { | 
 |         String8 token = next_token(&p, &line); | 
 |         if (*p == '\0') { | 
 |             break; | 
 |         } | 
 |         switch (state) | 
 |         { | 
 |             case BEGIN: | 
 |                 if (token == "key") { | 
 |                     state = SCANCODE; | 
 |                 } else { | 
 |                     LOGE("%s:%d: expected key, got '%s'\n", filename, line, | 
 |                             token.string()); | 
 |                     err = BAD_VALUE; | 
 |                     goto done; | 
 |                 } | 
 |                 break; | 
 |             case SCANCODE: | 
 |                 scancode = strtol(token.string(), &end, 0); | 
 |                 if (*end != '\0') { | 
 |                     LOGE("%s:%d: expected scancode (a number), got '%s'\n", | 
 |                             filename, line, token.string()); | 
 |                     goto done; | 
 |                 } | 
 |                 //LOGI("%s:%d: got scancode %d\n", filename, line, scancode ); | 
 |                 state = KEYCODE; | 
 |                 break; | 
 |             case KEYCODE: | 
 |                 keycode = token_to_value(token.string(), KEYCODES); | 
 |                 //LOGI("%s:%d: got keycode %d for %s\n", filename, line, keycode, token.string() ); | 
 |                 if (keycode == 0) { | 
 |                     LOGE("%s:%d: expected keycode, got '%s'\n", | 
 |                             filename, line, token.string()); | 
 |                     goto done; | 
 |                 } | 
 |                 state = FLAG; | 
 |                 break; | 
 |             case FLAG: | 
 |                 if (token == "key") { | 
 |                     if (scancode != -1) { | 
 |                         //LOGI("got key decl scancode=%d keycode=%d" | 
 |                         //       " flags=0x%08x\n", scancode, keycode, flags); | 
 |                         Key k = { keycode, flags }; | 
 |                         m_keys.add(scancode, k); | 
 |                         state = SCANCODE; | 
 |                         scancode = -1; | 
 |                         keycode = -1; | 
 |                         flags = 0; | 
 |                         break; | 
 |                     } | 
 |                 } | 
 |                 tmp = token_to_value(token.string(), FLAGS); | 
 |                 //LOGI("%s:%d: got flags %x for %s\n", filename, line, tmp, token.string() ); | 
 |                 if (tmp == 0) { | 
 |                     LOGE("%s:%d: expected flag, got '%s'\n", | 
 |                             filename, line, token.string()); | 
 |                     goto done; | 
 |                 } | 
 |                 flags |= tmp; | 
 |                 break; | 
 |         } | 
 |     } | 
 |     if (state == FLAG && scancode != -1 ) { | 
 |         //LOGI("got key decl scancode=%d keycode=%d" | 
 |         //       " flags=0x%08x\n", scancode, keycode, flags); | 
 |         Key k = { keycode, flags }; | 
 |         m_keys.add(scancode, k); | 
 |     } | 
 |  | 
 | done: | 
 |     free(buf); | 
 |     close(fd); | 
 |  | 
 |     m_status = err; | 
 |     return err; | 
 | } | 
 |  | 
 | status_t | 
 | KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags) const | 
 | { | 
 |     if (m_status != NO_ERROR) { | 
 |         return m_status; | 
 |     } | 
 |  | 
 |     ssize_t index = m_keys.indexOfKey(scancode); | 
 |     if (index < 0) { | 
 |         //LOGW("couldn't map scancode=%d\n", scancode); | 
 |         return NAME_NOT_FOUND; | 
 |     } | 
 |  | 
 |     const Key& k = m_keys.valueAt(index); | 
 |  | 
 |     *keycode = k.keycode; | 
 |     *flags = k.flags; | 
 |  | 
 |     //LOGD("mapped scancode=%d to keycode=%d flags=0x%08x\n", scancode, | 
 |     //        keycode, flags); | 
 |  | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | status_t | 
 | KeyLayoutMap::findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const | 
 | { | 
 |     if (m_status != NO_ERROR) { | 
 |         return m_status; | 
 |     } | 
 |      | 
 |     const size_t N = m_keys.size(); | 
 |     for (size_t i=0; i<N; i++) { | 
 |         if (m_keys.valueAt(i).keycode == keycode) { | 
 |             outScancodes->add(m_keys.keyAt(i)); | 
 |         } | 
 |     } | 
 |      | 
 |     return NO_ERROR; | 
 | } | 
 |  | 
 | }; |