1

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

如何在 Windows 中复制 Linux 行为?

几点注意事项:

  • Windows,我的意思是我在 wine 下编译和运行
  • 阴谋集团 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 上,这样做是“正确”的事情,即打印了一个蓝色的“@”。在酒下,我看不到任何变化。我希望这只是 wine 的一个特性,而不是 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
4

1 回答 1

3

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

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

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

于 2014-04-01T22:10:51.687 回答