diff options
Diffstat (limited to 'libs/ui/KeyLayoutMap.cpp')
-rw-r--r-- | libs/ui/KeyLayoutMap.cpp | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp new file mode 100644 index 0000000..15ae54c --- /dev/null +++ b/libs/ui/KeyLayoutMap.cpp @@ -0,0 +1,235 @@ +#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; +} + +}; |