Come posso verificare se un utente ha premuto un pulsante mentre una funzione è in esecuzione?


8

Ho una funzione che viene eseguita automaticamente dopo che l'utente fa qualche azione. Tuttavia, il completamento della funzione richiede molto tempo. Ciò significa che Emacs non risponde per un breve periodo dopo ogni input. Per risolvere questo problema, vorrei verificare se l'utente ha inserito un nuovo input e, in tal caso, annullare l'esecuzione di questa funzione e procedere con l'input dell'utente.

Esiste una variabile che contiene input da tastiera in coda? In caso contrario, esiste un altro modo per verificare se l'utente ha premuto un pulsante da quando è stata avviata una funzione?


2
Potresti voler guardare la while-no-inputmacro. Sembra fare quello che vuoi: cioè annulla l'esecuzione del suo corpo quando appare un nuovo input.
wvxvw,

@wvxvw Il tuo commento mi sembra una buona risposta. Dovresti pubblicarlo come tale!
Phil Hudson,

Risposte:


5

OK, proverò una risposta estesa. Il fatto è che Emacs Lisp è a thread singolo. È possibile eseguire più processi, ma non all'interno dell'interprete Emacs Lisp. Tuttavia, l'input da tastiera che devi leggere dall'utente per interrompere la tua funzione deve essere elaborato dallo stesso interprete Emacs Lisp. Ciò significa che se l'interprete è bloccato nell'interpretazione di un codice Lisp, potrebbe non esserci un modo per interromperlo dall'interno. Ecco un punto nel manuale che descrive questa situazione:

A livello di codice C, la chiusura non può avvenire da nessuna parte; solo nei posti speciali che controllano il quit-flag. La ragione di ciò è che smettere in altri luoghi potrebbe lasciare un'incoerenza nello stato interno di Emacs. Poiché la chiusura è posticipata fino a un luogo sicuro, la chiusura non può causare il crash di Emacs.

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

Quindi, come Emacs ha ancora la C-gfunzionalità / annullamento? - Ci sono timer e funzioni che eseguono I / O (attendere gli eventi nel ciclo di comando). I timer possono disporre che i calcoli vengano eseguiti in blocchi, in modo da avere punti nei calcoli in cui è possibile guardarsi intorno e, se necessario, impedire tutti i calcoli successivi. Le funzioni I / O possono inviare quitsegnali. La macro with-keyboard-quitattende questo segnale e una volta ricevuta uscirà con grazia. Tuttavia, la tua funzione deve sapere per inviare questo segnale. Ciò significa che se la tua funzione impedisce all'utente di inviare input da tastiera, non sarai in grado di beneficiare degli interrupt da tastiera.

In conclusione: prova a racchiudere il codice della tua funzione in while-no-input. Se questo non funziona, prova a riscrivere la tua funzione in modo che Emacs elabori gli eventi della tastiera.


C-gpuò sempre interrompere il codice lisp, while-no-inputsemplicemente lo estende ad altri input da tastiera.
npostavs

@npostavs non proprio. Prova a interrompere qualcosa del genere (while t). (Ma prima di farlo, assicurati di aver salvato tutte le modifiche).
wvxvw,

Ho digitato (while t)in *scratch*e ha colpito C-x C-epoi C-g; Ho ricevuto il Quitmessaggio, Emacs non si è bloccato.
npostavs,

@npostavs, troverò sicuramente una combinazione che non è possibile interrompere, ma non ho tempo di cercarla in questo momento. Non sono sicuro di quanto ci si *scratch*può fidare perché ogni valutazione che fai lì è racchiusa in una funzione di aiuto.
wvxvw,

Sono riuscito a rimanere bloccato (while t (condition-case _ (while t) (quit nil))), penso in teoria che sia interrompibile se potessi colpire C-gal momento giusto, ma in pratica non puoi.
npostavs,

3

Vorrei andare con input-pending-t. Dai documenti:

(input-pending-p e CHECK-TIMER opzionali)

Restituisce t se l'input del comando è attualmente disponibile senza attesa. In realtà, il valore è nullo solo se possiamo essere sicuri che nessun input sia disponibile; in caso di dubbio, il valore è t.

Un rapido esempio:

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

Perfetto! Entrambe le risposte sono fantastiche, peccato che potrei accettarne solo una. Grazie!
giovedì
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.