Не могу считывать сразу и нажатия и отжатия клавиш python keyboard

Недавно решил начать делать свою игру с нуля. Первым делом решил сделать систему биндинга клавиш. Легко сделал 2 типа - [одиночное нажатие,переключение]. Однако с созданием самого ходового типа - "удержания" появилась проблема. Я не могу сделать сразу отслеживание и нажатия и отжатия (новые потоки попросту не создаются. посмотрел это через threading.active_count()). Как я могу это починить. У меня есть идея с потиковой проверкой (отслеживание клавиатуры идет в цикле с ожиданием 0.1 секунду. в один тик можно проверять нажатие а в следующий отжатие и так поочередно) Весь код достаточно большой, так что приведу именно цикл.

f_Kb - класс, в котором я написал методы check_button_press и check_button_release, которые соответственно проверяют нажатие и отжатие заданной клавиши.

i = 0
while i < 100/0.1: #цикл идет 100 секунд
    z = 0
    while z < len(f_Kb.type): обнуление всех кулдаунов (для предотвращения ложных, повторных считываний)
        f_Kb.cooldowns[z] = False
        z += 1
    
    z = 0
    while z < len(f_Kb.online_keys): #запуск функций у активных биндов
        f_Kb.behaviours[f_Kb.get_index_by_object(f_Kb.online_keys[z],f_Kb.keys)]()
        z += 1

   
    #...............проблемное место.................
    keyboard.on_release(f_Kb.check_button_press)
    keyboard.on_press(f_Kb.check_button_release)
    i += 1

как я могу реализовать свою идею?


Ответы (1 шт):

Автор решения: Amgarak

Интересная зада, решил для вас сделать небольшой пример:

import keyboard
import threading
import queue
import time

class KeyTracker:
    def __init__(self, callback):
        self.pressed_keys = set()
        self.callback = callback
        self.queue = queue.Queue()

        keyboard.hook(self.key_event)

        self.callback_thread = threading.Thread(target=self.queue_callback)
        self.callback_thread.start()

    def key_event(self, event):
        if event.event_type == keyboard.KEY_DOWN:
            if event.name not in self.pressed_keys:
                self.pressed_keys.add(event.name)
                self.queue.put(self.pressed_keys)
                print(f"Нажата клавиша: {event.name}")  
                    
        elif event.event_type == keyboard.KEY_UP:
            if event.name in self.pressed_keys:
                self.pressed_keys.remove(event.name)
                self.queue.put(self.pressed_keys)
                print(f"Отпущена клавиша: {event.name}")  

    def queue_callback(self):
        while True:
            pressed_keys = self.queue.get()
            if pressed_keys is None:
                break  
            self.callback(pressed_keys)

    def stop(self):
        self.queue.put(None)  
        self.callback_thread.join()

    def start(self):
        try:
            keyboard.wait('esc')
        except KeyboardInterrupt:
            pass
        finally:
            self.stop()

threads = {}

def pressed_keys(keys):
    print(f"Активные клавиши: {keys}")
    if 'z' in keys and 'z' not in threads:
        threads['z'] = threading.Thread(target=z_pressed, args=(keys,))
        threads['z'].start()
        
    if 'x' in keys and 'x' not in threads:
        threads['x'] = threading.Thread(target=x_pressed, args=(keys,))
        threads['x'].start()
        
    keys_v_b = {'v', 'b'}
    if keys_v_b.issubset(keys) and 'v+b' not in threads:
        threads['v+b'] = threading.Thread(target=v_b_pressed, args=(keys,))
        threads['v+b'].start()

def z_pressed(keys):
    while 'z' in keys:
        print("Зажата Z")
        time.sleep(0.2) 
    del threads['z']
        
def x_pressed(keys):
    while 'x' in keys:
        print("Зажата x")
        time.sleep(0.2) 
    del threads['x']
        
def v_b_pressed(keys):
    while all(key in keys for key in ('v', 'b')):
        print("Зажата v+b")
        time.sleep(0.2) 
    del threads['v+b']

if __name__ == "__main__":
    tracker = KeyTracker(pressed_keys)
    tracker.start()

введите сюда описание изображения введите сюда описание изображения

→ Ссылка