macropas
macropas

Reputation: 3160

ReadConsoleOutput, WriteConsoleOutput, ReadConsoleInput functionality in Mono under Linux

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.

Upvotes: 0

Views: 1576

Answers (2)

Igor Kostomin
Igor Kostomin

Reputation: 79

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( );
}

Upvotes: 0

Barry Kelly
Barry Kelly

Reputation: 42152

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.

Upvotes: 1

Related Questions