#1 Le 24/05/2021, à 15:00
- DonutMan75
[RESOLU] [python] lire un seul caractère sur l'entrée standard
Bonjour à tous,
je développe un petit programme en Python 3.X et à un moment je souhaite demander à l'utilisateur d'appuyer soit sur "flèche haut" soit sur "flèche bas" et agir en fonction de son action.
Il ne faudrait pas que l'utilisateur ait à appuyer sur "entrée" après avoir choisi la flèche. Confusément, je cherche l'équivalent d'un getchar() classique quoi..
En cherchant sur le net, je suis rapidement tombé sur ce fil qui préconise d'utiliser sys.stdin.read(1) pour lire UN caractère sur l'entrée standard. (j'ai royalement ignoré la partie sur la cross-compatibilité Windows, nous sommes entre gens bien élevés)
Mais voilà, je n'arrive pas à obtenir le bon comportement.... et selon le contexte de lancement du code (via Spyder ou via le terminal), le comportement change !
Mon code minimal :
import sys
while True:
sys.stdin.flush() # Je ne souhaite pas être pollué par ce qu'il y aurait dans le buffer au moment où je demande d'appuyer sur une touche
c = sys.stdin.read(1)
if c == ' ':
break
else:
print('- read : %s' % c)
Comportement avec Spyder : j'ai ça qui s'affiche en boucle sans que j'appuie sur une touche !
- read :
- read :
- read :
- read :
- read :
- read :
- read :
- read :
- read :
- read :
...
Comportement avec le terminal : l'appel est bien bloquant quand j'exécute le script sans rien envoyer sur l'entrée standard.
$ python test_char.py
<rien...>
En revanche, je suis obligé de taper "entrée" pour que ce soit pris en compte...
$ python test_char.py
abc<Entrée>
- read : a
- read : b
- read : c
- read :
Qu'en pensez-vous ?
Merci par avance
D.
Dernière modification par DonutMan75 (Le 25/05/2021, à 09:57)
Hors ligne
#2 Le 24/05/2021, à 17:47
- DonutMan75
Re : [RESOLU] [python] lire un seul caractère sur l'entrée standard
Alors, une première ébauche de réponse.
Pour commencer, getchar() tel qu'il est défini dans stdio.h attend un retour à la ligne ou un EOF pour traiter toute nouvelle arrivée sur stdin.
Donc en Python et avec sys.stdin.read(1), je viens bien récupérer exactement un caractère.. L'appel sera bloquant tant que le flux stdin est vide.
Mais (et c'est là que ça coince), pour le remplir je dois taper sur mon clavier (normal...) ET appuyer sur <Entrée> pour envoyer le tout sur stdin.
Après cela, l'appel à sys.stdin.read(1) reverra le 1ere caractère que j'ai envoyé.
Pour obtenir le comportement souhaité, il est possible d'utiliser la commande stty en amont du programme pour modifier le comportement du terminal
$ python test_char.py
abc<Entrée>
- read : a
- read : b
- read : c
- read :
$ stty -icanon
$ python test_char.py # Cette fois-ci j'obtiens bien le comportement attendu !
a- read : a
b- read : b
c- read : c
$ stty sane # on rétablit le comportement par défaut
A ce stade, j'ai un peu avancé mais ce n'est pas très élégant de devoir passer par stty pour obtenir ce que je souhaite... Je continue à creuser.
Par ailleurs, je n'ai toujours pas bien compris pourquoi le même programme exécuté via Spyder donnait un comportement différent...
D.
Hors ligne
#3 Le 25/05/2021, à 06:18
- Compte supprimé
Re : [RESOLU] [python] lire un seul caractère sur l'entrée standard
Bonjour,
Remarque:
Tu utilises python comme on utiliserait bash.
Avec python, tu disposes notamment de tkinter, une interface graphique qui te permet de gérer les événement claviers.
Exemple de mise en oeuvre:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="Appuyer flèche up/down", font=("helvetica", 30))
label.grid()
def action_up(event):
label.config(text="Tu viens d'appuyer sur up!")
def action_down(event):
label.config(text="Tu viens d'appuyer sur down!")
root.bind("<Up>", action_up)
root.bind('<Down>', action_down)
root.mainloop
#4 Le 25/05/2021, à 09:57
- DonutMan75
Re : [RESOLU] [python] lire un seul caractère sur l'entrée standard
Hello pseudofab !
Merci pour ton retour, c'est exactement ce que je cherchais à faire !
Je n'ai jamais vraiment utilisé tkinter, c'est l'occasion de m'y mettre
Bonne journée à tous,
D.
Hors ligne
#5 Le 26/05/2021, à 08:46
- Compte supprimé
Re : [RESOLU] [python] lire un seul caractère sur l'entrée standard
Je n'ai jamais vraiment utilisé tkinter, c'est l'occasion de m'y mettre
Je ne peux que t'y encourager... Tu ne regretteras pas le temps investi à son étude . Tkinter permet de faire un tas de trucs , y compris des jeux (tkinter.canvas est très puissant...)
À partir du lien ci-joint , tu trouveras une ressource pdf sur tkinter écrite en bon français et relativement complète...
http://ateliers.mse.free.fr/tkinter/page_tkinter.html
à plus
#6 Le 14/07/2021, à 17:25
- CasseTaTélé_isback
Re : [RESOLU] [python] lire un seul caractère sur l'entrée standard
Bonjour,
@pseudofab
j'ai copié ton example dans un fichier mais ça marche pas, ça donne ça quand je tape sur des touche dont (up et down) :
$ ./clavier6.py
^[[A^[[B^[[5~^[[6~+
00
3.48
PS: je ne veux pas d'interface graphique c'est pour un script python dans le terminal
Ubuntu 20.04
Hors ligne
#7 Le 14/07/2021, à 18:25
- Compte supprimé
Re : [RESOLU] [python] lire un seul caractère sur l'entrée standard
Bonjour,
Si tu veux lancer le script depuis le terminal, ajoute en début de script:
#!/usr/bin/env python3
Le mainloop(post #5) a été imputé de ses parenthèses lors de mon copié-collé:
root.mainloop()
Pour lancer le script avec
$ ./clavier6.py
, il te faut au préalable rendre le script exécutable:
chmod +x clavier6.py
Sinon, tu peux aussi le lancer explicitement :
python3 mon_chemin/clavier6.py
Voilà, tu devrais maintenant pouvoir exécuter le script
#8 Le 16/07/2021, à 09:31
- CasseTaTélé_isback
Re : [RESOLU] [python] lire un seul caractère sur l'entrée standard
Le mainloop(post #5) a été imputé de ses parenthèses lors de mon copié-collé:
ah oui c'est ça qu'il manquait ! (j'avais fait tout le reste pour le lancer bien sûr !
Ceci dit le résultat n'est pas celui que je voulais puisque ça ouvre une fenêtre ... Tant pis, merci quand même !
Ubuntu 20.04
Hors ligne