Spaces:
Sleeping
Sleeping
File size: 5,311 Bytes
d12bc25 |
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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
import win32api
import win32con
import win32ui
MAPVK_VK_TO_CHAR = 2
key_name_to_vk = {}
key_code_to_name = {}
_better_names = {
"escape": "esc",
"return": "enter",
"back": "pgup",
"next": "pgdn",
}
def _fillvkmap():
# Pull the VK_names from win32con
names = [entry for entry in win32con.__dict__ if entry.startswith("VK_")]
for name in names:
code = getattr(win32con, name)
n = name[3:].lower()
key_name_to_vk[n] = code
if n in _better_names:
n = _better_names[n]
key_name_to_vk[n] = code
key_code_to_name[code] = n
_fillvkmap()
def get_vk(chardesc):
if len(chardesc) == 1:
# it is a character.
info = win32api.VkKeyScan(chardesc)
if info == -1:
# Note: returning None, None causes an error when keyboard layout is non-English, see the report below
# https://stackoverflow.com/questions/45138084/pythonwin-occasionally-gives-an-error-on-opening
return 0, 0
vk = win32api.LOBYTE(info)
state = win32api.HIBYTE(info)
modifiers = 0
if state & 0x1:
modifiers |= win32con.SHIFT_PRESSED
if state & 0x2:
modifiers |= win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED
if state & 0x4:
modifiers |= win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED
return vk, modifiers
# must be a 'key name'
return key_name_to_vk.get(chardesc.lower()), 0
modifiers = {
"alt": win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED,
"lalt": win32con.LEFT_ALT_PRESSED,
"ralt": win32con.RIGHT_ALT_PRESSED,
"ctrl": win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED,
"ctl": win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED,
"control": win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED,
"lctrl": win32con.LEFT_CTRL_PRESSED,
"lctl": win32con.LEFT_CTRL_PRESSED,
"rctrl": win32con.RIGHT_CTRL_PRESSED,
"rctl": win32con.RIGHT_CTRL_PRESSED,
"shift": win32con.SHIFT_PRESSED,
"key": 0, # ignore key tag.
}
def parse_key_name(name):
name = name + "-" # Add a sentinal
start = pos = 0
max = len(name)
toks = []
while pos < max:
if name[pos] in "+-":
tok = name[start:pos]
# use the ascii lower() version of tok, so ascii chars require
# an explicit shift modifier - ie 'Ctrl+G' should be treated as
# 'ctrl+g' - 'ctrl+shift+g' would be needed if desired.
# This is mainly to avoid changing all the old keystroke defs
toks.append(tok.lower())
pos += 1 # skip the sep
start = pos
pos += 1
flags = 0
# do the modifiers
for tok in toks[:-1]:
mod = modifiers.get(tok.lower())
if mod is not None:
flags |= mod
# the key name
vk, this_flags = get_vk(toks[-1])
return vk, flags | this_flags
_checks = [
[ # Shift
("Shift", win32con.SHIFT_PRESSED),
],
[ # Ctrl key
("Ctrl", win32con.LEFT_CTRL_PRESSED | win32con.RIGHT_CTRL_PRESSED),
("LCtrl", win32con.LEFT_CTRL_PRESSED),
("RCtrl", win32con.RIGHT_CTRL_PRESSED),
],
[ # Alt key
("Alt", win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED),
("LAlt", win32con.LEFT_ALT_PRESSED),
("RAlt", win32con.RIGHT_ALT_PRESSED),
],
]
def make_key_name(vk, flags):
# Check alt keys.
flags_done = 0
parts = []
for moddata in _checks:
for name, checkflag in moddata:
if flags & checkflag:
parts.append(name)
flags_done = flags_done & checkflag
break
if flags_done & flags:
parts.append(hex(flags & ~flags_done))
# Now the key name.
if vk is None:
parts.append("<Unknown scan code>")
else:
try:
parts.append(key_code_to_name[vk])
except KeyError:
# Not in our virtual key map - ask Windows what character this
# key corresponds to.
scancode = win32api.MapVirtualKey(vk, MAPVK_VK_TO_CHAR)
parts.append(chr(scancode))
sep = "+"
if sep in parts:
sep = "-"
return sep.join([p.capitalize() for p in parts])
def _psc(char):
sc, mods = get_vk(char)
print("Char %s -> %d -> %s" % (repr(char), sc, key_code_to_name.get(sc)))
def test1():
for ch in """aA0/?[{}];:'"`~_-+=\\|,<.>/?""":
_psc(ch)
for code in ["Home", "End", "Left", "Right", "Up", "Down", "Menu", "Next"]:
_psc(code)
def _pkn(n):
vk, flags = parse_key_name(n)
print("%s -> %s,%s -> %s" % (n, vk, flags, make_key_name(vk, flags)))
def test2():
_pkn("ctrl+alt-shift+x")
_pkn("ctrl-home")
_pkn("Shift-+")
_pkn("Shift--")
_pkn("Shift+-")
_pkn("Shift++")
_pkn("LShift-+")
_pkn("ctl+home")
_pkn("ctl+enter")
_pkn("alt+return")
_pkn("Alt+/")
_pkn("Alt+BadKeyName")
_pkn("A") # an ascii char - should be seen as 'a'
_pkn("a")
_pkn("Shift-A")
_pkn("Shift-a")
_pkn("a")
_pkn("(")
_pkn("Ctrl+(")
_pkn("Ctrl+Shift-8")
_pkn("Ctrl+*")
_pkn("{")
_pkn("!")
_pkn(".")
if __name__ == "__main__":
test2()
|