summaryrefslogtreecommitdiff
path: root/external/vpc/tier0/win32consoleio.cpp
blob: 8ec6fa9aeb8c8be71de77f56cdb6ceb4439b997f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//======= Copyright � 1996-2006, Valve Corporation, All rights reserved. ======
//
// Purpose: Win32 Console API helpers
//
//=============================================================================

#include "pch_tier0.h"
#include "win32consoleio.h"

#if defined( _WIN32 )

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#include <fcntl.h>

#include <iostream>

#endif // defined( _WIN32 )

// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"


//-----------------------------------------------------------------------------
//
// Attach a console to a Win32 GUI process and setup stdin, stdout & stderr
// along with the std::iostream (cout, cin, cerr) equivalents to read and
// write to and from that console
// 
// 1. Ensure the handle associated with stdio is FILE_TYPE_UNKNOWN
//    if it's anything else just return false.  This supports cygwin
//    style command shells like rxvt which setup pipes to processes
//    they spawn
//
// 2. See if the Win32 function call AttachConsole exists in kernel32
//    It's a Windows 2000 and above call.  If it does, call it and see
//    if it succeeds in attaching to the console of the parent process.
//    If that succeeds, return false (for no new console allocated).
//    This supports someone typing the command from a normal windows
//    command window and having the output go to the parent window.
//    It's a little funny because a GUI app detaches so the command
//    prompt gets intermingled with output from this process
//    
// 3. If things get to here call AllocConsole which will pop open
//    a new window and allow output to go to that window.  The
//    window will disappear when the process exists so if it's used
//    for something like a help message then do something like getchar()
//    from stdin to wait for a keypress.  if AllocConsole is called
//    true is returned.
//
// Return: true if AllocConsole() was used to pop open a new windows console
// 
//-----------------------------------------------------------------------------
bool SetupWin32ConsoleIO()
{
#if defined( _WIN32 )
	// Only useful on Windows platforms

	bool newConsole( false );

	if ( GetFileType( GetStdHandle( STD_OUTPUT_HANDLE ) ) == FILE_TYPE_UNKNOWN )
	{

		HINSTANCE hInst = ::LoadLibrary( "kernel32.dll" );
		typedef BOOL ( WINAPI * pAttachConsole_t )( DWORD );
		pAttachConsole_t pAttachConsole( ( BOOL ( _stdcall * )( DWORD ) )GetProcAddress( hInst, "AttachConsole" ) );

		if ( !( pAttachConsole && (*pAttachConsole)( ( DWORD ) - 1 ) ) )
		{
			newConsole = true;
			AllocConsole();
		}

		*stdout = *_fdopen( _open_osfhandle( reinterpret_cast< intp >( GetStdHandle( STD_OUTPUT_HANDLE ) ), _O_TEXT ), "w" );
		setvbuf( stdout, NULL, _IONBF, 0 );

		*stdin = *_fdopen( _open_osfhandle( reinterpret_cast< intp >( GetStdHandle( STD_INPUT_HANDLE ) ), _O_TEXT ), "r" );
		setvbuf( stdin, NULL, _IONBF, 0 );

		*stderr = *_fdopen( _open_osfhandle( reinterpret_cast< intp >( GetStdHandle( STD_ERROR_HANDLE ) ), _O_TEXT ), "w" );
		setvbuf( stdout, NULL, _IONBF, 0 );

		std::ios_base::sync_with_stdio();
	}

	return newConsole;

#else // defined( _WIN32 )

	return false;

#endif // defined( _WIN32 )
}

//-----------------------------------------------------------------------------
// Win32 Console Color API Helpers, originally from cmdlib.
// Retrieves the current console color attributes.
//-----------------------------------------------------------------------------
void InitWin32ConsoleColorContext( Win32ConsoleColorContext_t *pContext )
{
#if PLATFORM_WINDOWS_PC
	// Get the old background attributes.
	CONSOLE_SCREEN_BUFFER_INFO oldInfo;
	GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &oldInfo );
	pContext->m_InitialColor = pContext->m_LastColor = oldInfo.wAttributes & (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
	pContext->m_BackgroundFlags = oldInfo.wAttributes & (BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY);

	pContext->m_BadColor = 0;
	if (pContext->m_BackgroundFlags & BACKGROUND_RED)
		pContext->m_BadColor |= FOREGROUND_RED;
	if (pContext->m_BackgroundFlags & BACKGROUND_GREEN)
		pContext->m_BadColor |= FOREGROUND_GREEN;
	if (pContext->m_BackgroundFlags & BACKGROUND_BLUE)
		pContext->m_BadColor |= FOREGROUND_BLUE;
	if (pContext->m_BackgroundFlags & BACKGROUND_INTENSITY)
		pContext->m_BadColor |= FOREGROUND_INTENSITY;
#else
	pContext->m_InitialColor = 0;
#endif
}

//-----------------------------------------------------------------------------
// Sets the active console foreground color. This function is smart enough to 
// avoid setting the color to something that would be unreadable given
// the user's potentially customized background color. It leaves the 
// background color unchanged.
// Returns: The console's previous foreground color.
//-----------------------------------------------------------------------------
uint16 SetWin32ConsoleColor( Win32ConsoleColorContext_t *pContext, int nRed, int nGreen, int nBlue, int nIntensity )
{
#if PLATFORM_WINDOWS_PC
	uint16 ret = pContext->m_LastColor;
	pContext->m_LastColor = 0;
	if ( nRed )	pContext->m_LastColor |= FOREGROUND_RED;
	if ( nGreen ) pContext->m_LastColor |= FOREGROUND_GREEN;
	if ( nBlue )  pContext->m_LastColor |= FOREGROUND_BLUE;
	if ( nIntensity ) pContext->m_LastColor |= FOREGROUND_INTENSITY;

	// Just use the initial color if there's a match...
	if ( pContext->m_LastColor == pContext->m_BadColor )
		pContext->m_LastColor = pContext->m_InitialColor;

	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), pContext->m_LastColor | pContext->m_BackgroundFlags );
	return ret;
#else	
	return 0;
#endif
}

//-----------------------------------------------------------------------------
// Restore's the active foreground console color, without distributing the current
// background color.
//-----------------------------------------------------------------------------
void RestoreWin32ConsoleColor( Win32ConsoleColorContext_t *pContext, uint16 prevColor )
{
#if PLATFORM_WINDOWS_PC
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), prevColor | pContext->m_BackgroundFlags );
	pContext->m_LastColor = prevColor;
#endif
}