¿Cómo puedo verificar si un usuario ha presionado un botón mientras se ejecuta una función?


8

Tengo una función que se ejecuta automáticamente después de que el usuario realiza alguna acción. Sin embargo, la función tarda mucho en completarse. Esto significa que Emacs deja de responder por un corto tiempo después de cada entrada. Para solucionar esto, me gustaría verificar si el usuario ha ingresado una nueva entrada y, de ser así, cancelar la ejecución de esta función y proceder con la entrada del usuario.

¿Hay alguna variable que contenga entradas de teclado en cola? Si no, ¿hay otra forma de verificar si el usuario ha presionado un botón desde que una función comenzó a ejecutarse?


2
Es posible que desee mirar while-no-inputmacro. Parece hacer lo que quiere: es decir, cancela la ejecución de su cuerpo cuando aparece una nueva entrada.
wvxvw el

@wvxvw Tu comentario me parece una buena respuesta. ¡Deberías publicarlo como tal!
Phil Hudson el

Respuestas:


5

OK, intentaré una respuesta ampliada. La cuestión es que Emacs Lisp es de un solo subproceso. Puede girar más procesos, pero no dentro del intérprete de Emacs Lisp. Sin embargo, la entrada de teclado que necesita leer del usuario para interrumpir su función debe ser procesada por el mismo intérprete de Emacs Lisp. Esto significa que si su intérprete está atascado interpretando algún código Lisp, puede que no haya una forma de interrumpirlo desde dentro. Aquí hay un lugar en el manual que describe esta situación:

En el nivel del código C, dejar de fumar no puede ocurrir en cualquier lugar; solo en los lugares especiales que marcan dejar de fumar. La razón de esto es que dejar de fumar en otros lugares puede dejar una inconsistencia en el estado interno de Emacs. Debido a que dejar de fumar se retrasa hasta un lugar seguro, no puede hacer que Emacs se bloquee.

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

Entonces, ¿cómo Emacs todavía tiene la C-gfuncionalidad / cancelación? - Hay temporizadores y funciones que hacen E / S (esperar eventos en el bucle de comandos). Los temporizadores pueden organizar que sus cálculos se realicen en fragmentos, de modo que tenga puntos en sus cálculos donde pueda mirar a su alrededor y, si es necesario, evitar todos los cálculos adicionales. Las funciones de E / S pueden enviar quitseñal. La macro with-keyboard-quitespera esta señal y una vez recibida saldrá con gracia. Sin embargo, su función necesita saber para enviar esta señal. Esto significa que si su función impide que el usuario envíe la entrada del teclado, no podrá beneficiarse de las interrupciones del teclado.

En pocas palabras: intente envolver el código de su función while-no-input. Si esto no funciona, intente reescribir su función de manera que permita que Emacs procese los eventos del teclado.


C-gsiempre puede interrumpir el código lisp, while-no-inputsolo lo extiende a otra entrada de teclado.
npostavs

@npostavs no realmente. Intenta interrumpir algo como (while t). (Pero antes de hacerlo, asegúrese de haber guardado todos los cambios).
wvxvw

He escrito (while t)en *scratch*y golpear C-x C-ea continuación C-g; Recibí el Quitmensaje, Emacs no se atascó.
npostavs

@npostavs bueno, seguro encontraré una combinación que no es posible interrumpir, pero que no tengo tiempo para buscarla en este momento. Sin *scratch*embargo, no estoy seguro de cuánto se puede confiar porque cada evaluación que realice allí está envuelta en una función auxiliar.
wvxvw

Me las arreglé para quedarme atrapado (while t (condition-case _ (while t) (quit nil))), creo que en teoría eso es interrumpible si pudieras golpear C-gen el momento adecuado, pero en la práctica no puedes.
npostavs

3

Me gustaría ir con input-pending-t. De los documentos:

(input-pendiente-p y CHECK-TIMERS opcionales)

Devuelve t si la entrada de comando está disponible actualmente sin esperar. En realidad, el valor es nulo solo si podemos estar seguros de que no hay entrada disponible; Si hay una duda, el valor es t.

Un ejemplo rápido:

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

¡Perfecto! Ambas respuestas son geniales, lástima que solo pudiera aceptar una. ¡Gracias!
jcaw
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.