Как создать глобальную горячую клавишу на Windows с 3 аргументами?
Так же, как Ctl, Alt + delete
Я хочу написать программу, которая использует глобальные горячие клавиши с 3 или более аргументами в Python. Назначенная функция должна выполняться только при нажатии всех трех клавиш на клавиатуре. Например alt, windows и F3.
win32con.VK_F3, win32con.MOD_WIN, win32con.VK_F5
Это текущая программа, которую я хочу запустить, однако ее вывод:
Traceback (most recent call last):
File "C:\Python32\Syntax\hot keys\hotkeys2.py", line 41, in <module>
for id, (vk, modifiers) in HOTKEYS.items ():
ValueError: too many values to unpack (expected 2)
Программа:
import os
import sys
import ctypes
from ctypes import wintypes
import win32con
byref = ctypes.byref
user32 = ctypes.windll.user32
HOTKEYS = {
1 : (win32con.VK_F3, win32con.MOD_WIN, win32con.VK_F5),
2 : (win32con.VK_F4, win32con.MOD_WIN),
3 : (win32con.VK_F2, win32con.MOD_WIN)
}
def handle_win_f3 ():
#os.startfile (os.environ['TEMP'])
print ("Hello WOrld! F3")
def handle_win_f4 ():
#user32.PostQuitMessage (0)
print ("Hello WOrld! F4")
def handle_win_f1_escape ():
print("exit")
sys.exit()
HOTKEY_ACTIONS = {
1 : handle_win_f3,
2 : handle_win_f4,
3 : handle_win_f1_escape
}
for id, (vk, modifiers) in HOTKEYS.items ():
print ("Registering id", id, "for key", vk)
if not user32.RegisterHotKey (None, id, modifiers, vk):
print ("Unable to register id", id)
try:
msg = wintypes.MSG ()
while user32.GetMessageA (byref (msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
action_to_take = HOTKEY_ACTIONS.get (msg.wParam)
#print(" msg.message == win32con.WM_HOTKEY:")
if action_to_take:
action_to_take ()
user32.TranslateMessage (byref (msg))
user32.DispatchMessageA (byref (msg))
finally:
for id in HOTKEYS.keys ():
user32.UnregisterHotKey (None, id)
print("user32.UnregisterHotKey (None, id)")
Регистрация 3 горячих клавиш? Возможный? Объясняет, как можно использовать назначить одну клавишу, которая должна быть нажата, а затем, если две из которых нужно нажать. Однако я не буду, чтобы функция выполнялась только тогда, когда все нажаты одновременно. я взял
2 ответа
Для начала, если вы хотите Alt, Windows и F3, вам не нужно использовать win32con.VK_F3, win32con.MOD_ALT, win32con.MOD_WIN
для HOTKEYS
запись?
Однако не имеет смысла говорить " F3" с модификаторами " Win" и " F5".
Ошибка на линии:
for id, (vk, modifiers) in HOTKEYS.items ():
потому что значение каждой записи словаря является переменной длины tuple
, Вот способ обработать то, что также побитовое ИЛИ объединяет все значения модификатора в рамках подготовки к передаче их в качестве единственного аргумента RegisterHotKey()
,
from functools import reduce
for id, values in HOTKEYS.items ():
vk, modifiers = values[0], reduce (lambda x, y: x | y, values[1:])
print ("Registering id", id, "for key", vk)
if not user32.RegisterHotKey (None, id, modifiers, vk):
print ("Unable to register id", id)
Было бы легче работать над вашей проблемой, если бы ваш код был с отступом и следовал рекомендациям PEP 8 - Руководство по стилю для кода Python. Пожалуйста, подумайте об этом в будущем.
Для тех, кто интересуется подробностями и более сложным примером по этой теме, я недавно написал короткую программу, демонстрирующую функции горячих клавиш, предоставляемые win32con. Программа позволяет вам указать и протестировать любые горячие клавиши из командной строки:
Использование:
python.exe hotkey.py MOD_ALT VK_UP
-> тест горячей клавиши ALT + стрелка вверх
# Imports
import win32con
import ctypes, ctypes.wintypes
import sys
#
# Functions
#
def dispatch_hotkey(msg):
mod = msg.lParam & 0b1111111111111111
key = msg.lParam >> 16
bit = bin(msg.lParam)[2:]
print("\n*** Received hotkey message (wParam: %d, lParam: %d)" % (msg.wParam, msg.lParam))
print("lParam bitmap: %s" % bit)
print("lParam low-word (modifier): %d, high-word (key): %d" % (mod, key))
print("-> Hotkey %s with modifier %s detected\n" % (keys[key], mods[mod]))
#
# Main
#
# Build translation maps (virtual key codes / modifiers to string)
# Note: exec() is a hack and should not be used in real programs!!
print("\n*** Building translation maps")
mods = {}
keys = {}
for item in dir(win32con):
if item.startswith("MOD_"):
exec("mods[item] = win32con." + item)
exec("mods[win32con." + item + "] = '" + item + "'")
if item.startswith("VK_"):
exec("keys[item] = win32con." + item)
exec("keys[win32con." + item + "] = '" + item + "'")
# Process command line
print("\n*** Processing command line")
mod = "MOD_WIN"
key = "VK_ESCAPE"
for param in sys.argv:
if param.startswith("MOD_"):
if param in mods: mod = param
else: print("\nInvalid modifier specified (%s). Using default.\n-> Use '--list-mods' for a list of valid modifiers." % param)
if param.startswith("VK_"):
if param in keys: key = param
else: print("\nInvalid key specified (%s). Using default.\n-> Use '--list-keys' for a list of valid keys." % param)
if "--list-mods" in sys.argv:
print("\nAvailable modifiers:")
for item in dir(win32con):
if item.startswith("MOD_"): sys.stdout.write(item + ", ")
print("\b\b ")
if "--list-keys" in sys.argv:
print("\nAvailable keys:")
for item in dir(win32con):
if item.startswith("VK_"): sys.stdout.write(item + ", ")
print("\b\b ")
# Register hotkey
print("\n*** Registering global hotkey (modifier: %s, key: %s)" % (mod, key))
ctypes.windll.user32.RegisterHotKey(None, 1, mods[mod], keys[key])
# Wait for hotkey to be triggered
print("\n*** Waiting for hotkey message...")
try:
msg = ctypes.wintypes.MSG()
while ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
dispatch_hotkey(msg)
break
ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))
ctypes.windll.user32.DispatchMessageA(ctypes.byref(msg))
# Unregister hotkey
finally:
ctypes.windll.user32.UnregisterHotKey(None, 1)
Обратите внимание, что эта программа предназначена только для демонстрационных целей, так как ее части (например, функция exec) не должны использоваться в производственных средах. Также обратите внимание, что при таком подходе вы не сможете переопределить встроенные горячие клавиши, такие как WIN + E и т. Д., Они просто будут игнорироваться и по-прежнему выполнять встроенные функции (например, открывать Проводник).
Другой путь (любезно предоставлено @martineau)
Вот как построить карты перевода без использования exec()
:
print("\n*** Building translation maps")
mods = {}
keys = {}
for item, value in vars(win32con).items():
if item.startswith("MOD_"):
mods[item] = value
mods[value] = item
elif item.startswith("VK_"):
keys[item] = value
keys[value] = item