2010-06-06 29 views
24

He intentado esto:Haskell: leer el carácter de entrada de la consola de inmediato, no después de nueva línea

main = do 
    hSetBuffering stdin NoBuffering 
    c <- getChar 

pero espera hasta que el se pulsa ENTER, que no es lo que quiero. Quiero leer el personaje inmediatamente después de que el usuario lo presiona.

estoy usando v6.12.1 GHC en Windows 7.

EDIT: solución para mí fue pasar de GHC a WinHugs, que apoya esto correctamente.

+2

Eso no es realmente una buena solución. La verdadera solución consiste en elegir explícitamente IO con búfer de caracteres; usando el getch del sistema conio.h El enlace de Artelius contiene un código de ejemplo para eso. – jrockway

+0

¡Es una buena solución si le conviene!Usar una herramienta diferente que no tenga el error tiene sentido. Si no necesita las características del lenguaje de compiladores recientes de ghc, WinHugs es más rápido que ghci o winghci en mi experiencia. Funciona sin problemas y se ve mejor. Tampoco necesita '' r' cuando haya editado su código, lo que me encanta. – AndrewC

+0

¿Cómo se relaciona con 'main = do hSetBuffering stdin NoBuffering; interactuar $ map Data.Char.toUpper'? En mi caso, espera una nueva línea antes de que aparezca ningún resultado. (Ubuntu, GHC 7.6.3.) – ominug

Respuesta

18

podría ser un error:

http://hackage.haskell.org/trac/ghc/ticket/2189

Los siguientes repeticiones del programa caracteres introducidos hasta que se pulsa la tecla de escape.

import IO 
import Monad 
import Char 

main :: IO() 
main = do hSetBuffering stdin NoBuffering 
      inputLoop 

inputLoop :: IO() 
inputLoop = do i <- getContents 
       mapM_ putChar $ takeWhile ((/= 27) . ord) i 

Debido a la línea de entrada estándar NoBuffering hSetBuffering que no debería ser necesario pulsar la tecla enter entre las pulsaciones del teclado. Este programa funciona correctamente en WinHugs (versión sep 2006). Sin embargo, GHC 6.8.2 no repite los caracteres hasta que se presiona la tecla enter. El problema se reproduce con todos los ejecutables de GHC (ghci, GHC, runghc, runhaskell), utilizando tanto cmd.exe y command.com en Windows XP Professional ...

4

Hmm .. En realidad no puedo ver esto característica para ser un error. Cuando lee stdin eso significa que quiere trabajar con un "archivo" y cuando pasa el búfer, está diciendo que no hay necesidad de leer el búfer. Pero eso no significa que la aplicación que está emulando ese "archivo" no debería usar el buffer de escritura. Para Linux, si su terminal está en modo "icanon", no envía ninguna entrada hasta que ocurra algún evento especial (como Enter presionado o Ctrl + D). Probablemente la consola en Windows tiene algunos modos similares.

+0

Gracias. Suena sinceramente, pero si ves la descripción del error: es realmente lo que estaba preguntando, así que por ahora voy a marcar la respuesta de Artelius. – Steves

+3

Al menos funciona de manera diferente en Windows y Linux. En Linux, el código publicado por Steves funciona SIN esperar. Entonces creo que es un error, y debería arreglarse. –

+0

Esto es (parcialmente) incorrecto. Al usar el software de emulación de consola o la consola MinGW, el almacenamiento en búfer aún se ignora. Windows ignora el almacenamiento en búfer en el nivel del sistema operativo, no a nivel de la consola. – YoYoYonnY

17

Sí, es un error. Aquí hay una solución para salvar a la gente y hacer clic en el desplazamiento:

{-# LANGUAGE ForeignFunctionInterface #-} 
import Data.Char 
import Foreign.C.Types 
getHiddenChar = fmap (chr.fromEnum) c_getch 
foreign import ccall unsafe "conio.h getch" 
    c_getch :: IO CInt 

para que pueda reemplazar las llamadas a getChar con llamadas a getHiddenChar.

Tenga en cuenta que esto es una solución para ghc/ghci en Windows. Por ejemplo, winhugs no tiene el error y este código no funciona en winhugs.

+1

Me gusta esta solución. Tenga en cuenta, sin embargo, que 'inseguro' causará una llamada de bloqueo a' getch' para bloquear todos los otros hilos en el programa. Soy autor del paquete ['hidden-char'] (http://hackage.haskell.org/package/hidden-char) en Hackage que tiene una variante de esta función que usa el FFI inseguro. –

1

El paquete Haskeline funcionó para mí.

Si lo necesita para caracteres individuales, simplemente cambie la muestra ligeramente.

  1. getInputLine convierte getInputChar
  2. "quit" se convierte en 'q'
  3. ++ input se convierte en ++ [input]
main = runInputT defaultSettings loop 
    where 
     loop :: InputT IO() 
     loop = do 
      minput <- getInputChar "% " 
      case minput of 
       Nothing -> return() 
       Just 'q' -> return() 
       Just input -> do outputStrLn $ "Input was: " ++ [input] 
           loop 
Cuestiones relacionadas