#python
#python
Вопрос:
Вот простой фрагмент гораздо более крупной программы, над которой я работаю. decideByKeypress()
Это функция, которая ожидает либо нажатия клавиши Esc, либо комбинации клавиш left Ctrl
и left Shift
. Первое взаимодействие с клавиатурой означает успех, следовательно return 0
, в то время как последнее означает, что что-то не так, следовательно return -1
. (Пользователь увидит на экране пары ввода-вывода классификации ML, и этот фрагмент поможет пользователю решить, правильная классификация или нет.)
Поскольку процесс прослушивания должен быть прерван первым, я, очевидно, не мог добавить вышеупомянутые операторы return непосредственно туда. Вот почему on_press
возвращает False
как в Esc
, так и в Shift Ctrl
случаях.
Я добавил логическую переменную escPressed
, чтобы четко разделить два случая. Ему True
присваивается значение A, если <Key.esc: <27>>
оно найдено в текущем наборе, и a False
присваивается в другом случае.
Теперь, получив escPressed
, я надеялся, что смогу просто добавить условие if / else и вернуть 0 или -1 на основе истинности или ложности escPressed
. Однако при запуске кода и нажатии Esc
мне кажется, что True
значение, установленное в escPressed
, игнорируется, как будто внутреннее escPress
не увидит уже определенное внешнее escPressed
. Я очень удивлен таким поведением, поскольку переменная, объявленная внутри функции, может быть доступна функциям внутри этой функции, как объяснено здесь.
Вот полный код:
from pynput import keyboard
COMBINATIONS = [
{ keyboard.Key.shift, keyboard.Key.ctrl_l },
{ keyboard.Key.esc }
]
def decideByKeypress():
current = set()
escPressed = bool()
def on_press(key):
if any([key in COMBO for COMBO in COMBINATIONS]):
current.add(key)
if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
print(current)
if keyboard.Key.esc in current:
escPressed = True
return False
elif (keyboard.Key.shift_l in current) and (keyboard.Key.ctrl_l in current):
escPressed = False
return False
else:
pass
def on_release(key):
try:
current.remove(key)
except KeyError:
pass
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
if escPressed:
print("Esc has been pressed!")
return -1
else:
print("Esc has not been pressed!")
return 0
if __name__ == "__main__":
decideByKeypress()
И вот мои выходные данные, которые я получил при нажатии Esc
:
{<Key.esc: <27>>}
escPressed is set to True
Esc has NOT been pressed!
Ответ №1:
Я не уверен в фактической реализации keyboard.Listener
, но что-то в ней, по-видимому, заставляет escPressed
быть видимой только on_press
функцию (вероятно, она выполняется в отдельном потоке).
Быстрым способом решения этой проблемы будет отслеживание состояния в изменяемой / совместно используемой структуре данных, например, a dict
.
state = {'esc': False}
def decideByKeypress():
current = set()
def on_press(key):
if any([key in COMBO for COMBO in COMBINATIONS]):
current.add(key)
if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
print(current)
if keyboard.Key.esc in current:
state['esc'] = True
return False
elif (keyboard.Key.shift_l in current) and (keyboard.Key.ctrl_l in current):
state['esc'] = False
return False
else:
pass
def on_release(key):
try:
current.remove(key)
except KeyError:
pass
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
if state['esc']:
print("Esc has been pressed!")
return -1
else:
print("Esc has not been pressed!")
return 0
if __name__ == "__main__":
decideByKeypress()
запуск и нажатие esc:
{<Key.esc: <27>>}
Esc has been pressed!
Комментарии:
1. Очень полезно! Огромное спасибо за вашу помощь, @DeepSpace!