| 159 | } |
| 160 | |
| 161 | static char32_t getchar32() { |
| 162 | #if defined(_WIN32) |
| 163 | HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE); |
| 164 | wchar_t high_surrogate = 0; |
| 165 | |
| 166 | while (true) { |
| 167 | INPUT_RECORD record; |
| 168 | DWORD count; |
| 169 | if (!ReadConsoleInputW(hConsole, &record, 1, &count) || count == 0) { |
| 170 | return WEOF; |
| 171 | } |
| 172 | |
| 173 | if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown) { |
| 174 | wchar_t wc = record.Event.KeyEvent.uChar.UnicodeChar; |
| 175 | if (wc == 0) { |
| 176 | continue; |
| 177 | } |
| 178 | |
| 179 | if ((wc >= 0xD800) && (wc <= 0xDBFF)) { // Check if wc is a high surrogate |
| 180 | high_surrogate = wc; |
| 181 | continue; |
| 182 | } |
| 183 | if ((wc >= 0xDC00) && (wc <= 0xDFFF)) { // Check if wc is a low surrogate |
| 184 | if (high_surrogate != 0) { // Check if we have a high surrogate |
| 185 | return ((high_surrogate - 0xD800) << 10) + (wc - 0xDC00) + 0x10000; |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | high_surrogate = 0; // Reset the high surrogate |
| 190 | return static_cast<char32_t>(wc); |
| 191 | } |
| 192 | } |
| 193 | #else |
| 194 | wchar_t wc = getwchar(); |
| 195 | if (static_cast<wint_t>(wc) == WEOF) { |
| 196 | return WEOF; |
| 197 | } |
| 198 | |
| 199 | #if WCHAR_MAX == 0xFFFF |
| 200 | if ((wc >= 0xD800) && (wc <= 0xDBFF)) { // Check if wc is a high surrogate |
| 201 | wchar_t low_surrogate = getwchar(); |
| 202 | if ((low_surrogate >= 0xDC00) && (low_surrogate <= 0xDFFF)) { // Check if the next wchar is a low surrogate |
| 203 | return (static_cast<char32_t>(wc & 0x03FF) << 10) + (low_surrogate & 0x03FF) + 0x10000; |
| 204 | } |
| 205 | } |
| 206 | if ((wc >= 0xD800) && (wc <= 0xDFFF)) { // Invalid surrogate pair |
| 207 | return 0xFFFD; // Return the replacement character U+FFFD |
| 208 | } |
| 209 | #endif |
| 210 | |
| 211 | return static_cast<char32_t>(wc); |
| 212 | #endif |
| 213 | } |
| 214 | |
| 215 | static void pop_cursor() { |
| 216 | #if defined(_WIN32) |