From 3d3399a7dbe65714a7a45590d1e9bdc1c3908f48 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 20 Oct 2026 21:20:52 +0000 Subject: [PATCH] Declare `Terminal::read_unicode_character` on Windows too `bracketed_paste` calls it as a member of `Terminal` since the merge of https://github.com/ClickHouse/replxx/pull/49, but it was declared and defined only outside `_WIN32`, so `replxx_impl.cxx` no longer compiled for Windows. On Windows it reads one code point from the console with `ReadConsoleW`, combining a surrogate pair. Co-Authored-By: Claude Opus 5.5 --- src/terminal.cxx | 28 ++++++++++++++++++++++++++++ src/terminal.hxx | 5 +++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/terminal.cxx b/src/terminal.cxx index f13d96f..1b4072f 100644 --- a/src/terminal.cxx +++ b/src/terminal.cxx @@ -363,6 +363,34 @@ char32_t Terminal::read_unicode_character( int escDelay_ ) { } } +#else // #ifndef _WIN32 + +/** + * Read a character from the Windows console and return the Unicode (char32_t) + * character it encodes. `ReadConsoleW` hands over UTF-16, from which a surrogate + * pair is one code point. + * + * @return char32_t Unicode character, or zero if the console cannot be read + */ +char32_t Terminal::read_unicode_character( int ) { + wchar_t units[2] = {}; + DWORD read( 0 ); + + if ( !ReadConsoleW( _consoleIn, &units[0], 1, &read, nullptr ) || ( read != 1 ) ) { + return 0; + } + + /* A high surrogate is only half of a code point; the low half follows it. */ + if ( ( units[0] >= 0xD800 ) && ( units[0] <= 0xDBFF ) ) { + if ( !ReadConsoleW( _consoleIn, &units[1], 1, &read, nullptr ) || ( read != 1 ) ) { + return 0; + } + return static_cast( 0x10000 + ( ( units[0] - 0xD800 ) << 10 ) + ( units[1] - 0xDC00 ) ); + } + + return static_cast( units[0] ); +} + #endif // #ifndef _WIN32 void beep(int fd_) { diff --git a/src/terminal.hxx b/src/terminal.hxx index e00ca07..60735f4 100644 --- a/src/terminal.hxx +++ b/src/terminal.hxx @@ -78,9 +78,10 @@ public: void jump_cursor( int, int ); void set_cursor_visible( bool ); void set_escdelay(int delay); -#ifndef _WIN32 - /* A positive delay limits the wait, zero waits indefinitely, a negative one does not wait. */ + /* A positive delay limits the wait, zero waits indefinitely, a negative one does not wait. + * On Windows the delay is ignored and the call blocks until the console delivers a character. */ char32_t read_unicode_character( int escDelay_ = 0 ); +#ifndef _WIN32 int read_verbatim( char32_t*, int ); int install_window_change_handler( void ); #endif