1#define LOG_TAG "KeyCharacterMap" 2 3#include <ui/KeyCharacterMap.h> 4#include <cutils/properties.h> 5 6#include <utils/Log.h> 7#include <sys/types.h> 8#include <unistd.h> 9#include <stdlib.h> 10#include <fcntl.h> 11#include <limits.h> 12#include <string.h> 13 14struct Header 15{ 16 char magic[8]; 17 unsigned int endian; 18 unsigned int version; 19 unsigned int keycount; 20 unsigned char kbdtype; 21 char padding[11]; 22}; 23 24KeyCharacterMap::KeyCharacterMap() 25{ 26} 27 28KeyCharacterMap::~KeyCharacterMap() 29{ 30 free(m_keys); 31} 32 33unsigned short 34KeyCharacterMap::get(int keycode, int meta) 35{ 36 Key* k = find_key(keycode); 37 if (k != NULL) { 38 return k->data[meta & META_MASK]; 39 } 40 return 0; 41} 42 43unsigned short 44KeyCharacterMap::getNumber(int keycode) 45{ 46 Key* k = find_key(keycode); 47 if (k != NULL) { 48 return k->number; 49 } 50 return 0; 51} 52 53unsigned short 54KeyCharacterMap::getMatch(int keycode, const unsigned short* chars, 55 int charsize, uint32_t modifiers) 56{ 57 Key* k = find_key(keycode); 58 modifiers &= 3; // ignore the SYM key because we don't have keymap entries for it 59 if (k != NULL) { 60 const uint16_t* data = k->data; 61 for (int j=0; j<charsize; j++) { 62 uint16_t c = chars[j]; 63 for (int i=0; i<(META_MASK + 1); i++) { 64 if ((modifiers == 0) || ((modifiers & i) != 0)) { 65 if (c == data[i]) { 66 return c; 67 } 68 } 69 } 70 } 71 } 72 return 0; 73} 74 75unsigned short 76KeyCharacterMap::getDisplayLabel(int keycode) 77{ 78 Key* k = find_key(keycode); 79 if (k != NULL) { 80 return k->display_label; 81 } 82 return 0; 83} 84 85bool 86KeyCharacterMap::getKeyData(int keycode, unsigned short *displayLabel, 87 unsigned short *number, unsigned short* results) 88{ 89 Key* k = find_key(keycode); 90 if (k != NULL) { 91 memcpy(results, k->data, sizeof(short)*(META_MASK + 1)); 92 *number = k->number; 93 *displayLabel = k->display_label; 94 return true; 95 } else { 96 return false; 97 } 98} 99 100bool 101KeyCharacterMap::find_char(uint16_t c, uint32_t* key, uint32_t* mods) 102{ 103 uint32_t N = m_keyCount; 104 for (int j=0; j<(META_MASK + 1); j++) { 105 Key const* keys = m_keys; 106 for (uint32_t i=0; i<N; i++) { 107 if (keys->data[j] == c) { 108 *key = keys->keycode; 109 *mods = j; 110 return true; 111 } 112 keys++; 113 } 114 } 115 return false; 116} 117 118bool 119KeyCharacterMap::getEvents(uint16_t* chars, size_t len, 120 Vector<int32_t>* keys, Vector<uint32_t>* modifiers) 121{ 122 for (size_t i=0; i<len; i++) { 123 uint32_t k, mods; 124 if (find_char(chars[i], &k, &mods)) { 125 keys->add(k); 126 modifiers->add(mods); 127 } else { 128 return false; 129 } 130 } 131 return true; 132} 133 134KeyCharacterMap::Key* 135KeyCharacterMap::find_key(int keycode) 136{ 137 Key* keys = m_keys; 138 int low = 0; 139 int high = m_keyCount - 1; 140 int mid; 141 int n; 142 while (low <= high) { 143 mid = (low + high) / 2; 144 n = keys[mid].keycode; 145 if (keycode < n) { 146 high = mid - 1; 147 } else if (keycode > n) { 148 low = mid + 1; 149 } else { 150 return keys + mid; 151 } 152 } 153 return NULL; 154} 155 156KeyCharacterMap* 157KeyCharacterMap::load(int id) 158{ 159 KeyCharacterMap* rv = NULL; 160 char path[PATH_MAX]; 161 char propName[100]; 162 char dev[PROPERTY_VALUE_MAX]; 163 char tmpfn[PROPERTY_VALUE_MAX]; 164 int err; 165 const char* root = getenv("ANDROID_ROOT"); 166 167 sprintf(propName, "hw.keyboards.%u.devname", id); 168 err = property_get(propName, dev, ""); 169 if (err > 0) { 170 // replace all the spaces with underscores 171 strcpy(tmpfn, dev); 172 for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' ')) 173 *p = '_'; 174 snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn); 175 //LOGD("load: dev='%s' path='%s'\n", dev, path); 176 rv = try_file(path); 177 if (rv != NULL) { 178 return rv; 179 } 180 LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev); 181 } else { 182 LOGW("No keyboard for id %d", id); 183 } 184 185 snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root); 186 rv = try_file(path); 187 if (rv == NULL) { 188 LOGE("Can't find any keycharmaps (also tried %s)", path); 189 return NULL; 190 } 191 LOGW("Using default keymap: %s", path); 192 193 return rv; 194} 195 196KeyCharacterMap* 197KeyCharacterMap::try_file(const char* filename) 198{ 199 KeyCharacterMap* rv = NULL; 200 Key* keys; 201 int fd; 202 off_t filesize; 203 Header header; 204 int err; 205 206 fd = open(filename, O_RDONLY); 207 if (fd == -1) { 208 LOGW("Can't open keycharmap file"); 209 return NULL; 210 } 211 212 filesize = lseek(fd, 0, SEEK_END); 213 lseek(fd, 0, SEEK_SET); 214 215 // validate the header 216 if (filesize <= (off_t)sizeof(header)) { 217 LOGW("Bad keycharmap - filesize=%d\n", (int)filesize); 218 goto cleanup1; 219 } 220 221 err = read(fd, &header, sizeof(header)); 222 if (err == -1) { 223 LOGW("Error reading keycharmap file"); 224 goto cleanup1; 225 } 226 227 if (0 != memcmp(header.magic, "keychar", 8)) { 228 LOGW("Bad keycharmap magic token"); 229 goto cleanup1; 230 } 231 if (header.endian != 0x12345678) { 232 LOGW("Bad keycharmap endians"); 233 goto cleanup1; 234 } 235 if ((header.version & 0xff) != 2) { 236 LOGW("Only support keycharmap version 2 (got 0x%08x)", header.version); 237 goto cleanup1; 238 } 239 if (filesize < (off_t)(sizeof(Header)+(sizeof(Key)*header.keycount))) { 240 LOGW("Bad keycharmap file size\n"); 241 goto cleanup1; 242 } 243 244 // read the key data 245 keys = (Key*)malloc(sizeof(Key)*header.keycount); 246 err = read(fd, keys, sizeof(Key)*header.keycount); 247 if (err == -1) { 248 LOGW("Error reading keycharmap file"); 249 free(keys); 250 goto cleanup1; 251 } 252 253 // return the object 254 rv = new KeyCharacterMap; 255 rv->m_keyCount = header.keycount; 256 rv->m_keys = keys; 257 rv->m_type = header.kbdtype; 258 259cleanup1: 260 close(fd); 261 262 return rv; 263} 264