|  | #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; | 
|  | } | 
|  |  | 
|  | }; |