Подтвердить что ты не робот

Haskell: немедленно прочитать входной символ с консоли, а не после новой строки

Я пробовал это:

main = do
    hSetBuffering stdin NoBuffering 
    c <- getChar

но он ждет, пока не будет нажата кнопка ввода, чего я не хочу. Я хочу прочитать символ сразу после нажатия на него пользователя.

Я использую ghc v6.12.1 в Windows 7.

EDIT: обходной путь для меня переместился с GHC на WinHugs, который поддерживает это правильно.

4b9b3361

Ответ 1

Может быть ошибка:

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 нет необходимости нажимать клавишу ввода между нажатиями клавиш. Эта программа работает правильно в WinHugs (версия sep 2006). Однако GHC 6.8.2 не повторяет символы до тех пор, пока не будет нажата клавиша ввода. Проблема была воспроизведена со всеми исполняемыми файлами GHC (ghci, ghc, runghc, runhaskell), используя как cmd.exe, так и command.com в Windows XP Professional...

Ответ 2

Да, это ошибка. Здесь обходной путь для сохранения щелчков и прокрутки людей:

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

Обратите внимание, что это обходное решение для ghc/ghci в Windows. Например, winhugs не имеет ошибки, и этот код не работает в winhugs.

Ответ 3

Хм.. Собственно, я не вижу, чтобы эта функция была ошибкой. Когда вы читаете stdin, это означает, что вы хотите работать с "файлом", и когда вы включаете буферизацию, вы говорите, что нет необходимости в буфере чтения. Но это не означает, что приложение, которое эмулирует этот "файл", не должно использовать буфер записи. Для linux, если ваш терминал находится в режиме "icanon", он не посылает никакого ввода до тех пор, пока не произойдет какое-либо специальное событие (например, Enter нажатие или Ctrl + D). Вероятно, консоль в Windows имеет несколько подобных режимов.

Ответ 4

Пакет Haskeline работал у меня.

Если вам это нужно для отдельных символов, просто слегка измените образец.

  • 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