Linux 下 Mono 中的 ReadConsoleOutput、WriteConsoleOutput、ReadConsoleInput 功能

发布于 2024-08-01 12:42:22 字数 515 浏览 4 评论 0原文

我在程序的 .Net 版本中通过 P/Invoke 使用三个本机 WinApi 函数: ReadConsoleOutputWriteConsoleOutput, ReadConsoleInput。 Linux下Mono对应的功能如何实现?

我了解标准 System.Console 类。 但由于某些奇怪的原因,此类不以任何方式支持前面提到的 winapi 函数的功能。

I use in .Net version of my program three native WinApi functions through P/Invoke:
ReadConsoleOutput, WriteConsoleOutput, ReadConsoleInput.
How to implement this functionality in Mono counterpart under Linux?

I know about standart System.Console class. But this class for some strange reason does not support functionality of previously mentioned winapi-functions in any way.

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

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

发布评论

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

评论(2

薄暮涼年 2024-08-08 12:42:22

如果您重写 I/O,以便它跟踪屏幕本身应该显示的内容(现在不应占用太多内存),并且仅使用 Console 类进行更新,你应该发现 Mono 的实现可以跟上。 Mono 还可以通过 Mono.Terminal 命名空间,但坚持使用 Console 将更加可移植。 您仍然可以通过 SetCursorPosition 方法、BackgroundColor 属性等使用它进行定位和颜色。

If you rewrite your I/O so that it keeps track of what ought to be on the screen itself (which shouldn't take up too much memory these days), and only update using the Console class, you should find that Mono's implementation can keep up. Mono also comes with access to ncurses functionality via the Mono.Terminal namespace, but sticking to Console will be more portable. You can still use it for positioning and color, via SetCursorPosition method, BackgroundColor property, etc.

沦落红尘 2024-08-08 12:42:22

对于 ReadConsoleInput 的等效功能,可以使用 libtermkey 库。

ReadConsoleOutput 在 Linux 中是不可能的,但您可以将数据存储在自定义屏幕缓冲区中。 使用 NCurses 可以轻松实现 WriteConsoleOutput。

看看Windows和Posix平台中实现的事件循环。 使用的主要函数有:poll()、pipe()、writeInt64()、readInt64() - 来自标准 libc:

termkeyHandle = LibTermKey.termkey_new( 0, TermKeyFlag.TERMKEY_FLAG_SPACESYMBOL );

// Setup the input mode
Console.Write( "\x1B[?1002h" );
pollfd fd = new pollfd( );
fd.fd = 0;
fd.events = POLL_EVENTS.POLLIN;

pollfd[ ] fds = new pollfd[ 2 ];
fds[ 0 ] = fd;
fds[ 1 ] = new pollfd( );
int pipeResult = Libc.pipe( pipeFds );
if ( pipeResult == -1 ) {
    throw new InvalidOperationException( "Cannot create self-pipe." );
}
fds[ 1 ].fd = pipeFds[ 0 ];
fds[ 1 ].events = POLL_EVENTS.POLLIN;

while ( true ) {
    int pollRes = Libc.poll( fds, 2, -1 );
    if ( pollRes == 0 ) throw new InvalidOperationException( "Assertion failed." );
    if ( pollRes == -1 ) {
        int errorCode = Marshal.GetLastWin32Error();
        if ( errorCode != Libc.EINTR ) {
            throw new InvalidOperationException(string.Format("poll() returned with error code {0}", errorCode));
        }
    }

    bool needProcessInvokeActions = false;
    if ( fds[ 1 ].revents != POLL_EVENTS.NONE ) {
        UInt64 u;
        Libc.readInt64( fds[ 1 ].fd, out u );
        if ( u == 1 ) {
            // Exit from application
            break;
        }
    }

    if ( ( fds[ 0 ].revents & POLL_EVENTS.POLLIN ) == POLL_EVENTS.POLLIN ||
         ( fds[ 0 ].revents & POLL_EVENTS.POLLHUP ) == POLL_EVENTS.POLLHUP ||
         ( fds[ 0 ].revents & POLL_EVENTS.POLLERR ) == POLL_EVENTS.POLLERR ) {
        LibTermKey.termkey_advisereadable( termkeyHandle );
    }

    while ( ( LibTermKey.termkey_getkey( termkeyHandle, ref key ) ) == TermKeyResult.TERMKEY_RES_KEY ) {
        processLinuxInput( key );
    }

    renderer.UpdateRender( );
}

For functionality equivalent for ReadConsoleInput use can use libtermkey library.

ReadConsoleOutput is impossible in Linux, but you can store the data in custom screen buffer. WriteConsoleOutput can be easy implemented using NCurses.

Look at the event loop implemented in Windows and Posix platforms. Main functions used are: poll(), pipe(), writeInt64(), readInt64() - from standard libc:

termkeyHandle = LibTermKey.termkey_new( 0, TermKeyFlag.TERMKEY_FLAG_SPACESYMBOL );

// Setup the input mode
Console.Write( "\x1B[?1002h" );
pollfd fd = new pollfd( );
fd.fd = 0;
fd.events = POLL_EVENTS.POLLIN;

pollfd[ ] fds = new pollfd[ 2 ];
fds[ 0 ] = fd;
fds[ 1 ] = new pollfd( );
int pipeResult = Libc.pipe( pipeFds );
if ( pipeResult == -1 ) {
    throw new InvalidOperationException( "Cannot create self-pipe." );
}
fds[ 1 ].fd = pipeFds[ 0 ];
fds[ 1 ].events = POLL_EVENTS.POLLIN;

while ( true ) {
    int pollRes = Libc.poll( fds, 2, -1 );
    if ( pollRes == 0 ) throw new InvalidOperationException( "Assertion failed." );
    if ( pollRes == -1 ) {
        int errorCode = Marshal.GetLastWin32Error();
        if ( errorCode != Libc.EINTR ) {
            throw new InvalidOperationException(string.Format("poll() returned with error code {0}", errorCode));
        }
    }

    bool needProcessInvokeActions = false;
    if ( fds[ 1 ].revents != POLL_EVENTS.NONE ) {
        UInt64 u;
        Libc.readInt64( fds[ 1 ].fd, out u );
        if ( u == 1 ) {
            // Exit from application
            break;
        }
    }

    if ( ( fds[ 0 ].revents & POLL_EVENTS.POLLIN ) == POLL_EVENTS.POLLIN ||
         ( fds[ 0 ].revents & POLL_EVENTS.POLLHUP ) == POLL_EVENTS.POLLHUP ||
         ( fds[ 0 ].revents & POLL_EVENTS.POLLERR ) == POLL_EVENTS.POLLERR ) {
        LibTermKey.termkey_advisereadable( termkeyHandle );
    }

    while ( ( LibTermKey.termkey_getkey( termkeyHandle, ref key ) ) == TermKeyResult.TERMKEY_RES_KEY ) {
        processLinuxInput( key );
    }

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