| // Copyright (c) 2011-2016 Ryan Prichard | |
| // | |
| // Permission is hereby granted, free of charge, to any person obtaining a copy | |
| // of this software and associated documentation files (the "Software"), to | |
| // deal in the Software without restriction, including without limitation the | |
| // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
| // sell copies of the Software, and to permit persons to whom the Software is | |
| // furnished to do so, subject to the following conditions: | |
| // | |
| // The above copyright notice and this permission notice shall be included in | |
| // all copies or substantial portions of the Software. | |
| // | |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
| // IN THE SOFTWARE. | |
| Win32Console::Win32Console() : m_titleWorkBuf(16) | |
| { | |
| // The console window must be non-NULL. It is used for two purposes: | |
| // (1) "Freezing" the console to detect the exact number of lines that | |
| // have scrolled. | |
| // (2) Killing processes attached to the console, by posting a WM_CLOSE | |
| // message to the console window. | |
| m_hwnd = GetConsoleWindow(); | |
| ASSERT(m_hwnd != nullptr); | |
| } | |
| std::wstring Win32Console::title() | |
| { | |
| while (true) { | |
| // Calling GetConsoleTitleW is tricky, because its behavior changed | |
| // from XP->Vista, then again from Win7->Win8. The Vista+Win7 behavior | |
| // is especially broken. | |
| // | |
| // The MSDN documentation documents nSize as the "size of the buffer | |
| // pointed to by the lpConsoleTitle parameter, in characters" and the | |
| // successful return value as "the length of the console window's | |
| // title, in characters." | |
| // | |
| // On XP, the function returns the title length, AFTER truncation | |
| // (excluding the NUL terminator). If the title is blank, the API | |
| // returns 0 and does not NUL-terminate the buffer. To accommodate | |
| // XP, the function must: | |
| // * Terminate the buffer itself. | |
| // * Double the size of the title buffer in a loop. | |
| // | |
| // On Vista and up, the function returns the non-truncated title | |
| // length (excluding the NUL terminator). | |
| // | |
| // On Vista and Windows 7, there is a bug where the buffer size is | |
| // interpreted as a byte count rather than a wchar_t count. To | |
| // work around this, we must pass GetConsoleTitleW a buffer that is | |
| // twice as large as what is actually needed. | |
| // | |
| // See misc/*/Test_GetConsoleTitleW.cc for tests demonstrating Windows' | |
| // behavior. | |
| DWORD count = GetConsoleTitleW(m_titleWorkBuf.data(), | |
| m_titleWorkBuf.size()); | |
| const size_t needed = (count + 1) * sizeof(wchar_t); | |
| if (m_titleWorkBuf.size() < needed) { | |
| m_titleWorkBuf.resize(needed); | |
| continue; | |
| } | |
| m_titleWorkBuf[count] = L'\0'; | |
| return m_titleWorkBuf.data(); | |
| } | |
| } | |
| void Win32Console::setTitle(const std::wstring &title) | |
| { | |
| if (!SetConsoleTitleW(title.c_str())) { | |
| trace("SetConsoleTitleW failed"); | |
| } | |
| } | |
| void Win32Console::setFrozen(bool frozen) { | |
| const int SC_CONSOLE_MARK = 0xFFF2; | |
| const int SC_CONSOLE_SELECT_ALL = 0xFFF5; | |
| if (frozen == m_frozen) { | |
| // Do nothing. | |
| } else if (frozen) { | |
| // Enter selection mode by activating either Mark or SelectAll. | |
| const int command = m_freezeUsesMark ? SC_CONSOLE_MARK | |
| : SC_CONSOLE_SELECT_ALL; | |
| SendMessage(m_hwnd, WM_SYSCOMMAND, command, 0); | |
| m_frozen = true; | |
| } else { | |
| // Send Escape to cancel the selection. | |
| SendMessage(m_hwnd, WM_CHAR, 27, 0x00010001); | |
| m_frozen = false; | |
| } | |
| } | |