| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 | }; |