2 # -*- coding: utf-8 -*-
4 # Copyright (c) 2010 Alejandro R. Sedeño <asedeno@mit.edu>
6 # Permission is hereby granted, free of charge, to any person
7 # obtaining a copy of this software and associated documentation files
8 # (the "Software"), to deal in the Software without restriction,
9 # including without limitation the rights to use, copy, modify, merge,
10 # publish, distribute, sublicense, and/or sell copies of the Software,
11 # and to permit persons to whom the Software is furnished to do so,
12 # subject to the following conditions:
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 from __future__ import with_statement
31 # All specified sources are from Google's Android SDK.
32 # For more information, see:
33 # http://developer.android.com/sdk/index.html
37 # build/tools/kcm/kcm.cpp
40 # Offset | Description
41 # 0x00-0x07 | The ascii value "keychar" including the null character
42 # 0x08-0x0b | Endian marker (0x12345678)
43 # 0x0c-0x0f | version (2)
44 # 0x10-0x13 | key count (n)
45 # 0x14-0x17 | keyboard type (NUMERIC [1], Q14 [2], QWERTY [3], etc.)
47 # 0x20-.... | entries (16 bytes × key count)
50 # Offset | Description
51 # 0x00-0x03 | KeyEvent name
52 # 0x04-0x05 | Display Label
57 # 0x0e-0x0f | Shift+Alt
61 # frameworks/base/include/ui/KeycodeLabels.h
62 keycodes={"SOFT_LEFT": 1, "SOFT_RIGHT": 2, "HOME": 3, "BACK": 4,
63 "CALL": 5, "ENDCALL": 6, "0": 7, "1": 8, "2": 9, "3": 10,
64 "4": 11, "5": 12, "6": 13, "7": 14, "8": 15, "9": 16,
65 "STAR": 17, "POUND": 18, "DPAD_UP": 19, "DPAD_DOWN": 20,
66 "DPAD_LEFT": 21, "DPAD_RIGHT": 22, "DPAD_CENTER": 23,
67 "VOLUME_UP": 24, "VOLUME_DOWN": 25, "POWER": 26,
68 "CAMERA": 27, "CLEAR": 28, "A": 29, "B": 30, "C": 31,
69 "D": 32, "E": 33, "F": 34, "G": 35, "H": 36, "I": 37,
70 "J": 38, "K": 39, "L": 40, "M": 41, "N": 42, "O": 43,
71 "P": 44, "Q": 45, "R": 46, "S": 47, "T": 48, "U": 49,
72 "V": 50, "W": 51, "X": 52, "Y": 53, "Z": 54, "COMMA": 55,
73 "PERIOD": 56, "ALT_LEFT": 57, "ALT_RIGHT": 58,
74 "SHIFT_LEFT": 59, "SHIFT_RIGHT": 60, "TAB": 61, "SPACE": 62,
75 "SYM": 63, "EXPLORER": 64, "ENVELOPE": 65, "ENTER": 66,
76 "DEL": 67, "GRAVE": 68, "MINUS": 69, "EQUALS": 70,
77 "LEFT_BRACKET": 71, "RIGHT_BRACKET": 72, "BACKSLASH": 73,
78 "SEMICOLON": 74, "APOSTROPHE": 75, "SLASH": 76, "AT": 77,
79 "NUM": 78, "HEADSETHOOK": 79, "FOCUS": 80, "PLUS": 81,
80 "MENU": 82, "NOTIFICATION": 83, "SEARCH": 84,
81 "MEDIA_PLAY_PAUSE": 85, "MEDIA_STOP": 86, "MEDIA_NEXT": 87,
82 "MEDIA_PREVIOUS": 88, "MEDIA_REWIND": 89,
83 "MEDIA_FAST_FORWARD": 90, "MUTE": 91, "PAGE_UP": 92,
84 "PAGE_DOWN": 93, "PICTSYMBOLS": 94, "SWITCH_CHARSET": 95, }
87 for (k,v) in keycodes.items(): rkeycodes[v] = k
89 keyboardTypes = {1: 'NUMERIC', 2: 'Q14', 3: 'QWERTY',}
91 if n in keyboardTypes:
92 return keyboardTypes[n]
99 Takes the first 32 bytes of the file, confirms it is a valid keymap header
100 Returns endian marker for struct, entry count, and keyboard type.
102 (magic, marker) = struct.unpack('8s4s20x', buf)
106 if marker == '\x12\x34\x56\x78': # big
108 elif marker == '\x78\x56\x34\x12': # little
113 (version, count, kbtype) = struct.unpack(endian+'12x3i8x', buf)
116 kbtype = getKBType(kbtype)
117 return (endian, count, kbtype)
120 def __init__(self, values):
128 self.shiftalt) = values
131 return "KR: KeyCode %i; Base: %i" % (self.keycode, self.base)
134 if 0x20 < val <= 0x7e:
135 return "'%s'" % chr(val)
140 fmt = (rkeycodes[self.keycode],)
141 fmt += tuple([self._fmt(x) for x in self.values[1:]])
142 return ("%-15s%-10s%-10s%-10s%-10s%-10s%-10s" % fmt).strip()
144 def parseKR(buf, endian):
146 Parses a 16-byte key row entry
148 return KR(struct.unpack(endian+'I6H', buf))
150 def decompileKCM(In, Out):
152 endian, count, ktype = checkHeader(header)
153 Out.write("[type=%s]\n" % ktype)
154 #------0 1 2 3 4 5 6 7
155 #------01234567890123456789012345678901234567890123456789012345678901234567890123
156 Out.write("# keycode Display Number Base Shift Alt Shift+Alt\n")
157 for i in range(count):
158 kr = parseKR(In.read(16), endian)
159 Out.write(kr.printKR()+"\n")
161 if __name__ == '__main__':
162 if len(sys.argv) != 3:
163 print """usage: kcm [INPUT] [OUTPUT]
165 INPUT compiled keycharmap file, - for STDIN
166 OUTPUT keycharmap file, - for STDOUT
169 In, Out = sys.argv[1:3]
171 output = StringIO.StringIO()
173 decompileKCM(sys.stdin, output)
175 with open(sys.argv[1],'rb') as f:
176 decompileKCM(f, output)
179 sys.stdout.write(output.getvalue())
181 with open(sys.argv[2],'w') as f:
182 f.write(output.getvalue())