Wie kann ich überprüfen, ob ein Benutzer eine Taste gedrückt hat, während eine Funktion ausgeführt wird?


8

Ich habe eine Funktion, die automatisch ausgeführt wird, nachdem der Benutzer eine Aktion ausgeführt hat. Die Ausführung der Funktion dauert jedoch lange. Dies bedeutet, dass Emacs nach jeder Eingabe für kurze Zeit nicht mehr reagiert. Um dies zu beheben, möchte ich überprüfen, ob der Benutzer eine neue Eingabe eingegeben hat, und in diesem Fall die Ausführung dieser Funktion abbrechen und mit der Benutzereingabe fortfahren.

Gibt es eine Variable, die Tastatureingaben in der Warteschlange enthält? Wenn nicht, gibt es eine andere Möglichkeit zu überprüfen, ob der Benutzer eine Taste gedrückt hat, seit eine Funktion ausgeführt wurde?


2
Vielleicht möchten Sie sich das while-no-inputMakro ansehen . Es scheint zu tun, was Sie wollen: dh es bricht die Ausführung seines Körpers ab, wenn neue Eingaben erscheinen.
wvxvw

@wvxvw Dein Kommentar scheint mir eine gute Antwort zu sein. Du solltest es als solches posten!
Phil Hudson

Antworten:


5

OK, ich werde eine erweiterte Antwort versuchen. Die Sache ist, Emacs Lisp ist Single-Threaded. Sie können mehr Prozesse drehen, jedoch nicht im Emacs Lisp-Interpreter. Die Tastatureingaben, die Sie vom Benutzer lesen müssen, um Ihre Funktion zu unterbrechen, müssen jedoch von demselben Emacs Lisp-Interpreter verarbeitet werden. Dies bedeutet, dass Sie möglicherweise keine Möglichkeit haben, den Lisp-Code von innen heraus zu unterbrechen, wenn Ihr Interpreter beim Interpretieren eines Lisp-Codes nicht weiterkommt. Hier ist eine Stelle im Handbuch, die diese Situation beschreibt:

Auf der Ebene des C-Codes kann das Beenden nicht überall stattfinden. nur an den besonderen Stellen, die die Quit-Flag überprüfen. Der Grund dafür ist, dass das Beenden an anderen Orten zu einer Inkonsistenz im internen Zustand von Emacs führen kann. Da das Beenden bis zu einem sicheren Ort verzögert wird, kann das Beenden Emacs nicht zum Absturz bringen.

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

Wie hat Emacs noch die C-gFunktion / Abbrechen? - Es gibt Timer und Funktionen, die E / A ausführen (auf Ereignisse in der Befehlsschleife warten). Timer können dafür sorgen, dass Ihre Berechnungen in Blöcken durchgeführt werden, sodass Sie Punkte in Ihren Berechnungen haben, an denen Sie sich umschauen und gegebenenfalls alle weiteren Berechnungen verhindern können. E / A-Funktionen können quitSignale senden . Das Makro with-keyboard-quitwartet auf dieses Signal und wird nach dem Empfang ordnungsgemäß beendet. Ihre Funktion muss jedoch wissen, um dieses Signal zu senden. Dies bedeutet, dass Sie nicht von Tastaturunterbrechungen profitieren können, wenn Ihre Funktion den Benutzer daran hindert, Tastatureingaben zu senden.

Fazit: Versuchen Sie, den Code Ihrer Funktion in zu verpacken while-no-input. Wenn dies nicht funktioniert, schreiben Sie Ihre Funktion so um, dass Emacs Tastaturereignisse verarbeiten kann.


C-gkann lisp-Code immer unterbrechen, while-no-inputerweitert dies nur auf andere Tastatureingaben.
Npostavs

@npostavs nicht wirklich. Versuchen Sie so etwas zu unterbrechen (while t). (Aber bevor Sie dies tun, stellen Sie sicher, dass Sie alle Ihre Änderungen gespeichert haben).
wvxvw

Ich tippte (while t)in ein *scratch*und drücken Sie C-x C-edann C-g; Ich habe die QuitNachricht erhalten, Emacs ist nicht hängen geblieben.
Npostavs

@npostavs Nun, ich werde sicher eine Kombination finden, die nicht unterbrochen werden kann, aber ich habe momentan keine Zeit, danach zu suchen. Ich bin mir jedoch nicht sicher, wie viel *scratch*vertrauenswürdig ist, da jede Bewertung, die Sie dort vornehmen, in eine Hilfsfunktion eingebunden ist.
wvxvw

Ich habe es geschafft, festzuhalten (while t (condition-case _ (while t) (quit nil))), ich denke theoretisch ist das unterbrechbar, wenn man nur C-gzum richtigen Zeitpunkt treffen könnte , aber in der Praxis kann man das nicht.
Npostavs

3

Ich würde mit gehen input-pending-t. Aus den Dokumenten:

(Eingabe anstehend-p & optionale CHECK-TIMER)

Geben Sie t zurück, wenn die Befehlseingabe derzeit ohne Wartezeit verfügbar ist. Tatsächlich ist der Wert nur dann Null, wenn wir sicher sein können, dass keine Eingabe verfügbar ist. Im Zweifelsfall ist der Wert t.

Ein kurzes Beispiel:

(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))

Perfekt! Beide Antworten sind großartig, schade, dass ich nur eine akzeptieren konnte. Vielen Dank!
Jcaw
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.