Reputation: 3160
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
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
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