Как создать глобальную горячую клавишу в Windows с 3 аргументами?

Так же, как CTL, Alt + удалить

Я хочу написать программу, которая использует глобальные горячие клавиши с 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 горячих клавиш? Возможно? Объясняет, как можно использовать назначение одной клавиши, которую нужно нажать, а затем, если нужно нажать две из них. Однако я не буду говорить, что функция работает только при одновременном нажатии всех кнопок. я взял


person helloworld1234    schedule 17.05.2013    source источник
comment
github.com/boppreh/keyboard   -  person Andrew    schedule 02.08.2017


Ответы (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. Пожалуйста, подумайте об этом в будущем.

person martineau    schedule 17.05.2013

Для тех, кто интересуется подробностями и более подробным примером по этой теме, я недавно написал короткую программу, демонстрирующую функции горячих клавиш, предоставляемые 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
person maxxim    schedule 09.07.2014
comment
Предлагаю сделать это рецептом Active State Python и, возможно, опубликовать ссылку на него в комментарий, а не как отсутствие ответа на смутно связанный вопрос здесь, на этом веб-сайте. - person martineau; 06.04.2016