0

J'essaie actuellement de démarrer et d'arrêter une boucle while en appuyant sur une touche (start) et en l'arrêtant en relâchant la touche.Modifier l'état de la variable de condition pour une boucle while en dehors de la boucle while

donc quelque chose comme ceci:

from pynput import keyboard 
global condition 
condition = False 

def on_press(key): 
    global condition 
    if key == keyboard.Key.cmd_r: 
     print('pressed cmd_r'.format(key)) 
     condition = True 
    else: 
     print('incorrect character {0}, press cmd_r'.format(key)) 


def on_release(key): 
    global condition 
    print('{0} released'.format(key)) 
    if key == keyboard.Key.cmd_r: 
     condition = False 
     #keyboard.Listener.stop 
     #return False 


with keyboard.Listener(on_press=on_press, on_release=on_release) as listener: 
    listener.join() 

while condition==True: 
    print "Condition true" 

Je ne sais pas pourquoi cela ne fonctionne pas .. Il devrait dans ma tête?

+0

est-ce peut-être que la condition est False au début, donc il ne démarre jamais réellement la boucle while et le processus se termine? –

+0

aussi 'condition' devrait être déclaré' global' dans les callbacks –

+0

J'ai mis le 'global' en haut mais devrait-il aussi être fait dans les rappels? – jkn

Répondre

0

Le problème est que lorsque vous appelez listener.join() votre code attend à ce point pour le fil à compléter. Mais ça ne se terminera jamais car c'est toujours à l'écoute! Au lieu de cela, vous voulez appeler listener.start() afin que le thread s'exécute en arrière-plan et vous êtes libre de faire ce que vous voulez.

Le partage de variables entre threads n'étant généralement pas accepté, je crée une classe d'écouteurs modifiée qui associe la variable key_pressed à elle-même lorsqu'une touche est enfoncée et None lorsqu'elle est libérée. Vous pouvez faire ce que vous voulez avec cette variable en cochant la case à tout moment dans une boucle séparée en appelant listener.key_pressed

from pynput import keyboard 
import time 


class MyListener(keyboard.Listener): 
    def __init__(self): 
     super(MyListener, self).__init__(self.on_press, self.on_release) 
     self.key_pressed = None 

    def on_press(self, key): 
     self.key_pressed = key 

    def on_release(self, key): 
     self.key_pressed = None 


listener = MyListener() 
listener.start() 

while True: 
    time.sleep(0.1) 
    print listener.key_pressed 

Notez que si vous ne donnez pas de retard avec time.sleep comme ci-dessus, vous surcharger la mémoire tampon et entraîner des retards dans la production. Il suffit de mettre un petit délai si vous le voulez rapidement, mais pas zéro.

+0

Pour vous assurer que vous avez bien saisi l'événement de touche, vous pouvez également modifier la méthode 'on_release' pour avoir aussi self.key_pressed = key'. Cependant, cela rend l'auditeur inutile après un seul événement de presse clé, mais peut-être que c'est ce que vous voulez! – henneray

+0

Cela ressemble à quelque chose que je cherchais, et 'on_release' doit arrêter l'action, donc le réinitialiser à' None' devrait être correct .. Dire devrait comme je semble avoir quelques problèmes à implémenter la fonctionnalité .. – jkn

+0

Ce sera son idiot, mais comment vérifier si une touche est pressée? Je n'arrive pas à tester la variable 'listener.key_pressed' avec les touches qu'elle imprime en plus de none? – jkn

0

Vous pourriez avoir besoin de quelque chose comme une boucle principale où vous pouvez inclure votre boucle spéciale pour y parvenir.

Mise à jour 1 - Comment? (Mauvais)

while True: 
    # main loop 
    while condition: 
     # your special loop 
     # do something... 
    time.sleep(0.1) # sleep 0.1 seconds 

La « boucle principale » est une boucle infinie et exécute des instructions incluses toutes les 0,1 seconde. Par conséquent, vous fournissez la possibilité de continuer à vérifier le condition. Si le condition == True votre "boucle spéciale" va s'exécuter et il s'arrête lorsque le condition == False, puis la "boucle principale" continue son exécution.

Mise à jour 2 - La mise en œuvre (correcte)

Ok, je l'ai exécuté le code et je vois que la solution « boucle principale » n'est pas ici. Pour l'instant, je rapide, solution éprouvée, basée sur multithreading:

import time 
import threading 

from pynput import keyboard 


condition = False 


def my_special_task(): 
    global condition 
    while condition: 
     print("condition = %s" % condition) 
     time.sleep(0.1) 


def on_press(key): 
    global condition 
    if key == keyboard.Key.ctrl_r: 
     print('Pressed ctrl_r') 
     condition = True 
     thread = threading.Thread(target=my_special_task) 
     thread.start() 
    else: 
     print("Incorrect KEY: %s, press ctrl_r instead" % key) 


def on_release(key): 
    global condition 
    print("%s released" % key) 
    if key == keyboard.Key.ctrl_r: 
     condition = False 


with keyboard.Listener(on_press=on_press, on_release=on_release) as listener: 
    listener.join() 
+0

mais comment? ... Je n'ai vraiment aucune idée de comment ça devrait être? – jkn

+0

et comment/où lisez-vous l'entrée du clavier, ou modifiez la 'condition' de la boucle while? – jkn

+0

J'avoue que la solution "boucle principale" est mauvaise, mais j'ai trouvé la bonne solution et mis à jour la réponse. Désolé pour le trompeur.Je pense qu'il faut des connaissances multithread en Python pour comprendre et résoudre des problèmes comme celui-ci. –