From 5b0b5567f8adb9901f277351599ddf35332e2c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 18:56:58 +0200 Subject: [PATCH 1/4] refactor(win): console buf info will be used more than once --- tui.hpp | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/tui.hpp b/tui.hpp index 8cb432b..f2b2a46 100644 --- a/tui.hpp +++ b/tui.hpp @@ -124,6 +124,27 @@ namespace tui { #undef win_setup +#ifdef _WIN32 + inline CONSOLE_SCREEN_BUFFER_INFO get_console_buf_info() { + HANDLE console = nullptr; + CONSOLE_SCREEN_BUFFER_INFO info; + // create a handle to the console screen + console = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, 0, nullptr); + if (console == INVALID_HANDLE_VALUE) { + std::cerr << "couldn't get console handle\n"; + exit(1); + } + // calculate the size of the console window + if (GetConsoleScreenBufferInfo(console, &info) == 0) { + std::cerr << "couldn't get console screen buffer info\n"; + exit(1); + } + CloseHandle(console); + return info; + } +#endif + namespace cursor { // template for moving cursor // moves cursor `n` times to `dir` @@ -162,7 +183,7 @@ namespace tui { csi_fn(query_position, "6n"); // returns: (rows;cols) - // WARN: can be quite slow, don't use on eg. every screen update! + // NOTE: can take a while (eg 16ms) on (relatively) slow terminals inline std::pair get_position() { query_position(); std::flush(std::cout); @@ -204,20 +225,8 @@ namespace tui { // returns: (rows;cols)/(y;x) inline std::pair size() { #ifdef _WIN32 - HANDLE console; - CONSOLE_SCREEN_BUFFER_INFO info; - short rows; - short columns; - // create a handle to the console screen - console = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_EXISTING, 0, NULL); - if (console == INVALID_HANDLE_VALUE) - return {0, 0}; - - // calculate the size of the console window - if (GetConsoleScreenBufferInfo(console, &info) == 0) - return {0, 0}; - CloseHandle(console); + auto info = get_console_buf_info(); + short rows, columns; columns = info.srWindow.Right - info.srWindow.Left + 1; rows = info.srWindow.Bottom - info.srWindow.Top + 1; From 211347d6ddabcff1bae281e4f077de1c1de88e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 19:35:47 +0200 Subject: [PATCH 2/4] perf(win): cursor position query has a significantly faster alternative in winapi --- tui.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tui.hpp b/tui.hpp index f2b2a46..0ec0c95 100644 --- a/tui.hpp +++ b/tui.hpp @@ -182,6 +182,15 @@ namespace tui { // tell the terminal to check where the cursor is csi_fn(query_position, "6n"); +#ifdef _WIN32 + // returns: (rows;cols) + inline std::pair get_position() { + auto info = get_console_buf_info(); + auto rows = info.dwCursorPosition.X + 1; + auto cols = info.dwCursorPosition.Y + 1; + return {rows, cols}; + } +#else // returns: (rows;cols) // NOTE: can take a while (eg 16ms) on (relatively) slow terminals inline std::pair get_position() { @@ -200,6 +209,8 @@ namespace tui { return {rows, cols}; } +#endif + } // namespace cursor namespace screen { From f737712eb854985337e22f0b3e0583bf7716872e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 19:59:08 +0200 Subject: [PATCH 3/4] refactor(win): clangd suggestions --- tui.hpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tui.hpp b/tui.hpp index 0ec0c95..7904707 100644 --- a/tui.hpp +++ b/tui.hpp @@ -3,7 +3,6 @@ #ifdef _WIN32 // windows -#include #include #else // not windows @@ -20,7 +19,6 @@ #include #include #include -#include #include #include #include // for std::pair @@ -60,7 +58,7 @@ namespace tui { exit(1); \ } \ DWORD mode; \ - if (!GetConsoleMode(hStdin, &mode)) { \ + if (GetConsoleMode(hStdin, &mode) == 0) { \ std::cerr << "error getting the console mode\n"; \ exit(1); \ } @@ -73,7 +71,7 @@ namespace tui { DWORD newMode = mode; newMode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); - if (!SetConsoleMode(hStdin, newMode)) { + if (SetConsoleMode(hStdin, newMode) == 0) { std::cerr << "error setting the console to raw mode\n"; exit(1); } @@ -102,7 +100,7 @@ namespace tui { // Restore original mode mode |= (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); - if (!SetConsoleMode(hStdin, mode)) { + if (SetConsoleMode(hStdin, mode) == 0) { std::cerr << "error restoring the console mode\n"; exit(1); } @@ -237,9 +235,8 @@ namespace tui { inline std::pair size() { #ifdef _WIN32 auto info = get_console_buf_info(); - short rows, columns; - columns = info.srWindow.Right - info.srWindow.Left + 1; - rows = info.srWindow.Bottom - info.srWindow.Top + 1; + int columns = info.srWindow.Right - info.srWindow.Left + 1; + int rows = info.srWindow.Bottom - info.srWindow.Top + 1; return {rows, columns}; #else From 7f0069384bcfed66db9f8af243c0c03e478481d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Tue, 6 May 2025 20:14:22 +0200 Subject: [PATCH 4/4] misc(examples): add cursor position query speed test --- examples/cursor-position-query.cpp | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 examples/cursor-position-query.cpp diff --git a/examples/cursor-position-query.cpp b/examples/cursor-position-query.cpp new file mode 100644 index 0000000..39781bd --- /dev/null +++ b/examples/cursor-position-query.cpp @@ -0,0 +1,34 @@ +#include "../tui.hpp" +#include +#include +#include +// #include + +// returns how much the queries altogether took in ns +uint64_t get_cursor_pos_n(const unsigned n) { + auto start = std::chrono::high_resolution_clock::now(); + for (auto i = 0; i < n; ++i) { + // std::cout << "getting cursor position...\n"; + auto cursor_pos = tui::cursor::get_position(); + // std::cout << "cursor @ {" << cursor_pos.first << ", " << cursor_pos.second << "}\n"; + // assert(cursor_pos == cursor_pos_tty); + // std::this_thread::sleep_for(std::chrono::milliseconds(800)); + } + auto end = std::chrono::high_resolution_clock::now(); + return std::chrono::duration_cast(end - start).count(); +} + +int main(int argc, char** argv) { + tui::enable_raw_mode(); + + unsigned n = 8; + if (argc > 1) { + n = std::stoi(argv[1]); + } + + auto query_t_sum = get_cursor_pos_n(n); + // std::this_thread::sleep_for(std::chrono::seconds(8)); + tui::disable_raw_mode(); + std::cout << "getting cursor " << n << " times took: " << query_t_sum / 1000000 << "ms, avg: " << query_t_sum / n <<"ns\n"; + return 0; +}