我尝试过这个:
main = do
hSetBuffering stdin NoBuffering
c <- getChar
但它会等待用户按下回车键,这不是我想要的。我希望能够立即读取用户按下的字符。
我正在使用 Windows 7 上的 GHC v6.12.1。
编辑:对我来说解决方法是从 GHC 切换到支持此功能的 WinHugs。
是的,这是一个 bug。以下是一种解决方法,可以避免用户不断点击和滚动:
{-# 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没有这个bug,因此在winhugs中不起作用。
unsafe
会导致一个阻塞调用 getch
的操作阻塞程序中的所有其他线程。我是 hidden-char
包在 Hackage 上的作者,它使用了不安全的 FFI 来实现此函数的变体。 - Richard CookByteCodeLink: can't find label During interactive linking, GHCi couldn't find the following symbol: getch
请尝试将 getch
替换为 _getch
以进行外部导入。 - Oly可能是个bug:
http://hackage.haskell.org/trac/ghc/ticket/2189
下面的程序会重复输入的字符,直到按下Esc键。
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 line,不需要在按键之间按下回车键。这个程序在 WinHugs(2006年9月版本)中可以正常工作。然而,在 GHC 6.8.2 中,直到按下回车键之前,字符才会被重复打印。在 Windows XP Professional 上,使用 cmd.exe 和 command.com,所有 GHC 可执行文件(ghci、ghc、runghc、runhaskell)都出现了这个问题...
嗯...实际上我认为这个功能并不是一个bug。当你读取stdin
时,意味着你想要使用一个“文件”,而当你关闭缓冲时,你是在说不需要读取缓冲区。但这并不意味着模拟该“文件”的应用程序不应该使用写入缓冲区。对于Linux,如果你的终端处于“icanon”模式下,它不会发送任何输入,直到发生某些特殊事件(例如按下Enter或Ctrl + D)。可能Windows的控制台也有类似的模式。
getInputLine
变成 getInputChar
"quit"
变成 'q'
++ input
变成 ++ [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
我使用了haskeline包,这是其他答案中提到的,用于组合这个简单的getChar
替代方案。如果getInputChar
返回Nothing
,它会再次请求输入。这对我解决了问题,您可以根据需要进行修改。
import System.Console.Haskeline
( runInputT
, defaultSettings
, getInputChar
)
betterInputChar :: IO Char
betterInputChar = do
mc <- runInputT defaultSettings (getInputChar "")
case mc of
Nothing -> betterInputChar
(Just c) -> return c
main = do hSetBuffering stdin NoBuffering; interact $ map Data.Char.toUpper
有什么关系?在我的情况下,它会在任何输出出现之前等待一个新行。(Ubuntu,GHC 7.6.3。) - ominug