Skip to content

Commit 618542a

Browse files
authored
Merge pull request #55 from csboo/speedy-windows-cursor-query
speedy windows cursor position query
2 parents d73549c + 7f00693 commit 618542a

File tree

2 files changed

+73
-22
lines changed

2 files changed

+73
-22
lines changed

examples/cursor-position-query.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include "../tui.hpp"
2+
#include <cassert>
3+
#include <chrono>
4+
#include <cstdint>
5+
// #include <thread>
6+
7+
// returns how much the queries altogether took in ns
8+
uint64_t get_cursor_pos_n(const unsigned n) {
9+
auto start = std::chrono::high_resolution_clock::now();
10+
for (auto i = 0; i < n; ++i) {
11+
// std::cout << "getting cursor position...\n";
12+
auto cursor_pos = tui::cursor::get_position();
13+
// std::cout << "cursor @ {" << cursor_pos.first << ", " << cursor_pos.second << "}\n";
14+
// assert(cursor_pos == cursor_pos_tty);
15+
// std::this_thread::sleep_for(std::chrono::milliseconds(800));
16+
}
17+
auto end = std::chrono::high_resolution_clock::now();
18+
return std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
19+
}
20+
21+
int main(int argc, char** argv) {
22+
tui::enable_raw_mode();
23+
24+
unsigned n = 8;
25+
if (argc > 1) {
26+
n = std::stoi(argv[1]);
27+
}
28+
29+
auto query_t_sum = get_cursor_pos_n(n);
30+
// std::this_thread::sleep_for(std::chrono::seconds(8));
31+
tui::disable_raw_mode();
32+
std::cout << "getting cursor " << n << " times took: " << query_t_sum / 1000000 << "ms, avg: " << query_t_sum / n <<"ns\n";
33+
return 0;
34+
}

tui.hpp

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
#ifdef _WIN32 // windows
55

6-
#include <wchar.h>
76
#include <windows.h>
87

98
#else // not windows
@@ -20,7 +19,6 @@
2019
#include <cassert>
2120
#include <cstdint>
2221
#include <iostream>
23-
#include <ostream>
2422
#include <sstream>
2523
#include <string>
2624
#include <utility> // for std::pair
@@ -60,7 +58,7 @@ namespace tui {
6058
exit(1); \
6159
} \
6260
DWORD mode; \
63-
if (!GetConsoleMode(hStdin, &mode)) { \
61+
if (GetConsoleMode(hStdin, &mode) == 0) { \
6462
std::cerr << "error getting the console mode\n"; \
6563
exit(1); \
6664
}
@@ -73,7 +71,7 @@ namespace tui {
7371
DWORD newMode = mode;
7472
newMode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
7573

76-
if (!SetConsoleMode(hStdin, newMode)) {
74+
if (SetConsoleMode(hStdin, newMode) == 0) {
7775
std::cerr << "error setting the console to raw mode\n";
7876
exit(1);
7977
}
@@ -102,7 +100,7 @@ namespace tui {
102100

103101
// Restore original mode
104102
mode |= (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
105-
if (!SetConsoleMode(hStdin, mode)) {
103+
if (SetConsoleMode(hStdin, mode) == 0) {
106104
std::cerr << "error restoring the console mode\n";
107105
exit(1);
108106
}
@@ -124,6 +122,27 @@ namespace tui {
124122

125123
#undef win_setup
126124

125+
#ifdef _WIN32
126+
inline CONSOLE_SCREEN_BUFFER_INFO get_console_buf_info() {
127+
HANDLE console = nullptr;
128+
CONSOLE_SCREEN_BUFFER_INFO info;
129+
// create a handle to the console screen
130+
console = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
131+
OPEN_EXISTING, 0, nullptr);
132+
if (console == INVALID_HANDLE_VALUE) {
133+
std::cerr << "couldn't get console handle\n";
134+
exit(1);
135+
}
136+
// calculate the size of the console window
137+
if (GetConsoleScreenBufferInfo(console, &info) == 0) {
138+
std::cerr << "couldn't get console screen buffer info\n";
139+
exit(1);
140+
}
141+
CloseHandle(console);
142+
return info;
143+
}
144+
#endif
145+
127146
namespace cursor {
128147
// template for moving cursor
129148
// moves cursor `n` times to `dir`
@@ -161,8 +180,17 @@ namespace tui {
161180
// tell the terminal to check where the cursor is
162181
csi_fn(query_position, "6n");
163182

183+
#ifdef _WIN32
184+
// returns: (rows;cols)
185+
inline std::pair<unsigned, unsigned> get_position() {
186+
auto info = get_console_buf_info();
187+
auto rows = info.dwCursorPosition.X + 1;
188+
auto cols = info.dwCursorPosition.Y + 1;
189+
return {rows, cols};
190+
}
191+
#else
164192
// returns: (rows;cols)
165-
// WARN: can be quite slow, don't use on eg. every screen update!
193+
// NOTE: can take a while (eg 16ms) on (relatively) slow terminals
166194
inline std::pair<unsigned, unsigned> get_position() {
167195
query_position();
168196
std::flush(std::cout);
@@ -179,6 +207,8 @@ namespace tui {
179207

180208
return {rows, cols};
181209
}
210+
#endif
211+
182212
} // namespace cursor
183213

184214
namespace screen {
@@ -204,22 +234,9 @@ namespace tui {
204234
// returns: (rows;cols)/(y;x)
205235
inline std::pair<unsigned, unsigned> size() {
206236
#ifdef _WIN32
207-
HANDLE console;
208-
CONSOLE_SCREEN_BUFFER_INFO info;
209-
short rows;
210-
short columns;
211-
// create a handle to the console screen
212-
console = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
213-
OPEN_EXISTING, 0, NULL);
214-
if (console == INVALID_HANDLE_VALUE)
215-
return {0, 0};
216-
217-
// calculate the size of the console window
218-
if (GetConsoleScreenBufferInfo(console, &info) == 0)
219-
return {0, 0};
220-
CloseHandle(console);
221-
columns = info.srWindow.Right - info.srWindow.Left + 1;
222-
rows = info.srWindow.Bottom - info.srWindow.Top + 1;
237+
auto info = get_console_buf_info();
238+
int columns = info.srWindow.Right - info.srWindow.Left + 1;
239+
int rows = info.srWindow.Bottom - info.srWindow.Top + 1;
223240

224241
return {rows, columns};
225242
#else

0 commit comments

Comments
 (0)