summaryrefslogtreecommitdiffstats
path: root/tools/kcm
diff options
context:
space:
mode:
Diffstat (limited to 'tools/kcm')
-rw-r--r--tools/kcm/Android.mk15
-rw-r--r--tools/kcm/kcm.cpp421
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));
+}
+