installed pty
[VSoRC/.git] / node_modules / node-pty / deps / winpty / src / agent / Win32ConsoleBuffer.cc
1 // Copyright (c) 2011-2016 Ryan Prichard
2 //
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:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
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
19 // IN THE SOFTWARE.
20
21 #include "Win32ConsoleBuffer.h"
22
23 #include <windows.h>
24
25 #include "../shared/DebugClient.h"
26 #include "../shared/StringBuilder.h"
27 #include "../shared/WinptyAssert.h"
28
29 std::unique_ptr<Win32ConsoleBuffer> Win32ConsoleBuffer::openStdout() {
30     return std::unique_ptr<Win32ConsoleBuffer>(
31         new Win32ConsoleBuffer(GetStdHandle(STD_OUTPUT_HANDLE), false));
32 }
33
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));
42 }
43
44 std::unique_ptr<Win32ConsoleBuffer> Win32ConsoleBuffer::createErrorBuffer() {
45     SECURITY_ATTRIBUTES sa = {};
46     sa.nLength = sizeof(sa);
47     sa.bInheritHandle = TRUE;
48     const HANDLE conout =
49         CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
50                                   FILE_SHARE_READ | FILE_SHARE_WRITE,
51                                   &sa,
52                                   CONSOLE_TEXTMODE_BUFFER,
53                                   nullptr);
54     ASSERT(conout != INVALID_HANDLE_VALUE);
55     return std::unique_ptr<Win32ConsoleBuffer>(
56         new Win32ConsoleBuffer(conout, true));
57 }
58
59 HANDLE Win32ConsoleBuffer::conout() {
60     return m_conout;
61 }
62
63 void Win32ConsoleBuffer::clearLines(
64         int row,
65         int count,
66         const ConsoleScreenBufferInfo &info) {
67     // TODO: error handling
68     const int width = info.bufferSize().X;
69     DWORD actual = 0;
70     if (!FillConsoleOutputCharacterW(
71             m_conout, L' ', width * count, Coord(0, row),
72             &actual) || static_cast<int>(actual) != width * count) {
73         trace("FillConsoleOutputCharacterW failed");
74     }
75     if (!FillConsoleOutputAttribute(
76             m_conout, kDefaultAttributes, width * count, Coord(0, row),
77             &actual) || static_cast<int>(actual) != width * count) {
78         trace("FillConsoleOutputAttribute failed");
79     }
80 }
81
82 void Win32ConsoleBuffer::clearAllLines(const ConsoleScreenBufferInfo &info) {
83     clearLines(0, info.bufferSize().Y, info);
84 }
85
86 ConsoleScreenBufferInfo Win32ConsoleBuffer::bufferInfo() {
87     // TODO: error handling
88     ConsoleScreenBufferInfo info;
89     if (!GetConsoleScreenBufferInfo(m_conout, &info)) {
90         trace("GetConsoleScreenBufferInfo failed");
91     }
92     return info;
93 }
94
95 Coord Win32ConsoleBuffer::bufferSize() {
96     return bufferInfo().bufferSize();
97 }
98
99 SmallRect Win32ConsoleBuffer::windowRect() {
100     return bufferInfo().windowRect();
101 }
102
103 bool Win32ConsoleBuffer::resizeBufferRange(const Coord &initialSize,
104                                            Coord &finalSize) {
105     if (SetConsoleScreenBufferSize(m_conout, initialSize)) {
106         finalSize = initialSize;
107         return true;
108     }
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) {
114         size.X++;
115         if (SetConsoleScreenBufferSize(m_conout, size)) {
116             finalSize = 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);
121             return true;
122         }
123     }
124     trace("SetConsoleScreenBufferSize failed: "
125           "tried (%d,%d) through (%d,%d)",
126           initialSize.X, initialSize.Y,
127           size.X, size.Y);
128     return false;
129 }
130
131 void Win32ConsoleBuffer::resizeBuffer(const Coord &size) {
132     // TODO: error handling
133     if (!SetConsoleScreenBufferSize(m_conout, size)) {
134         trace("SetConsoleScreenBufferSize failed: size=(%d,%d)",
135               size.X, size.Y);
136     }
137 }
138
139 void Win32ConsoleBuffer::moveWindow(const SmallRect &rect) {
140     // TODO: error handling
141     if (!SetConsoleWindowInfo(m_conout, TRUE, &rect)) {
142         trace("SetConsoleWindowInfo failed");
143     }
144 }
145
146 Coord Win32ConsoleBuffer::cursorPosition() {
147     return bufferInfo().dwCursorPosition;
148 }
149
150 void Win32ConsoleBuffer::setCursorPosition(const Coord &coord) {
151     // TODO: error handling
152     if (!SetConsoleCursorPosition(m_conout, coord)) {
153         trace("SetConsoleCursorPosition failed");
154     }
155 }
156
157 void Win32ConsoleBuffer::read(const SmallRect &rect, CHAR_INFO *data) {
158     // TODO: error handling
159     SmallRect tmp(rect);
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 << '}';
166         };
167         sb << "Win32ConsoleBuffer::read: ReadConsoleOutput failed: readRegion=";
168         outStruct(rect);
169         CONSOLE_SCREEN_BUFFER_INFO info = {};
170         if (GetConsoleScreenBufferInfo(m_conout, &info)) {
171             sb << ", dwSize=(" << info.dwSize.X << ',' << info.dwSize.Y
172                << "), srWindow=";
173             outStruct(info.srWindow);
174         } else {
175             sb << ", GetConsoleScreenBufferInfo also failed";
176         }
177         trace("%s", sb.c_str());
178     }
179 }
180
181 void Win32ConsoleBuffer::write(const SmallRect &rect, const CHAR_INFO *data) {
182     // TODO: error handling
183     SmallRect tmp(rect);
184     if (!WriteConsoleOutputW(m_conout, data, rect.size(), Coord(), &tmp)) {
185         trace("WriteConsoleOutput failed");
186     }
187 }
188
189 void Win32ConsoleBuffer::setTextAttribute(WORD attributes) {
190     if (!SetConsoleTextAttribute(m_conout, attributes)) {
191         trace("SetConsoleTextAttribute failed");
192     }
193 }