Haskell:立即从控制台读取输入字符,而不是在换行符之后

时间:2010-06-06 11:14:09

标签: windows haskell io ghc buffering

我试过这个:

main = do
    hSetBuffering stdin NoBuffering 
    c <- getChar

但它会等到按下输入,这不是我想要的。我希望在用户按下后立即阅读该字符。

我在Windows 7上使用ghc v6.12.1。

编辑:我的解决方法是从GHC转移到WinHugs,它正确地支持了这一点。

4 个答案:

答案 0 :(得分:19)

可能是个错误:

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

  

以下程序重复输入的字符,直到按下退出键。

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
     

由于hSetBuffering stdin NoBuffering行,因此无需在按键之间按Enter键。此程序在WinHugs中正常工作(sep 2006版)。但是,GHC 6.8.2在按下回车键之前不会重复这些字符。使用所有GHC可执行文件(ghci,ghc,runghc,runhaskell),在Windows XP Professional上同时使用cmd.exe和command.com重现该问题...

答案 1 :(得分:19)

是的,这是一个错误。这是一个解决方法来保存人们点击和滚动:

{-# 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

因此,您可以通过调用getChar替换对getHiddenChar的来电。

请注意,这是针对Windows上的ghc / ghci的解决方法。例如,winhugs没有错误,这段代码在winhugs中不起作用。

答案 2 :(得分:3)

嗯..实际上我看不出这个功能是个bug。当您阅读stdin表示您想要使用“文件”时,当您开始缓冲时,您说不需要读取缓冲区。但这并不意味着模拟“文件”的应用程序不应该使用写缓冲区。对于Linux,如果您的终端处于“icanon”模式,它将不会发送任何输入,直到发生某些特殊事件(如按下Enter或Ctrl + D)。可能Windows中的控制台有一些类似的模式。

答案 3 :(得分:2)

Haskeline包对我有用。

如果您需要单个字符,那么只需稍微更改一下样本。

  1. getInputLine变为getInputChar
  2. "quit"变为'q'
  3. ++ input变为++ [input]
  4. 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