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

发布于 2024-09-04 01:47:05 字数 242 浏览 8 评论 0原文

我已经尝试过这个:

main = do
    hSetBuffering stdin NoBuffering 
    c <- getChar

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

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

编辑:我的解决方法是从 GHC 迁移到 WinHugs,它可以正确支持此功能。

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

牵强ㄟ 2024-09-11 01:47:05

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

{-# 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 中不起作用。

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 getChar with calls to 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.

望她远 2024-09-11 01:47:05

可能是一个错误:

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

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

导入IO
导入单子
导入字符

主要::IO()
main = do hSetBuffering stdin NoBuffering
          输入循环

输入循环::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)都重现了该问题...

Might be a bug:

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...

风透绣罗衣 2024-09-11 01:47:05

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

Hmm.. Actually I can't see this feature to be a bug. When you read stdin that 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.

面犯桃花 2024-09-11 01:47:05

Haskeline 包为我工作。

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

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

The Haskeline package worked for me.

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

  1. getInputLine becomes getInputChar
  2. "quit" becomes 'q'
  3. ++ input becomes ++ [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
奢欲 2024-09-11 01:47:05

我使用了 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

I used the haskeline package, suggested in other answers, to put together this simple alternative to getChar. It requests input again in the case that getInputChar returns Nothing. This worked for me to get past the issue; modify as needed.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文