ansi-terminal:Windows上的意外行为

时间:2014-04-01 21:38:44

标签: linux windows haskell ansi-escape

我正在Haskell中试验ansi-terminal,而且与Linux相比,似乎在Windows上的行为有问题。在Linux上,我得到一个蓝色的“@”,我可以使用wasd键(如预期的那样)移动,并可以通过按任何其他键退出。在Windows上,我只得到一个不会移动的白色“@”,并且根本无法移动角色。

如何在Windows中复制Linux行为?

一些注意事项:

  • 通过Windows,我的意思是我编译并在葡萄酒下运行
  • cabal 1.18.0.3
  • ghc 7.6.3
  • 通过'wine cabal install'安装ansi-terminal
  • 我宁愿不必使用ncurses(hscurses),如果可能的话

更新:最小的失败代码是:

import System.Console.ANSI

main :: IO ()
main = do
    clearScreen
    setCursorPosition 0 0
    setSGR [SetColor Foreground Vivid Blue]
    putStrLn "@"
    setSGR [Reset] 

在Linux上,这是“正确”的事情,因为打印了一个蓝色的“@”。在葡萄酒下,我看不到变化。我希望这只是葡萄酒而不是Windows的特点,因为我无法访问Windows盒子来试试这个。

我尝试的(原始)代码:

module Main where

import Data.Monoid 
import Control.Monad (unless)
import System.Console.ANSI
import System.IO

-- | thin wrapper around ansi-terminal's API ------------------------------
reset :: IO ()
reset = hSetSGR stdout [Reset]

bold :: [SGR]
bold = [SetConsoleIntensity BoldIntensity]

normal :: [SGR]
normal = [SetConsoleIntensity NormalIntensity]

background :: ColorIntensity -> Color -> [SGR]
background i c = [SetColor Background i c]

foreground :: ColorIntensity -> Color -> [SGR]
foreground i c = [SetColor Foreground i c]

swap :: [SGR]
swap = [SetSwapForegroundBackground True]

underline :: [SGR]
underline = [SetUnderlining SingleUnderline]

noUnderline :: [SGR]
noUnderline = [SetUnderlining NoUnderline]


-- Main -------------------------------------------------------------------
initTerminal :: IO ()
initTerminal = do
    hSetEcho stdin False
    mapM_ (`hSetBuffering` NoBuffering) [stdin, stdout]
    hideCursor
    hSetTitle stdout "Functional Wizardry: The Roguelike"

run :: Int -> Int -> IO ()
run x y = do
    hClearScreen stdout
    hSetCursorPosition stdout x y
    setSGR $ bold <> foreground Vivid Blue
    putStr "@"
    (x', y') <- getInput

    unless ((x', y') == (-1, -1)) $ run (x + x') (y + y')


getInput :: IO (Int, Int)
getInput = do
    char <- getChar
    case char of
        'a' -> return (0, -1)
        'd' -> return (0, 1)
        'w' -> return (1, 0)
        's' -> return (-1, 0)
        _ -> do
            hClearScreen stdout
            hSetCursorPosition stdout 0 0
            return (-1, -1)


main :: IO ()
main = do
    initTerminal
    run 0 0
    reset

1 个答案:

答案 0 :(得分:3)

您的Windows控制台是否支持ANSI? ANSI终端中的字符颜色和光标定位是通过流式传输特定的ESC序列(返回到VT-100 DEC终端,有些可能会进一步返回)完成的。这需要将控制台暴露为流设备。我最后一次尝试使用xterm支持的ANSI代码时,它没有在Windows上工作,我不得不编写一个本机库来公开对Windows控制台API的访问。这是因为我可以找到的API将Windows控制台暴露为不透明的API而没有流式传输行为。

警告:我在Java中尝试过,但除非Haskell ansi-terminal库执行某些特定于平台的魔法而不是普通的ANSI ESC序列,否则它将以相同的方式失败。

从一开始就尝试run 20 20 - 你得到@ 20,20,还是0,0?如果它仍然是0,0,那么它必须是Windows控制台支持ANSI的问题。我不知道是否可以将其配置为支持ANSI。