Skip to content

Commit f565c40

Browse files
committed
Fix console input if stdin is redirected to a pipe on Windows
1 parent 38fdbb5 commit f565c40

File tree

2 files changed

+63
-31
lines changed

2 files changed

+63
-31
lines changed

Server/core/CServerImpl.cpp

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <signal.h>
2525
#ifdef WIN32
2626
#include <Mmsystem.h>
27+
#include <io.h>
2728
#else
2829
#include <termios.h>
2930
#include <unistd.h>
@@ -160,6 +161,16 @@ void CServerImpl::Daemonize () const
160161
close ( 2 );
161162
assert ( open ( "/dev/null", O_WRONLY ) == 2 );
162163
}
164+
165+
#endif
166+
167+
#ifdef WIN32
168+
bool CServerImpl::HasConsole()
169+
{
170+
// Getting it a single time is sufficient
171+
static bool isTTY = _isatty(_fileno(stdin));
172+
return isTTY;
173+
}
163174
#endif
164175

165176

@@ -196,36 +207,47 @@ int CServerImpl::Run ( int iArgumentCount, char* szArguments [] )
196207
std::setlocale(LC_ALL,"C");
197208
assert ( strcoll( "a", "B" ) > 0 );
198209

199-
// Disable QuickEdit mode to prevent text selection causing server freeze
200-
HANDLE hConIn = GetStdHandle( STD_INPUT_HANDLE );
201-
DWORD dwConInMode;
202-
GetConsoleMode( hConIn, &dwConInMode );
203-
SetConsoleMode( hConIn, dwConInMode & ~ENABLE_QUICK_EDIT_MODE );
210+
// Get the console handles
211+
m_hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
212+
m_hConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
204213

205-
// Get the console handle
206-
m_hConsole = GetStdHandle ( STD_OUTPUT_HANDLE );
214+
// If stdout is piped GetConsoleScreenBufferInfo will fail
215+
// ==> check if stdin is piped
216+
if (HasConsole())
217+
{
218+
// Disable QuickEdit mode to prevent text selection causing server freeze
219+
DWORD dwConInMode;
220+
GetConsoleMode(m_hConsoleInput, &dwConInMode);
221+
SetConsoleMode(m_hConsoleInput, dwConInMode & ~ENABLE_QUICK_EDIT_MODE);
207222

208-
// Enable the default grey color with a black background
209-
SetConsoleTextAttribute ( m_hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE );
223+
// Enable the default grey color with a black background
224+
SetConsoleTextAttribute(m_hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
210225

211-
// Get the console's width
212-
CONSOLE_SCREEN_BUFFER_INFO ScrnBufferInfo;
213-
if ( !GetConsoleScreenBufferInfo( m_hConsole, &ScrnBufferInfo ) )
214-
{
215-
Print ( "ERROR: GetConsoleScreenBufferInfo failed (%08x)\n", GetLastError() );
216-
Print ( "Press Q to shut down the server!\n" );
217-
WaitForKey ( 'q' );
218-
DestroyWindow ( );
219-
return ERROR_OTHER;
220-
}
226+
// Get the console's width
227+
CONSOLE_SCREEN_BUFFER_INFO ScrnBufferInfo;
228+
if (!GetConsoleScreenBufferInfo(m_hConsole, &ScrnBufferInfo))
229+
{
230+
Print("ERROR: GetConsoleScreenBufferInfo failed (%08x)\n", GetLastError());
231+
Print("Press Q to shut down the server!\n");
232+
WaitForKey('q');
233+
DestroyWindow();
234+
return ERROR_OTHER;
235+
}
221236

222-
// Adjust the console's screenbuffer so we can disable a bar at the top
223-
if ( !g_bNoTopBar )
224-
ScrnBufferInfo.dwSize.Y = ScrnBufferInfo.srWindow.Bottom + 1;
237+
// Adjust the console's screenbuffer so we can disable a bar at the top
238+
if (!g_bNoTopBar)
239+
ScrnBufferInfo.dwSize.Y = ScrnBufferInfo.srWindow.Bottom + 1;
225240

226-
SetConsoleWindowInfo ( m_hConsole, TRUE, &ScrnBufferInfo.srWindow );
227-
SetConsoleScreenBufferSize( m_hConsole, ScrnBufferInfo.dwSize );
228-
SetConsoleOutputCP(CP_UTF8);
241+
SetConsoleWindowInfo(m_hConsole, TRUE, &ScrnBufferInfo.srWindow);
242+
SetConsoleScreenBufferSize(m_hConsole, ScrnBufferInfo.dwSize);
243+
SetConsoleOutputCP(CP_UTF8);
244+
}
245+
else if (GetFileType(m_hConsoleInput) == FILE_TYPE_PIPE)
246+
{
247+
// Enable non-blocking read mode
248+
DWORD pipeState = PIPE_NOWAIT;
249+
SetNamedPipeHandleState(GetStdHandle(STD_INPUT_HANDLE), &pipeState, nullptr, nullptr);
250+
}
229251
#else
230252
// support user locales
231253
std::setlocale(LC_ALL, "");
@@ -673,7 +695,16 @@ void CServerImpl::HandleInput ( void )
673695

674696
// Get the STDIN input
675697
#ifdef WIN32
676-
if ( kbhit () )
698+
if (!HasConsole())
699+
{
700+
// Read from pipe instead of tty
701+
// however, the encoding is dependent on the writer
702+
// so just accept ASCII here by convention
703+
DWORD read;
704+
if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE), &iStdIn, 1, &read, nullptr) || read == 0)
705+
iStdIn = 0;
706+
}
707+
else if ( kbhit () )
677708
{
678709
iStdIn = _getwch();
679710
}
@@ -766,7 +797,7 @@ void CServerImpl::HandleInput ( void )
766797
#ifdef WIN32 // WIN32: we have to use a prefix code, this routine opens an extra switch
767798
case KEY_EXTENDED:
768799
// Color the text
769-
if ( !g_bSilent )
800+
if (!g_bSilent && HasConsole())
770801
SetConsoleTextAttribute ( m_hConsole, FOREGROUND_GREEN | FOREGROUND_RED );
771802

772803
iStdIn = _getwch();
@@ -830,7 +861,7 @@ void CServerImpl::HandleInput ( void )
830861
#ifdef WIN32 // WIN32: Close the switch again
831862
}
832863
// Restore the color
833-
if ( !g_bSilent )
864+
if (!g_bSilent && HasConsole())
834865
SetConsoleTextAttribute ( m_hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE );
835866

836867
break; // KEY_EXTENDED
@@ -845,7 +876,7 @@ void CServerImpl::HandleInput ( void )
845876

846877
#ifdef WIN32
847878
// Color the text
848-
if ( !g_bSilent )
879+
if (!g_bSilent && HasConsole())
849880
SetConsoleTextAttribute ( m_hConsole, FOREGROUND_GREEN | FOREGROUND_RED );
850881

851882
// Echo the input
@@ -861,7 +892,7 @@ void CServerImpl::HandleInput ( void )
861892

862893
#ifdef WIN32
863894
// Restore the color
864-
if ( !g_bSilent )
895+
if (!g_bSilent && HasConsole())
865896
SetConsoleTextAttribute ( m_hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE );
866897
#endif
867898
break;

Server/core/CServerImpl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class CServerImpl : public CServerInterface
6868
#ifndef WIN32
6969
void Daemonize () const;
7070
#else
71-
bool HasConsole ( void ) { return m_hConsole != NULL; }
71+
bool HasConsole ();
7272
#endif
7373

7474
private:
@@ -109,6 +109,7 @@ class CServerImpl : public CServerInterface
109109

110110
#ifdef WIN32
111111
HANDLE m_hConsole;
112+
HANDLE m_hConsoleInput;
112113
CHAR_INFO m_ScrnBuffer[256];
113114

114115
CThreadCommandQueue* m_pThreadCommandQueue;

0 commit comments

Comments
 (0)