-
Notifications
You must be signed in to change notification settings - Fork 4
/
keycode.py
executable file
·99 lines (90 loc) · 4 KB
/
keycode.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/env python
# http://stackoverflow.com/questions/1918841/how-to-convert-ascii-character-to-cgkeycode */
import ctypes
import ctypes.util
import CoreFoundation
import Foundation
import objc
try:
unichr
except NameError:
unichr = chr
carbon_path = ctypes.util.find_library('Carbon')
carbon = ctypes.cdll.LoadLibrary(carbon_path)
# We could rely on the fact that kTISPropertyUnicodeKeyLayoutData has
# been the string @"TISPropertyUnicodeKeyLayoutData" since even the
# Classic Mac days. Or we could load it from the framework.
# Unfortunately, the framework doesn't have PyObjC wrappers, and there's
# no easy way to force PyObjC to wrap a CF/ObjC object that it doesn't
# know about. So:
_objc = ctypes.PyDLL(objc._objc.__file__)
_objc.PyObjCObject_New.restype = ctypes.py_object
_objc.PyObjCObject_New.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
def objcify(ptr):
return _objc.PyObjCObject_New(ptr, 0, 1)
kTISPropertyUnicodeKeyLayoutData_p = ctypes.c_void_p.in_dll(
carbon, 'kTISPropertyUnicodeKeyLayoutData')
kTISPropertyUnicodeKeyLayoutData = objcify(kTISPropertyUnicodeKeyLayoutData_p)
carbon.TISCopyCurrentKeyboardInputSource.argtypes = []
carbon.TISCopyCurrentKeyboardInputSource.restype = ctypes.c_void_p
carbon.TISGetInputSourceProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
carbon.TISGetInputSourceProperty.restype = ctypes.c_void_p
carbon.LMGetKbdType.argtypes = []
carbon.LMGetKbdType.restype = ctypes.c_uint32
OptionBits = ctypes.c_uint32
UniCharCount = ctypes.c_uint8
UniChar = ctypes.c_uint16
UniChar4 = UniChar * 4
carbon.UCKeyTranslate.argtypes = [ctypes.c_void_p, # keyLayoutPtr
ctypes.c_uint16, # virtualKeyCode
ctypes.c_uint16, # keyAction
ctypes.c_uint32, # modifierKeyState
ctypes.c_uint32, # keyboardType
OptionBits, # keyTranslateOptions
ctypes.POINTER(ctypes.c_uint32), # deadKeyState
UniCharCount, # maxStringLength
ctypes.POINTER(UniCharCount), # actualStringLength
UniChar4]
carbon.UCKeyTranslate.restype = ctypes.c_uint32 # OSStatus
kUCKeyActionDisplay = 3
kUCKeyTranslateNoDeadKeysBit = 0
kTISPropertyUnicodeKeyLayoutData = ctypes.c_void_p.in_dll(
carbon, 'kTISPropertyUnicodeKeyLayoutData')
def createStringForKey(keycode):
keyboard_p = carbon.TISCopyCurrentKeyboardInputSource()
keyboard = objcify(keyboard_p)
layout_p = carbon.TISGetInputSourceProperty(keyboard_p,
kTISPropertyUnicodeKeyLayoutData)
layout = objcify(layout_p)
layoutbytes = layout.bytes()
keysdown = ctypes.c_uint32()
length = UniCharCount()
chars = UniChar4()
retval = carbon.UCKeyTranslate(layoutbytes.tobytes(),
keycode,
kUCKeyActionDisplay,
0,
carbon.LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
ctypes.byref(keysdown),
4,
ctypes.byref(length),
chars)
s = u''.join(unichr(chars[i]) for i in range(length.value))
CoreFoundation.CFRelease(keyboard)
return s
codedict = {createStringForKey(code): code for code in range(128)}
def keyCodeForChar(c):
return codedict[c]
if __name__ == '__main__':
import sys
for arg in sys.argv[1:]:
try:
keycode = int(arg)
except ValueError:
print(u'{}: {}'.format(arg, keyCodeForChar(arg)))
else:
print('{}: {!r}'.format(keycode, createStringForKey(keycode)))
if len(sys.argv) < 2:
for keycode in range(128):
print('{}: {!r}'.format(keycode, createStringForKey(keycode)))