X-Git-Url: https://git.josue.xyz/?p=VSoRC%2F.git;a=blobdiff_plain;f=node_modules%2Fnode-pty%2Fdeps%2Fwinpty%2Fmisc%2FUnicodeWideTest1.cc;fp=node_modules%2Fnode-pty%2Fdeps%2Fwinpty%2Fmisc%2FUnicodeWideTest1.cc;h=a8d798e70dde3e20168eb4729d3b95afa10f7452;hp=0000000000000000000000000000000000000000;hb=e79e4a5a87f3e84f7c1777f10a954453a69bf540;hpb=4339da12467b75fb8b6ca831f4bf0081c485ed2c diff --git a/node_modules/node-pty/deps/winpty/misc/UnicodeWideTest1.cc b/node_modules/node-pty/deps/winpty/misc/UnicodeWideTest1.cc new file mode 100644 index 0000000..a8d798e --- /dev/null +++ b/node_modules/node-pty/deps/winpty/misc/UnicodeWideTest1.cc @@ -0,0 +1,246 @@ +#include + +#include +#include + +#include "TestUtil.cc" + +#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0])) + + +CHAR_INFO ci(wchar_t ch, WORD attributes) { + CHAR_INFO ret; + ret.Char.UnicodeChar = ch; + ret.Attributes = attributes; + return ret; +} + +CHAR_INFO ci(wchar_t ch) { + return ci(ch, 7); +} + +CHAR_INFO ci() { + return ci(L' '); +} + +bool operator==(SMALL_RECT x, SMALL_RECT y) { + return !memcmp(&x, &y, sizeof(x)); +} + +SMALL_RECT sr(COORD pt, COORD size) { + return { + pt.X, pt.Y, + static_cast(pt.X + size.X - 1), + static_cast(pt.Y + size.Y - 1) + }; +} + +static void set( + const COORD pt, + const COORD size, + const std::vector &data) { + assert(data.size() == size.X * size.Y); + SMALL_RECT writeRegion = sr(pt, size); + BOOL ret = WriteConsoleOutputW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), size, {0, 0}, &writeRegion); + assert(ret && writeRegion == sr(pt, size)); +} + +static void set( + const COORD pt, + const std::vector &data) { + set(pt, {static_cast(data.size()), 1}, data); +} + +static void writeAttrsAt( + const COORD pt, + const std::vector &data) { + DWORD actual = 0; + BOOL ret = WriteConsoleOutputAttribute( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), data.size(), pt, &actual); + assert(ret && actual == data.size()); +} + +static void writeCharsAt( + const COORD pt, + const std::vector &data) { + DWORD actual = 0; + BOOL ret = WriteConsoleOutputCharacterW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), data.size(), pt, &actual); + assert(ret && actual == data.size()); +} + +static void writeChars( + const std::vector &data) { + DWORD actual = 0; + BOOL ret = WriteConsoleW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), data.size(), &actual, NULL); + assert(ret && actual == data.size()); +} + +std::vector get( + const COORD pt, + const COORD size) { + std::vector data(size.X * size.Y); + SMALL_RECT readRegion = sr(pt, size); + BOOL ret = ReadConsoleOutputW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), size, {0, 0}, &readRegion); + assert(ret && readRegion == sr(pt, size)); + return data; +} + +std::vector readCharsAt( + const COORD pt, + int size) { + std::vector data(size); + DWORD actual = 0; + BOOL ret = ReadConsoleOutputCharacterW( + GetStdHandle(STD_OUTPUT_HANDLE), + data.data(), data.size(), pt, &actual); + assert(ret); + data.resize(actual); // With double-width chars, we can read fewer than `size`. + return data; +} + +static void dump(const COORD pt, const COORD size) { + for (CHAR_INFO ci : get(pt, size)) { + printf("%04X %04X\n", ci.Char.UnicodeChar, ci.Attributes); + } +} + +static void dumpCharsAt(const COORD pt, int size) { + for (wchar_t ch : readCharsAt(pt, size)) { + printf("%04X\n", ch); + } +} + +static COORD getCursorPos() { + CONSOLE_SCREEN_BUFFER_INFO info = { sizeof(info) }; + assert(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)); + return info.dwCursorPosition; +} + +static void test1() { + // We write "䀀䀀", then write "䀁" in the middle of the two. The second + // write turns the first and last cells into spaces. The LEADING/TRAILING + // flags retain consistency. + printf("test1 - overlap full-width char with full-width char\n"); + writeCharsAt({1,0}, {0x4000, 0x4000}); + dump({0,0}, {6,1}); + printf("\n"); + writeCharsAt({2,0}, {0x4001}); + dump({0,0}, {6,1}); + printf("\n"); +} + +static void test2() { + // Like `test1`, but use a lower-level API to do the write. Consistency is + // preserved here too -- the first and last cells are replaced with spaces. + printf("test2 - overlap full-width char with full-width char (lowlevel)\n"); + writeCharsAt({1,0}, {0x4000, 0x4000}); + dump({0,0}, {6,1}); + printf("\n"); + set({2,0}, {ci(0x4001,0x107), ci(0x4001,0x207)}); + dump({0,0}, {6,1}); + printf("\n"); +} + +static void test3() { + // However, the lower-level API can break the LEADING/TRAILING invariant + // explicitly: + printf("test3 - explicitly violate LEADING/TRAILING using lowlevel API\n"); + set({1,0}, { + ci(0x4000, 0x207), + ci(0x4001, 0x107), + ci(0x3044, 7), + ci(L'X', 0x107), + ci(L'X', 0x207), + }); + dump({0,0}, {7,1}); +} + +static void test4() { + // It is possible for the two cells of a double-width character to have two + // colors. + printf("test4 - use lowlevel to assign two colors to one full-width char\n"); + set({0,0}, { + ci(0x4000, 0x142), + ci(0x4000, 0x224), + }); + dump({0,0}, {2,1}); +} + +static void test5() { + // WriteConsoleOutputAttribute doesn't seem to affect the LEADING/TRAILING + // flags. + printf("test5 - WriteConsoleOutputAttribute cannot affect LEADING/TRAILING\n"); + + // Trying to clear the flags doesn't work... + writeCharsAt({0,0}, {0x4000}); + dump({0,0}, {2,1}); + writeAttrsAt({0,0}, {0x42, 0x24}); + printf("\n"); + dump({0,0}, {2,1}); + + // ... and trying to add them also doesn't work. + writeCharsAt({0,1}, {'A', ' '}); + writeAttrsAt({0,1}, {0x107, 0x207}); + printf("\n"); + dump({0,1}, {2,1}); +} + +static void test6() { + // The cursor position may be on either cell of a double-width character. + // Visually, the cursor appears under both cells, regardless of which + // specific one has the cursor. + printf("test6 - cursor can be either left or right cell of full-width char\n"); + + writeCharsAt({2,1}, {0x4000}); + + setCursorPos(2, 1); + auto pos1 = getCursorPos(); + Sleep(1000); + + setCursorPos(3, 1); + auto pos2 = getCursorPos(); + Sleep(1000); + + setCursorPos(0, 15); + printf("%d,%d\n", pos1.X, pos1.Y); + printf("%d,%d\n", pos2.X, pos2.Y); +} + +static void runTest(void (&test)()) { + system("cls"); + setCursorPos(0, 14); + test(); + system("pause"); +} + +int main(int argc, char *argv[]) { + if (argc == 1) { + startChildProcess(L"CHILD"); + return 0; + } + + setWindowPos(0, 0, 1, 1); + setBufferSize(80, 40); + setWindowPos(0, 0, 80, 40); + + auto cp = GetConsoleOutputCP(); + assert(cp == 932 || cp == 936 || cp == 949 || cp == 950); + + runTest(test1); + runTest(test2); + runTest(test3); + runTest(test4); + runTest(test5); + runTest(test6); + + return 0; +}