Initial Contribution
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp
new file mode 100644
index 0000000..e891181
--- /dev/null
+++ b/libs/ui/KeyCharacterMap.cpp
@@ -0,0 +1,263 @@
+#define LOG_TAG "KeyCharacterMap"
+
+#include <ui/KeyCharacterMap.h>
+#include <cutils/properties.h>
+
+#include <utils/Log.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>
+
+struct Header
+{
+ char magic[8];
+ unsigned int endian;
+ unsigned int version;
+ unsigned int keycount;
+ unsigned char kbdtype;
+ char padding[11];
+};
+
+KeyCharacterMap::KeyCharacterMap()
+{
+}
+
+KeyCharacterMap::~KeyCharacterMap()
+{
+ free(m_keys);
+}
+
+unsigned short
+KeyCharacterMap::get(int keycode, int meta)
+{
+ Key* k = find_key(keycode);
+ if (k != NULL) {
+ return k->data[meta & META_MASK];
+ }
+ return 0;
+}
+
+unsigned short
+KeyCharacterMap::getNumber(int keycode)
+{
+ Key* k = find_key(keycode);
+ if (k != NULL) {
+ return k->number;
+ }
+ return 0;
+}
+
+unsigned short
+KeyCharacterMap::getMatch(int keycode, const unsigned short* chars,
+ int charsize, uint32_t modifiers)
+{
+ Key* k = find_key(keycode);
+ modifiers &= 3; // ignore the SYM key because we don't have keymap entries for it
+ if (k != NULL) {
+ const uint16_t* data = k->data;
+ for (int j=0; j<charsize; j++) {
+ uint16_t c = chars[j];
+ for (int i=0; i<(META_MASK + 1); i++) {
+ if ((modifiers == 0) || ((modifiers & i) != 0)) {
+ if (c == data[i]) {
+ return c;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+unsigned short
+KeyCharacterMap::getDisplayLabel(int keycode)
+{
+ Key* k = find_key(keycode);
+ if (k != NULL) {
+ return k->display_label;
+ }
+ return 0;
+}
+
+bool
+KeyCharacterMap::getKeyData(int keycode, unsigned short *displayLabel,
+ unsigned short *number, unsigned short* results)
+{
+ Key* k = find_key(keycode);
+ if (k != NULL) {
+ memcpy(results, k->data, sizeof(short)*(META_MASK + 1));
+ *number = k->number;
+ *displayLabel = k->display_label;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool
+KeyCharacterMap::find_char(uint16_t c, uint32_t* key, uint32_t* mods)
+{
+ uint32_t N = m_keyCount;
+ for (int j=0; j<(META_MASK + 1); j++) {
+ Key const* keys = m_keys;
+ for (uint32_t i=0; i<N; i++) {
+ if (keys->data[j] == c) {
+ *key = keys->keycode;
+ *mods = j;
+ return true;
+ }
+ keys++;
+ }
+ }
+ return false;
+}
+
+bool
+KeyCharacterMap::getEvents(uint16_t* chars, size_t len,
+ Vector<int32_t>* keys, Vector<uint32_t>* modifiers)
+{
+ for (size_t i=0; i<len; i++) {
+ uint32_t k, mods;
+ if (find_char(chars[i], &k, &mods)) {
+ keys->add(k);
+ modifiers->add(mods);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+KeyCharacterMap::Key*
+KeyCharacterMap::find_key(int keycode)
+{
+ Key* keys = m_keys;
+ int low = 0;
+ int high = m_keyCount - 1;
+ int mid;
+ int n;
+ while (low <= high) {
+ mid = (low + high) / 2;
+ n = keys[mid].keycode;
+ if (keycode < n) {
+ high = mid - 1;
+ } else if (keycode > n) {
+ low = mid + 1;
+ } else {
+ return keys + mid;
+ }
+ }
+ return NULL;
+}
+
+KeyCharacterMap*
+KeyCharacterMap::load(int id)
+{
+ KeyCharacterMap* rv = NULL;
+ char path[PATH_MAX];
+ char propName[100];
+ char dev[PROPERTY_VALUE_MAX];
+ char tmpfn[PROPERTY_VALUE_MAX];
+ int err;
+ const char* root = getenv("ANDROID_ROOT");
+
+ sprintf(propName, "hw.keyboards.%u.devname", id);
+ err = property_get(propName, dev, "");
+ if (err > 0) {
+ // replace all the spaces with underscores
+ strcpy(tmpfn, dev);
+ for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
+ *p = '_';
+ snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn);
+ //LOGD("load: dev='%s' path='%s'\n", dev, path);
+ rv = try_file(path);
+ if (rv != NULL) {
+ return rv;
+ }
+ LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev);
+ } else {
+ LOGW("No keyboard for id %d", id);
+ }
+
+ snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root);
+ rv = try_file(path);
+ if (rv == NULL) {
+ LOGE("Can't find any keycharmaps (also tried %s)", path);
+ return NULL;
+ }
+ LOGW("Using default keymap: %s", path);
+
+ return rv;
+}
+
+KeyCharacterMap*
+KeyCharacterMap::try_file(const char* filename)
+{
+ KeyCharacterMap* rv = NULL;
+ Key* keys;
+ int fd;
+ off_t filesize;
+ Header header;
+ int err;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ LOGW("Can't open keycharmap file");
+ return NULL;
+ }
+
+ filesize = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+
+ // validate the header
+ if (filesize <= (off_t)sizeof(header)) {
+ LOGW("Bad keycharmap - filesize=%d\n", (int)filesize);
+ goto cleanup1;
+ }
+
+ err = read(fd, &header, sizeof(header));
+ if (err == -1) {
+ LOGW("Error reading keycharmap file");
+ goto cleanup1;
+ }
+
+ if (0 != memcmp(header.magic, "keychar", 8)) {
+ LOGW("Bad keycharmap magic token");
+ goto cleanup1;
+ }
+ if (header.endian != 0x12345678) {
+ LOGW("Bad keycharmap endians");
+ goto cleanup1;
+ }
+ if ((header.version & 0xff) != 2) {
+ LOGW("Only support keycharmap version 2 (got 0x%08x)", header.version);
+ goto cleanup1;
+ }
+ if (filesize < (off_t)(sizeof(Header)+(sizeof(Key)*header.keycount))) {
+ LOGW("Bad keycharmap file size\n");
+ goto cleanup1;
+ }
+
+ // read the key data
+ keys = (Key*)malloc(sizeof(Key)*header.keycount);
+ err = read(fd, keys, sizeof(Key)*header.keycount);
+ if (err == -1) {
+ LOGW("Error reading keycharmap file");
+ free(keys);
+ goto cleanup1;
+ }
+
+ // return the object
+ rv = new KeyCharacterMap;
+ rv->m_keyCount = header.keycount;
+ rv->m_keys = keys;
+ rv->m_type = header.kbdtype;
+
+cleanup1:
+ close(fd);
+
+ return rv;
+}