Comment puis-je vérifier si un utilisateur a appuyé sur un bouton pendant l'exécution d'une fonction?

8

J'ai une fonction qui s'exécute automatiquement après que l'utilisateur a effectué une action. Cependant, la fonction prend beaucoup de temps. Cela signifie qu'Emacs ne répond plus pendant une courte période après chaque entrée. Pour résoudre ce problème, je voudrais vérifier si l'utilisateur a entré une nouvelle entrée et si oui, annuler l'exécution de cette fonction et poursuivre la saisie de l'utilisateur.

Y a-t-il une variable qui contient les entrées de clavier en file d'attente? Sinon, existe-t-il un autre moyen de vérifier si l'utilisateur a appuyé sur un bouton depuis le début de l'exécution d'une fonction?

jcaw
la source
2
Vous voudrez peut-être regarder la while-no-inputmacro. Il semble faire ce que vous voulez: c'est-à-dire qu'il annule l'exécution de son corps lorsque de nouvelles entrées apparaissent.
wvxvw
@wvxvw Votre commentaire me semble être une bonne réponse. Vous devez le poster comme tel!
Phil Hudson

Réponses:

5

OK, je vais essayer une réponse élargie. Le fait est qu'Emacs Lisp est monothread. Vous pouvez faire tourner plus de processus, mais pas à l'intérieur de l'interpréteur Emacs Lisp. Cependant, l'entrée au clavier que vous devez lire à l'utilisateur pour interrompre votre fonction doit être traitée par le même interpréteur Emacs Lisp. Cela signifie que si votre interprète est bloqué en train d'interpréter du code Lisp, vous ne pourrez peut-être pas l'interrompre de l'intérieur. Voici un endroit dans le manuel qui décrit cette situation:

Au niveau du code C, l'arrêt ne peut se produire n'importe où; uniquement aux endroits spéciaux qui cochent quit-flag. La raison en est que cesser de fumer à d'autres endroits peut laisser une incohérence dans l'état interne d'Emacs. Parce que quitter est retardé jusqu'à un endroit sûr, il ne peut pas faire planter Emacs.

https://www.gnu.org/software/emacs/manual/html_node/elisp/Quitting.html

Alors, comment Emacs a-t-il toujours la C-gfonctionnalité / annulation? - Il y a des temporisateurs et des fonctions qui font des E / S (attendre les événements dans la boucle de commande). Les temporisateurs peuvent arranger vos calculs en morceaux, afin que vous ayez des points dans vos calculs où vous pouvez regarder autour et, si nécessaire, empêcher tous les calculs ultérieurs. Les fonctions d'E / S peuvent envoyer un quitsignal. La macro with-keyboard-quitattend ce signal et une fois reçue, elle se terminera normalement. Cependant, votre fonction doit savoir pour envoyer ce signal. Cela signifie que si votre fonction empêche l'utilisateur d'envoyer des entrées au clavier, vous ne pourrez pas bénéficier des interruptions du clavier.

En résumé: essayez d'enrouler le code de votre fonction dans while-no-input. Si cela ne fonctionne pas, essayez de réécrire votre fonction de manière à permettre à Emacs de traiter les événements du clavier.

wvxvw
la source
C-gpeut toujours interrompre le code lisp, while-no-inputl'étend simplement à d'autres entrées du clavier.
npostavs
@npostavs pas vraiment. Essayez d'interrompre quelque chose comme (while t). (Mais avant de le faire, assurez-vous d'avoir enregistré toutes vos modifications).
wvxvw
Je tapé (while t)dans *scratch*et frappé C-x C-epuis C-g; J'ai compris le Quitmessage, Emacs n'est pas resté coincé.
npostavs
@npostavs bien, je trouverai certainement une combinaison qui n'est pas possible d'interrompre, mais je n'ai pas le temps de la chercher pour le moment. Je ne sais pas à quel point *scratch*on peut faire confiance, car chaque évaluation que vous y faites est enveloppée dans une fonction d'aide.
wvxvw
J'ai réussi à rester avec (while t (condition-case _ (while t) (quit nil))), je pense qu'en théorie c'est interruptible si vous pouviez juste frapper C-gau bon moment, mais en pratique vous ne pouvez pas.
npostavs
3

J'irais avec input-pending-t. De la documentation:

(entrée en attente-p et CHECK-TIMERS en option)

Renvoie t si l'entrée de commande est actuellement disponible sans attente. En fait, la valeur n'est nulle que si nous pouvons être sûrs qu'aucune entrée n'est disponible; en cas de doute, la valeur est t.

Un exemple rapide:

(progn
  ;; I put this into a progn call so you can call it direcly from Emacs
  ;; if you are using the sx package
  (message "Try pressing a key in the next 2 seconds!")
  (sleep-for 2)
  (message (if (input-pending-p)
               "There is input waiting!"
             "No input, let’s move on!"))
  (sleep-for 2))
GergelyPolonkai
la source
Parfait! Les deux réponses sont excellentes, dommage que je ne puisse en accepter qu'une. Merci!
jcaw