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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2983974/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 14:36:21  来源:igfitidea点击:

Haskell: read input character from console immediately, not after newline

windowshaskellioghcbuffering

提问by Steves

I've tried this:

我试过这个:

main = do
    hSetBuffering stdin NoBuffering 
    c <- getChar

but it waits until the enter is pressed, which is not what I want. I want to read the character immediately after user presses it.

但它一直等到按下回车键,这不是我想要的。我想在用户按下后立即读取字符。

I am using ghc v6.12.1 on Windows 7.

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

EDIT: workaround for me was moving from GHC to WinHugs, which supports this correctly.

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

采纳答案by Artelius

Might be a bug:

可能是一个错误:

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

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

The following program repeats inputted characters until the escape key is pressed.

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

Because of the hSetBuffering stdin NoBuffering line it should not be necessary to press the enter key between keystrokes. This program works correctly in WinHugs (sep 2006 version). However, GHC 6.8.2 does not repeat the characters until the enter key is pressed. The problem was reproduced with all GHC executables (ghci, ghc, runghc, runhaskell), using both cmd.exe and command.com on Windows XP Professional...

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

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(2006 年 9 月版本)中正常运行。但是,GHC 6.8.2 在按下回车键之前不会重复字符。在 Windows XP Professional 上使用 cmd.exe 和 command.com 的所有 GHC 可执行文件(ghci、ghc、runghc、runhaskell)都重现了该问题...

回答by AndrewC

Yes, it's a bug. Here's a workaround to save folks clicking and scrolling:

是的,这是一个错误。这是一种避免人们点击和滚动的解决方法:

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

So you can replace calls to getCharwith calls to getHiddenChar.

因此,您可以将调用替换为getChar调用getHiddenChar

Note this is a workaround just for ghc/ghci on Windows. For example, winhugs doesn't have the bug and this code doesn't work in winhugs.

请注意,这是仅适用于 Windows 上的 ghc/ghci 的解决方法。例如,winhugs 没有错误,并且此代码在 winhugs 中不起作用。

回答by ony

Hmm.. Actually I can't see this feature to be a bug. When you read stdinthat means that you want to work with a "file" and when you turn of buffering you are saying that there is no need for read buffer. But that doesn't mean that application which is emulating that "file" should not use write buffer. For linux if your terminal is in "icanon" mode it doesn't send any input until some special event will occur (like Enter pressed or Ctrl+D). Probably console in Windows have some similar modes.

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

回答by romc

The Haskelinepackage worked for me.

Haskeline包对我来说有效。

If you need it for individual characters, then just change the sample slightly.

如果您需要单个字符,则只需稍微更改示例即可。

  1. getInputLinebecomes getInputChar
  2. "quit"becomes 'q'
  3. ++ inputbecomes ++ [input]
  1. getInputLine变成 getInputChar
  2. "quit"变成 'q'
  3. ++ 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