Haskell读取原始键盘输入

Mat*_*hid 17 io terminal haskell

我正在Haskell中编写一个终端模式程序.我如何阅读原始按键信息?

特别是,似乎有一些东西在Haskell之上提供行编辑工具.如果我这样做getLine,我似乎能够使用向上箭头来获取前一行,编辑文本,并且只有当我按Enter键时,文本才会对Haskell应用程序本身可见.

我所追求的是能够阅读单个按键,因此我可以自己实现行编辑.


也许我的问题不清楚.基本上我想构建类似Vi或Emacs(或Yi)的东西.我已经知道有终端绑定可以让我进行花哨的控制台模式打印,所以输出端不应该是一个问题.我只是想找到一种获取原始按键输入的方法,所以我可以做一些事情,比如(例如)当用户按下字母K时将K添加到当前文本行,或者当用户将文件保存到磁盘时按Ctrl + S.

Evi*_*ine 10

这可能是最简单的解决方案,类似于其他编程语言中的典型代码:

import System.IO (stdin, hReady)

getKey :: IO [Char]
getKey = reverse <$> getKey' ""
  where getKey' chars = do
          char <- getChar
          more <- hReady stdin
          (if more then getKey' else return) (char:chars)
Run Code Online (Sandbox Code Playgroud)

它的工作原理是"一次"读取多个字符.允许例如?,由三个字符组成的键['\ESC','[','A']与实际\ESC字符输入区分开.

用法示例:

import System.IO (stdin, hSetEcho, hSetBuffering, NoBuffering)
import Control.Monad (when)

-- Simple menu controller
main = do
  hSetBuffering stdin NoBuffering
  hSetEcho stdin False
  key <- getKey
  when (key /= "\ESC") $ do
    case key of
      "\ESC[A" -> putStr "?"
      "\ESC[B" -> putStr "?"
      "\ESC[C" -> putStr "?"
      "\ESC[D" -> putStr "?"
      "\n"     -> putStr "?"
      "\DEL"   -> putStr "?"
      _        -> return ()
    main
Run Code Online (Sandbox Code Playgroud)

这有点hackish,因为理论上,用户可以在程序到达之前输入更多的键hReady.如果终端允许粘贴,可能会发生这种情况.但实际上,对于交互式输入,这不是一个现实的场景.

有趣的事实:光标字符串可以putStr用来实际以编程方式移动光标.


Ste*_*ehl 9

听起来你想要readline支持.有几个软件包可以做到这一点,但haskeline可能是最容易使用最支持的平台.

import Control.Monad.Trans
import System.Console.Haskeline

type Repl a = InputT IO a

process :: String -> IO ()
process = putStrLn

repl :: Repl ()
repl = do
  minput <- getInputLine "> "
  case minput of
    Nothing -> outputStrLn "Goodbye."
    Just input -> (liftIO $ process input) >> repl

main :: IO ()
main = runInputT defaultSettings repl
Run Code Online (Sandbox Code Playgroud)


Mat*_*hid 7

未完成:

经过几个小时的网上冲浪,我可以报告以下内容:

  • readline有一个巨大的界面,几乎没有任何文档.从函数名称和类型签名中你可以猜出这些东西的作用......但它远非微不足道.无论如何,这个库似乎提供了一个高级编辑界面 - 这是我试图自己实现的东西.我需要更低级别的东西.

  • 在浏览源代码之后haskeline,似乎它有一个巨大的纠结低级代码,单独用于Win32和POSIX.如果一个简单的方法做控制台I/O,这个库不能证明它.代码看起来如此紧密集成,并且非常具体haskeline,我怀疑我可以重用它们.但也许通过阅读它我可以学到足够的东西来写自己的东西?

  • 易是......吓坏.Cabal文件列出了> 150个暴露的模块.(!!)但是,它下面显示的是使用名为vtyPOSIX 的软件包.(我想知道Yi如何在Windows上运行?)vty看起来它可能对我没有进一步修改直接有用.(但同样,不在Windows上.)

  • unix有...基本没什么有趣的.它有一堆东西可以在终端上设置东西,但绝对没有什么可以从终端读取.(除了可以检查回声是否打开等等.没有关于按键的信息.)

  • unix-compat 完全没有兴趣.


Pet*_*lák 5

一种选择是使用ncurses。一个简单的例子:

import Control.Monad
import UI.NCurses

main :: IO ()
main = runCurses $ do
    w <- defaultWindow
    forever $ do
        e <- getEvent w Nothing
        updateWindow w $ do
            moveCursor 0 0
            drawString (show e)
        render
Run Code Online (Sandbox Code Playgroud)