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