diff options
Diffstat (limited to 'tools/kcm')
-rw-r--r-- | tools/kcm/Android.mk | 15 | ||||
-rw-r--r-- | tools/kcm/kcm.cpp | 421 |
2 files changed, 436 insertions, 0 deletions
diff --git a/tools/kcm/Android.mk b/tools/kcm/Android.mk new file mode 100644 index 0000000..130a13a --- /dev/null +++ b/tools/kcm/Android.mk @@ -0,0 +1,15 @@ +# Copyright 2007 The Android Open Source Project +# +# Copies files into the directory structure described by a manifest + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + kcm.cpp + +LOCAL_MODULE := kcm + +include $(BUILD_HOST_EXECUTABLE) + + diff --git a/tools/kcm/kcm.cpp b/tools/kcm/kcm.cpp new file mode 100644 index 0000000..3e6320b --- /dev/null +++ b/tools/kcm/kcm.cpp @@ -0,0 +1,421 @@ +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <ui/KeycodeLabels.h> +#include <stdlib.h> +#include <ctype.h> +#include <map> +#include <string> +#include <utils/ByteOrder.h> + +using namespace std; + +enum { + LENDIAN, + BENDIAN +}; + +/* + * 1: KeyEvent name + * 2: display_label + * 3: number + * 4..7: base, shift, alt, shift-alt + */ +#define COLUMNS (3+4) + +struct KeyRecord +{ + int lineno; + int values[COLUMNS]; +}; + +struct PropValue +{ + PropValue() { lineno = -1; } + PropValue(const PropValue& that) { lineno=that.lineno; value=that.value; } + PropValue(int l, const string& v) { lineno = l; value = v; } + + int lineno; + string value; +}; + +static int usage(); + +// 0 -- ok +// >0 -- error +static int parse_key_line(const char* filename, int lineno, char* line, + KeyRecord* out); +static int write_kr(int fd, const KeyRecord& kr); + +int g_endian; + +int +main(int argc, char** argv) +{ + int err; + if (argc != 3) { + return usage(); + } + + const char* filename = argv[1]; + const char* outfilename = argv[2]; + + int in = open(filename, O_RDONLY); + if (in == -1) { + fprintf(stderr, "kcm: error opening file for read: %s\n", filename); + return 1; + } + + off_t size = lseek(in, 0, SEEK_END); + lseek(in, 0, SEEK_SET); + + char* input = (char*)malloc(size+1); + read(in, input, size); + input[size] = '\0'; + + close(in); + in = -1; + + map<string,PropValue> properties; + map<int,KeyRecord> keys; + int errorcount = 0; + int lineno = 1; + char *thisline = input; + while (*thisline) { + KeyRecord kr; + char *nextline = thisline; + + while (*nextline != '\0' && *nextline != '\n' && *nextline != '\r') { + nextline++; + } + + // eat whitespace, but not newlines + while (*thisline != '\0' && (*thisline == ' ' || *thisline == '\t')) { + thisline++; + } + + // find the end of the line + char lineend = *nextline; + *nextline = '\0'; + if (lineend == '\r' && nextline[1] == '\n') { + nextline++; + } + + if (*thisline == '\0' || *thisline == '\r' || *thisline == '\n' + || *thisline == '#') { + // comment or blank line + } + else if (*thisline == '[') { + // property - syntax [name=value] + // look for = + char* prop = thisline+1; + char* end = prop; + while (*end != '\0' && *end != '=') { + end++; + } + if (*end != '=') { + fprintf(stderr, "%s:%d: invalid property line: %s\n", + filename, lineno, thisline); + errorcount++; + } else { + *end = '\0'; + char* value = end+1; + end = nextline; + while (end > prop && *end != ']') { + end--; + } + if (*end != ']') { + fprintf(stderr, "%s:%d: property missing closing ]: %s\n", + filename, lineno, thisline); + errorcount++; + } else { + *end = '\0'; + properties[prop] = PropValue(lineno, value); + } + } + } + else { + // key + err = parse_key_line(filename, lineno, thisline, &kr); + if (err == 0) { + kr.lineno = lineno; + + map<int,KeyRecord>::iterator old = keys.find(kr.values[0]); + if (old != keys.end()) { + fprintf(stderr, "%s:%d: keycode %d already defined\n", + filename, lineno, kr.values[0]); + fprintf(stderr, "%s:%d: previously defined here\n", + filename, old->second.lineno); + errorcount++; + } + + keys[kr.values[0]] = kr; + } + else if (err > 0) { + errorcount += err; + } + } + lineno++; + + nextline++; + thisline = nextline; + + if (errorcount > 20) { + fprintf(stderr, "%s:%d: too many errors. stopping.\n", filename, + lineno); + return 1; + } + } + + free(input); + + map<string,PropValue>::iterator sit = properties.find("type"); + if (sit == properties.end()) { + fprintf(stderr, "%s: key character map must contain type property.\n", + argv[0]); + errorcount++; + } + PropValue pv = sit->second; + unsigned char kbdtype = 0; + if (pv.value == "NUMERIC") { + kbdtype = 1; + } + else if (pv.value == "Q14") { + kbdtype = 2; + } + else if (pv.value == "QWERTY") { + kbdtype = 3; + } + else { + fprintf(stderr, "%s:%d: keyboard type must be one of NUMERIC, Q14 " + " or QWERTY, not %s\n", filename, pv.lineno, pv.value.c_str()); + } + + if (errorcount != 0) { + return 1; + } + + int out = open(outfilename, O_RDWR|O_CREAT|O_TRUNC, 0660); + if (out == -1) { + fprintf(stderr, "kcm: error opening file for write: %s\n", outfilename); + return 1; + } + + int count = keys.size(); + + map<int,KeyRecord>::iterator it; + int n; + + /** + * File Format: + * Offset Description Value + * 0 magic string "keychar" + * 8 endian marker 0x12345678 + * 12 version 0x00000002 + * 16 key count number of key entries + * 20 keyboard type NUMERIC, Q14, QWERTY, etc. + * 21 padding 0 + * 32 the keys + */ + err = write(out, "keychar", 8); + if (err == -1) goto bad_write; + + n = htodl(0x12345678); + err = write(out, &n, 4); + if (err == -1) goto bad_write; + + n = htodl(0x00000002); + err = write(out, &n, 4); + if (err == -1) goto bad_write; + + n = htodl(count); + err = write(out, &n, 4); + if (err == -1) goto bad_write; + + err = write(out, &kbdtype, 1); + if (err == -1) goto bad_write; + + char zero[11]; + memset(zero, 0, 11); + err = write(out, zero, 11); + if (err == -1) goto bad_write; + + for (it = keys.begin(); it != keys.end(); it++) { + const KeyRecord& kr = it->second; + /* + printf("%2d/ [%d] [%d] [%d] [%d] [%d] [%d] [%d]\n", kr.lineno, + kr.values[0], kr.values[1], kr.values[2], kr.values[3], + kr.values[4], kr.values[5], kr.values[6]); + */ + err = write_kr(out, kr); + if (err == -1) goto bad_write; + } + + close(out); + return 0; + +bad_write: + fprintf(stderr, "kcm: fatal error writing to file: %s\n", outfilename); + close(out); + unlink(outfilename); + return 1; +} + +static int usage() +{ + fprintf(stderr, + "usage: kcm INPUT OUTPUT\n" + "\n" + "INPUT keycharmap file\n" + "OUTPUT compiled keycharmap file\n" + ); + return 1; +} + +static int +is_whitespace(const char* p) +{ + while (*p) { + if (!isspace(*p)) { + return 0; + } + p++; + } + return 1; +} + + +static int +parse_keycode(const char* filename, int lineno, char* str, int* value) +{ + const KeycodeLabel *list = KEYCODES; + while (list->literal) { + if (0 == strcmp(str, list->literal)) { + *value = list->value; + return 0; + } + list++; + } + + char* endptr; + *value = strtol(str, &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, "%s:%d: expected keycode label or number near: " + "%s\n", filename, lineno, str); + return 1; + } + + if (*value == 0) { + fprintf(stderr, "%s:%d: 0 is not a valid keycode.\n", + filename, lineno); + return 1; + } + + return 0; +} + +static int +parse_number(const char* filename, int lineno, char* str, int* value) +{ + int len = strlen(str); + + if (len == 3 && str[0] == '\'' && str[2] == '\'') { + if (str[1] > 0 && str[1] < 127) { + *value = (int)str[1]; + return 0; + } else { + fprintf(stderr, "%s:%d: only low ascii characters are allowed in" + " quotes near: %s\n", filename, lineno, str); + return 1; + } + } + + char* endptr; + *value = strtol(str, &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, "%s:%d: expected number or quoted ascii but got: %s\n", + filename, lineno, str); + return 1; + } + + if (*value >= 0xfffe || *value < 0) { + fprintf(stderr, "%s:%d: unicode char out of range (no negatives, " + "nothing larger than 0xfffe): %s\n", filename, lineno, str); + return 1; + } + + return 0; +} + +static int +parse_key_line(const char* filename, int lineno, char* line, KeyRecord* out) +{ + char* p = line; + + int len = strlen(line); + char* s[COLUMNS]; + for (int i=0; i<COLUMNS; i++) { + s[i] = (char*)malloc(len+1); + } + + for (int i = 0; i < COLUMNS; i++) { + while (*p != '\0' && isspace(*p)) { + p++; + } + + if (*p == '\0') { + fprintf(stderr, "%s:%d: not enough on this line: %s\n", filename, + lineno, line); + return 1; + } + + char *p1 = p; + while (*p != '\0' && !isspace(*p)) { + p++; + } + + memcpy(s[i], p1, p - p1); + s[i][p - p1] = '\0'; + } + + while (*p != '\0' && isspace(*p)) { + *p++; + } + if (*p != '\0') { + fprintf(stderr, "%s:%d: too much on one line near: %s\n", filename, + lineno, p); + fprintf(stderr, "%s:%d: -->%s<--\n", filename, lineno, line); + return 1; + } + + int errorcount = parse_keycode(filename, lineno, s[0], &out->values[0]); + for (int i=1; i<COLUMNS && errorcount == 0; i++) { + errorcount += parse_number(filename, lineno, s[i], &out->values[i]); + } + + return errorcount; +} + +struct WrittenRecord +{ + unsigned int keycode; // 4 bytes + unsigned short values[COLUMNS - 1]; // 6*2 bytes = 12 + // 16 bytes total +}; + +static int +write_kr(int fd, const KeyRecord& kr) +{ + WrittenRecord wr; + + wr.keycode = htodl(kr.values[0]); + for (int i=0; i<COLUMNS - 1; i++) { + wr.values[i] = htods(kr.values[i+1]); + } + + return write(fd, &wr, sizeof(WrittenRecord)); +} + |