1 // Copyright (c) 2011-2016 Ryan Prichard
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to
5 // deal in the Software without restriction, including without limitation the
6 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 // sell copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 #include "Win32ConsoleBuffer.h"
25 #include "../shared/DebugClient.h"
26 #include "../shared/StringBuilder.h"
27 #include "../shared/WinptyAssert.h"
29 std::unique_ptr<Win32ConsoleBuffer> Win32ConsoleBuffer::openStdout() {
30 return std::unique_ptr<Win32ConsoleBuffer>(
31 new Win32ConsoleBuffer(GetStdHandle(STD_OUTPUT_HANDLE), false));
34 std::unique_ptr<Win32ConsoleBuffer> Win32ConsoleBuffer::openConout() {
35 const HANDLE conout = CreateFileW(L"CONOUT$",
36 GENERIC_READ | GENERIC_WRITE,
37 FILE_SHARE_READ | FILE_SHARE_WRITE,
38 NULL, OPEN_EXISTING, 0, NULL);
39 ASSERT(conout != INVALID_HANDLE_VALUE);
40 return std::unique_ptr<Win32ConsoleBuffer>(
41 new Win32ConsoleBuffer(conout, true));
44 std::unique_ptr<Win32ConsoleBuffer> Win32ConsoleBuffer::createErrorBuffer() {
45 SECURITY_ATTRIBUTES sa = {};
46 sa.nLength = sizeof(sa);
47 sa.bInheritHandle = TRUE;
49 CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
50 FILE_SHARE_READ | FILE_SHARE_WRITE,
52 CONSOLE_TEXTMODE_BUFFER,
54 ASSERT(conout != INVALID_HANDLE_VALUE);
55 return std::unique_ptr<Win32ConsoleBuffer>(
56 new Win32ConsoleBuffer(conout, true));
59 HANDLE Win32ConsoleBuffer::conout() {
63 void Win32ConsoleBuffer::clearLines(
66 const ConsoleScreenBufferInfo &info) {
67 // TODO: error handling
68 const int width = info.bufferSize().X;
70 if (!FillConsoleOutputCharacterW(
71 m_conout, L' ', width * count, Coord(0, row),
72 &actual) || static_cast<int>(actual) != width * count) {
73 trace("FillConsoleOutputCharacterW failed");
75 if (!FillConsoleOutputAttribute(
76 m_conout, kDefaultAttributes, width * count, Coord(0, row),
77 &actual) || static_cast<int>(actual) != width * count) {
78 trace("FillConsoleOutputAttribute failed");
82 void Win32ConsoleBuffer::clearAllLines(const ConsoleScreenBufferInfo &info) {
83 clearLines(0, info.bufferSize().Y, info);
86 ConsoleScreenBufferInfo Win32ConsoleBuffer::bufferInfo() {
87 // TODO: error handling
88 ConsoleScreenBufferInfo info;
89 if (!GetConsoleScreenBufferInfo(m_conout, &info)) {
90 trace("GetConsoleScreenBufferInfo failed");
95 Coord Win32ConsoleBuffer::bufferSize() {
96 return bufferInfo().bufferSize();
99 SmallRect Win32ConsoleBuffer::windowRect() {
100 return bufferInfo().windowRect();
103 bool Win32ConsoleBuffer::resizeBufferRange(const Coord &initialSize,
105 if (SetConsoleScreenBufferSize(m_conout, initialSize)) {
106 finalSize = initialSize;
109 // The font might be too small to accommodate a very narrow console window.
110 // In that case, rather than simply give up, it's better to try wider
111 // buffer sizes until the call succeeds.
112 Coord size = initialSize;
113 while (size.X < 20) {
115 if (SetConsoleScreenBufferSize(m_conout, size)) {
117 trace("SetConsoleScreenBufferSize: initial size (%d,%d) failed, "
118 "but wider size (%d,%d) succeeded",
119 initialSize.X, initialSize.Y,
120 finalSize.X, finalSize.Y);
124 trace("SetConsoleScreenBufferSize failed: "
125 "tried (%d,%d) through (%d,%d)",
126 initialSize.X, initialSize.Y,
131 void Win32ConsoleBuffer::resizeBuffer(const Coord &size) {
132 // TODO: error handling
133 if (!SetConsoleScreenBufferSize(m_conout, size)) {
134 trace("SetConsoleScreenBufferSize failed: size=(%d,%d)",
139 void Win32ConsoleBuffer::moveWindow(const SmallRect &rect) {
140 // TODO: error handling
141 if (!SetConsoleWindowInfo(m_conout, TRUE, &rect)) {
142 trace("SetConsoleWindowInfo failed");
146 Coord Win32ConsoleBuffer::cursorPosition() {
147 return bufferInfo().dwCursorPosition;
150 void Win32ConsoleBuffer::setCursorPosition(const Coord &coord) {
151 // TODO: error handling
152 if (!SetConsoleCursorPosition(m_conout, coord)) {
153 trace("SetConsoleCursorPosition failed");
157 void Win32ConsoleBuffer::read(const SmallRect &rect, CHAR_INFO *data) {
158 // TODO: error handling
160 if (!ReadConsoleOutputW(m_conout, data, rect.size(), Coord(), &tmp) &&
161 isTracingEnabled()) {
162 StringBuilder sb(256);
163 auto outStruct = [&](const SMALL_RECT &sr) {
164 sb << "{L=" << sr.Left << ",T=" << sr.Top
165 << ",R=" << sr.Right << ",B=" << sr.Bottom << '}';
167 sb << "Win32ConsoleBuffer::read: ReadConsoleOutput failed: readRegion=";
169 CONSOLE_SCREEN_BUFFER_INFO info = {};
170 if (GetConsoleScreenBufferInfo(m_conout, &info)) {
171 sb << ", dwSize=(" << info.dwSize.X << ',' << info.dwSize.Y
173 outStruct(info.srWindow);
175 sb << ", GetConsoleScreenBufferInfo also failed";
177 trace("%s", sb.c_str());
181 void Win32ConsoleBuffer::write(const SmallRect &rect, const CHAR_INFO *data) {
182 // TODO: error handling
184 if (!WriteConsoleOutputW(m_conout, data, rect.size(), Coord(), &tmp)) {
185 trace("WriteConsoleOutput failed");
189 void Win32ConsoleBuffer::setTextAttribute(WORD attributes) {
190 if (!SetConsoleTextAttribute(m_conout, attributes)) {
191 trace("SetConsoleTextAttribute failed");