The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # |
| 3 | # a python script used to generate some C constant tables from a key charmap file |
| 4 | # |
| 5 | # usage: |
| 6 | # progname file.kcm > charmap-tab.h |
| 7 | # |
| 8 | import sys, os, string, re |
| 9 | |
| 10 | header = """\ |
| 11 | #include "android_charmap.h" |
| 12 | |
| 13 | /* the following is automatically generated by the 'gen-charmap.py' script |
| 14 | * do not touch. the generation command was: |
| 15 | * gen-charmap.py\ |
| 16 | """ |
| 17 | |
| 18 | header2 = """ |
| 19 | */ |
| 20 | """ |
| 21 | |
| 22 | kmap_header = """\ |
| 23 | static const AKeyEntry _%(name)s_keys[] = |
| 24 | { |
| 25 | /* keycode base caps fn caps+fn number */ |
| 26 | """ |
| 27 | |
| 28 | |
| 29 | kmap_footer = """\ |
| 30 | }; |
| 31 | |
| 32 | static const AKeyCharmap _%(name)s_charmap = |
| 33 | { |
| 34 | _%(name)s_keys, |
| 35 | %(count)d, |
| 36 | "%(name)s" |
| 37 | }; |
| 38 | """ |
| 39 | |
| 40 | |
| 41 | re_mapname = re.compile( r".*/(\w+).kcm" ) |
| 42 | re_start = re.compile( r"(\w+)\s*(.*)" ) |
| 43 | re_char = re.compile( r"('.')\s*(.*)" ) |
| 44 | re_hex = re.compile( r"(0x\w+)\s*(.*)" ) |
| 45 | |
| 46 | specials = { 'COMMA': 'Comma', |
| 47 | 'PERIOD': 'Period', |
| 48 | 'AT': 'At', |
| 49 | 'LEFT_BRACKET': 'LeftBracket', |
| 50 | 'RIGHT_BRACKET': 'RightBracket', |
| 51 | 'SLASH': 'Slash', |
| 52 | 'BACKSLASH': 'Backslash', |
| 53 | 'GRAVE': 'Grave', |
| 54 | 'MINUS': 'Minus', |
| 55 | 'EQUALS': 'Equals', |
| 56 | 'SEMICOLON': 'Semicolon', |
| 57 | 'APOSTROPHE': 'Apostrophe', |
| 58 | 'SPACE': 'Space', |
vchtchetkine | 9085a28 | 2009-09-14 15:29:20 -0700 | [diff] [blame] | 59 | 'ENTER': 'Newline', |
| 60 | 'TAB': 'Tab', |
| 61 | 'STAR': 'Star', |
| 62 | 'POUND': 'Pound', |
| 63 | 'PLUS': 'Plus', |
| 64 | 'DEL': 'Del' |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | entries = [] |
| 68 | |
| 69 | def match_char_or_hex(line): |
| 70 | m = re_char.match(line) |
| 71 | if not m: |
| 72 | m = re_hex.match(line) |
| 73 | return m |
| 74 | |
| 75 | def quote(s): |
| 76 | if s == "'''": |
| 77 | s = "'\\''" |
| 78 | elif s == "'\\'": |
| 79 | s = "'\\\\'" |
| 80 | return s |
| 81 | |
| 82 | def process_line(line,result): |
| 83 | m = re_start.match(line) |
| 84 | if not m: |
| 85 | print "bad bad line: " + line |
| 86 | return -1 |
| 87 | keycode = m.group(1) |
| 88 | line = m.group(2) |
| 89 | m = match_char_or_hex(line) |
| 90 | if not m: |
| 91 | print "character expected in: " + line |
| 92 | return -1 |
vchtchetkine | 9085a28 | 2009-09-14 15:29:20 -0700 | [diff] [blame] | 93 | disp = quote(m.group(1)) |
| 94 | line = m.group(2) |
| 95 | m = match_char_or_hex(line) |
| 96 | if not m: |
| 97 | print "character expected in: " + line |
| 98 | return -1 |
| 99 | number = quote(m.group(1)) |
| 100 | line = m.group(2) |
| 101 | m = match_char_or_hex(line) |
| 102 | if not m: |
| 103 | print "character expected in: " + line |
| 104 | return -1 |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 105 | base = quote(m.group(1)) |
| 106 | line = m.group(2) |
| 107 | m = match_char_or_hex(line) |
| 108 | if not m: |
| 109 | print "character expected in: " + line |
| 110 | return -1 |
| 111 | caps = quote(m.group(1)) |
| 112 | line = m.group(2) |
| 113 | m = match_char_or_hex(line) |
| 114 | if not m: |
| 115 | print "character expected in: " + line |
| 116 | return -1 |
| 117 | fn = quote(m.group(1)) |
| 118 | line = m.group(2) |
| 119 | m = match_char_or_hex(line) |
| 120 | if not m: |
| 121 | print "character expected in: " + line |
| 122 | return -1 |
| 123 | caps_fn = quote(m.group(1)) |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 124 | |
| 125 | if specials.has_key(keycode): |
| 126 | keycode = specials[keycode] |
| 127 | keycode = "kKeyCode" + keycode |
| 128 | |
| 129 | result.append( (keycode,base,caps,fn,caps_fn,number) ) |
| 130 | return 0 |
| 131 | |
| 132 | def process_file( file ): |
| 133 | result = [] |
| 134 | fp = open(file,"rb") |
| 135 | for line in fp.xreadlines(): |
| 136 | line = line.strip() |
| 137 | if not line: # skip empty lines |
| 138 | continue |
| 139 | if line[0] == '#' or line[0] == '[': # skip |
| 140 | continue |
| 141 | if process_line(line,result) < 0: |
| 142 | break |
| 143 | fp.close() |
| 144 | return result |
| 145 | |
| 146 | class KMap: |
| 147 | def __init__(self,name,results): |
| 148 | self.name = name |
| 149 | self.results = results |
| 150 | |
| 151 | def dump(self): |
| 152 | t = { 'name': self.name, 'count':len(self.results) } |
| 153 | print kmap_header % t |
| 154 | for item in self.results: |
| 155 | print " { %-22s, %5s, %5s, %5s, %6s, %5s }," % item |
| 156 | print kmap_footer % t |
| 157 | |
| 158 | kmaps = [] |
| 159 | |
| 160 | if len(sys.argv) < 2: |
| 161 | print "usage: progname charmap.kcm [charmap2.kcm ...] > charmap-tab.h" |
| 162 | else: |
| 163 | genline = "" |
| 164 | for filepath in sys.argv[1:]: |
| 165 | m = re_mapname.match(filepath) |
| 166 | if not m: |
| 167 | print "%s is not a keyboard charmap name" % filepath |
| 168 | os.exit(1) |
| 169 | |
| 170 | mapname = m.group(1) |
| 171 | genline = genline + " " + mapname + ".kcm" |
| 172 | |
| 173 | for filepath in sys.argv[1:]: |
| 174 | m = re_mapname.match(filepath) |
| 175 | mapname = m.group(1) |
| 176 | result = process_file( filepath ) |
| 177 | kmap = KMap(mapname,result) |
| 178 | kmaps.append(kmap) |
| 179 | |
| 180 | print header + genline + header2 |
| 181 | for kmap in kmaps: |
| 182 | kmap.dump() |
| 183 | |
| 184 | print "const AKeyCharmap* android_charmaps[%d] = {" % len(kmaps), |
| 185 | comma = "" |
| 186 | for kmap in kmaps: |
| 187 | print "%s&_%s_charmap" % (comma, kmap.name), |
| 188 | comma = ", " |
| 189 | print "};" |
| 190 | print "const int android_charmap_count = %d;" % len(kmaps) |