¿Hay alguna manera de leer un solo carácter de la entrada del usuario? Por ejemplo, presionan una tecla en la terminal y se devuelve (algo así como getch()
). Sé que hay una función en Windows para ello, pero me gustaría algo que sea multiplataforma.
262
msvcrt.getch
conmsvcrt.getwch
, como se sugiere allí.Respuestas:
Aquí hay un enlace a un sitio que dice cómo puede leer un solo carácter en Windows, Linux y OSX: http://code.activestate.com/recipes/134892/
fuente
ImportError
se usa la excepción como algún tipo de declaración if; ¿Por qué no llamar a platform.system () para verificar el sistema operativo?básicamente leerá 1 byte de STDIN.
Si debe usar el método que no espera
\n
, puede usar este código como se sugiere en la respuesta anterior:( tomado de http://code.activestate.com/recipes/134892/ )
fuente
La receta de ActiveState citada textualmente en dos respuestas está sobredimensionada. Se puede reducir a esto:
fuente
0
.También vale la pena probar la biblioteca readchar , que se basa en parte en la receta ActiveState mencionada en otras respuestas.
Instalación:
Uso:
Probado en Windows y Linux con Python 2.7.
En Windows, sólo llaves que se asignan a letras o códigos de control ASCII son compatibles ( Backspace, Enter, Esc, Tab, Ctrl+ carta ). En GNU / Linux (dependiendo de la terminal exacta, tal vez?) Que también consigue Insert, Delete, Pg Up, Pg Dn, Home, Endy llaves ... pero entonces, hay cuestiones que separan estas teclas especiales de una .F nEsc
Advertencia: Al igual que con la mayoría de las respuestas (¿todas?) Aquí, las teclas de señal como Ctrl+ C, Ctrl+ Dy Ctrl+ Zse capturan y devuelven (como
'\x03'
,'\x04'
y'\x1a'
respectivamente); Su programa puede ser difícil de abortar.fuente
Un método alternativo:
De esta publicación de blog .
fuente
| os.O_NONBLOCK
. De lo contrario, puede ponerlo en un bucle (es una buena idea dormir un poco en el bucle para evitar que gire).while True
entonceswhile 1
.Este código, basado aquí , elevará correctamente KeyboardInterrupt y EOFError si se presiona Ctrl+ Co Ctrl+ D.
Debería funcionar en Windows y Linux. Una versión de OS X está disponible desde la fuente original.
fuente
La respuesta (actualmente) mejor clasificada (con el código ActiveState) es demasiado complicada. No veo una razón para usar clases cuando una mera función debería ser suficiente. A continuación hay dos implementaciones que logran lo mismo pero con un código más legible.
Ambas implementaciones:
Versión 1: legible y simple
Versión 2: evitar importaciones repetidas y manejo de excepciones:
[EDITAR] Perdí una ventaja del código ActiveState. Si planea leer caracteres varias veces, ese código evita el costo (insignificante) de repetir la importación de Windows y el manejo de excepciones ImportError en sistemas similares a Unix. Si bien probablemente debería estar más preocupado por la legibilidad del código que por esa optimización insignificante, aquí hay una alternativa (es similar a la respuesta de Louis, pero getChar () es autónomo) que funciona igual que el código ActiveState y es más legible:
Código de ejemplo que ejercita cualquiera de las versiones getChar () anteriores:
fuente
Este podría ser un caso de uso para un administrador de contexto. Dejando de lado las asignaciones para el sistema operativo Windows, esta es mi sugerencia:
fuente
self
en__enter__
y tener unread
método que devuelvesys.stdin.read(1)
, entonces se podría leer múltiples personajes en un contexto.Intente usar esto: http://home.wlu.edu/~levys/software/kbhit.py No bloquea (eso significa que puede tener un bucle while y detectar una pulsación de tecla sin detenerlo) y multiplataforma.
Un ejemplo para usar esto:
O puede usar el módulo getch de PyPi . Pero esto bloquearía el ciclo while
fuente
Esto es NO BLOQUEO, lee una clave y la almacena en keypress.key.
en tu programa
fuente
Las respuestas aquí fueron informativas, sin embargo, también quería una forma de presionar las teclas de forma asincrónica y disparar las pulsaciones de teclas en eventos separados, todo de manera segura y multiplataforma. PyGame también estaba demasiado hinchado para mí. Así que hice lo siguiente (en Python 2.7 pero sospecho que es fácilmente portátil), que pensé que compartiría aquí en caso de que fuera útil para cualquier otra persona. Lo almacené en un archivo llamado keyPress.py.
La idea es simplemente llamar
keyPress.getKey()
, lo que leerá una tecla del teclado y luego devolverla.Si quieres algo más que eso, hice un
KeyCapture
objeto. Puedes crear uno a través de algo comokeys = keyPress.KeyCapture()
.Luego hay tres cosas que puedes hacer:
addEvent(functionName)
toma cualquier función que tome un parámetro. Luego, cada vez que se presiona una tecla, se llamará a esta función con la cadena de esa tecla como entrada. Estos se ejecutan en un hilo separado, por lo que puede bloquear todo lo que desee en ellos y no estropeará la funcionalidad de KeyCapturer ni retrasará los otros eventos.get()
devuelve una clave del mismo modo de bloqueo que antes. Ahora se necesita aquí porque las claves se están capturando a través delKeyCapture
objeto ahora, porkeyPress.getKey()
lo que entraría en conflicto con ese comportamiento y ambos perderían algunas claves ya que solo se puede capturar una clave a la vez. Además, digamos que el usuario presiona 'a', luego 'b', usted llamaget()
, el usuario presiona 'c'. Esaget()
llamada devolverá inmediatamente 'a', luego, si la vuelve a llamar, devolverá 'b', luego 'c'. Si lo vuelve a llamar, se bloqueará hasta que presione otra tecla. Esto asegura que no se pierda ninguna tecla, de forma bloqueada si lo desea. Entonces, de esta manera es un poco diferente quekeyPress.getKey()
antesSi desea el comportamiento de
getKey()
atrás,get(lossy=True)
es comoget()
, excepto que solo devuelve las teclas presionadas después de la llamada aget()
. Entonces, en el ejemplo anterior,get()
se bloquearía hasta que el usuario presione 'c', y luego, si lo vuelve a llamar, se bloqueará hasta que se presione otra tecla.getAsync()
Es un poco diferente. Está diseñado para algo que procesa mucho, luego vuelve ocasionalmente y comprueba qué teclas se presionaron. Por lo tanto,getAsync()
devuelve una lista de todas las teclas presionadas desde la última llamada agetAsync()
, en orden desde la tecla más antigua presionada hasta la más reciente. Tampoco se bloquea, lo que significa que si no se ha presionado ninguna tecla desde la última llamadagetAsync()
,[]
se devolverá un vacío .Para comenzar realmente a capturar claves, debe llamar
keys.startCapture()
con sukeys
objeto hecho anteriormente.startCapture
no bloquea, y simplemente inicia un hilo que solo registra las pulsaciones de teclas, y otro hilo para procesar esas pulsaciones de teclas. Hay dos hilos para garantizar que el hilo que registra las pulsaciones de teclas no pierda ninguna tecla.Si desea dejar de capturar claves, puede llamar
keys.stopCapture()
y dejará de capturar claves. Sin embargo, dado que capturar una clave es una operación de bloqueo, las claves de captura de subprocesos pueden capturar una clave más después de llamarstopCapture()
.Para evitar esto, puede pasar un parámetro o parámetros opcionales a
startCapture(functionName, args)
una función que simplemente hace algo como verificar si una tecla es igual a 'c' y luego sale. Es importante que esta función haga muy poco antes, por ejemplo, dormir aquí nos hará perder teclas.Sin embargo, si
stopCapture()
se llama en esta función, las capturas de teclas se detendrán de inmediato, sin intentar capturar más, y todas lasget()
llamadas se devolverán de inmediato, con Ninguno si aún no se ha presionado ninguna tecla.Además, dado que
get()
ygetAsync()
almacenar todas las teclas presionadas anteriores (hasta que se recupere), puede llamarclearGetList()
yclearAsyncList()
olvidar las teclas pulsadas previamente.Tenga en cuenta que
get()
,getAsync()
y los eventos son independientes, por lo que si se presiona una tecla: 1. Una llamadaget()
que está en espera, con pérdida activada, devolverá esa tecla. Las otras llamadas en espera (si las hay) continuarán esperando. 2. Esa clave se almacenará en la cola de obtención de claves, de modo queget()
con pérdida desactivada, se devolverá la tecla más antigua presionada que aún no ha sido devueltaget()
. 3. Todos los eventos se activarán con esa clave como su entrada 4. Esa clave se almacenará en la lista degetAsync()
claves, donde se devolverá esa lista y se configurará como lista vacía en la próxima llamada agetAsync()
Si todo esto es demasiado, aquí hay un caso de uso de ejemplo:
Me está funcionando bien a partir de la simple prueba que hice, pero felizmente recibiré comentarios de otros también si hay algo que me perdí.
Publiqué esto aquí también.
fuente
Un comentario en una de las otras respuestas mencionó el modo cbreak, que es importante para las implementaciones de Unix porque generalmente no desea que
KeyboardError
getchar consuma ^ C ( ) (como lo hará cuando configura el terminal en modo sin procesar, como lo hace la mayoría de las otras respuestas).Otro detalle importante es que si está buscando leer un carácter y no un byte , debe leer 4 bytes de la secuencia de entrada, ya que esa es la cantidad máxima de bytes que un solo carácter consistirá en UTF-8 (Python 3+ ) La lectura de un solo byte producirá resultados inesperados para caracteres de varios bytes, como las flechas del teclado.
Aquí está mi implementación modificada para Unix:
fuente
Prueba esto con pygame:
fuente
pygame.error: video system not initialized
La receta de ActiveState parece contener un pequeño error para los sistemas "posix" que impide la
Ctrl-C
interrupción (estoy usando Mac). Si pongo el siguiente código en mi script:Nunca podré terminar el script con
Ctrl-C
, y tengo que matar mi terminal para escapar.Creo que la siguiente línea es la causa, y también es demasiado brutal:
Aparte de eso, el paquete
tty
no es realmente necesario,termios
es suficiente para manejarlo.A continuación se muestra el código mejorado que funciona para mí (
Ctrl-C
se interrumpirá), con lagetche
función adicional que repite el carácter mientras escribe:Referencias
fuente
El
curses
paquete en python se puede usar para ingresar al modo "en bruto" para la entrada de caracteres desde el terminal con solo unas pocas declaraciones. El uso principal de Curses es hacerse cargo de la pantalla para la salida, que puede no ser lo que desea. Este fragmento de código utiliza en suprint()
lugar declaraciones, que son utilizables, pero debe ser consciente de cómo las maldiciones cambian las terminaciones de línea asociadas a la salida.fuente
Si estoy haciendo algo complicado, usaré maldiciones para leer las claves. Pero muchas veces solo quiero un script Python 3 simple que use la biblioteca estándar y pueda leer las teclas de flecha, así que hago esto:
fuente
Mi solución para python3, no depende de ningún paquete pip.
fuente
Creo que esta es la solución más elegante.
y luego úsalo en el código:
fuente
La respuesta aceptada no funcionó tan bien para mí (presionaría una tecla, no pasaría nada, luego presionaría otra tecla y funcionaría).
Después de aprender sobre el módulo de maldiciones , realmente parece ser el camino correcto. Y ahora está disponible para Windows a través de cursores de Windows (disponible a través de pip), por lo que puede programar de manera independiente de la plataforma. Aquí hay un ejemplo inspirado en este bonito tutorial en YouTube:
Guárdelo con una
.py
extensión o ejecútelocurses.wrapper(getkey)
en modo interactivo.fuente
Respondido aquí: raw_input en python sin presionar enter
Usa este código
Referencia: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
fuente
Si desea registrar solo una tecla, presione incluso si el usuario la presionó por más de una vez o siguió presionando la tecla por más tiempo. Para evitar obtener múltiples entradas presionadas, use el bucle while y páselo.
fuente
si solo quieres sostener la pantalla para que puedas ver el resultado en el terminal solo escribe
al final del código y mantendrá la pantalla
fuente
El raw_input incorporado debería ayudar.
fuente