void TestSetConsoleCursorPositionImpl(WORD wCursorX, WORD wCursorY, BOOL bExpectedResult) { COORD coordCursor; coordCursor.X = wCursorX; coordCursor.Y = wCursorY; // Get initial position data CONSOLE_SCREEN_BUFFER_INFOEX sbiInitial = { 0 }; sbiInitial.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); BOOL bResult = GetConsoleScreenBufferInfoEx(Common::_hConsole, &sbiInitial); VERIFY_WIN32_BOOL_SUCCEEDED(bResult, L"Get the initial buffer data."); // Attempt to set cursor into valid area bResult = SetConsoleCursorPosition(Common::_hConsole, coordCursor); VERIFY_ARE_EQUAL(bResult, bExpectedResult, L"Ensure that return from SET matches success/failure state we were expecting."); CONSOLE_SCREEN_BUFFER_INFOEX sbiTest = { 0 }; sbiTest.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); bResult = GetConsoleScreenBufferInfoEx(Common::_hConsole, &sbiTest); VERIFY_WIN32_BOOL_SUCCEEDED(bResult, L"GET the values back to ensure they were set properly."); // Cursor is where it was set to if we were supposed to be successful if (bExpectedResult) { VERIFY_ARE_EQUAL(coordCursor, sbiTest.dwCursorPosition, L"If SET was TRUE, we expect the cursor to be where we SET it."); } else { // otherwise, it's at where it was before VERIFY_ARE_EQUAL(sbiInitial.dwCursorPosition, sbiTest.dwCursorPosition, L"If SET was FALSE, we expect the cursor to not have moved."); } // Verify the viewport. bool fViewportMoveExpected = false; // If we expected the cursor to be set successfully, the viewport might have moved. if (bExpectedResult) { // If the position we set was outside the initial rectangle, then the viewport should have moved. if (coordCursor.X > sbiInitial.srWindow.Right || coordCursor.X < sbiInitial.srWindow.Left || coordCursor.Y > sbiInitial.srWindow.Bottom || coordCursor.Y < sbiInitial.srWindow.Top) { fViewportMoveExpected = true; } } if (fViewportMoveExpected) { // Something had to have changed in the viewport VERIFY_ARE_NOT_EQUAL(sbiInitial.srWindow, sbiTest.srWindow, L"The viewports must have changed if we set the cursor outside the current area."); } else { VERIFY_ARE_EQUAL(sbiInitial.srWindow, sbiTest.srWindow, L"The viewports must remain the same if the cursor was set inside the existing one."); } }
void FileTests::TestWriteFileWrapEOL() { bool fFlagOn; VERIFY_SUCCEEDED(TestData::TryGetValue(L"fFlagOn", fFlagOn)); HANDLE const hOut = GetStdOutputHandle(); VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexOriginal = { 0 }; csbiexOriginal.cbSize = sizeof(csbiexOriginal); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexOriginal), L"Retrieve screen buffer properties at beginning of test."); if (fFlagOn) { VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, ENABLE_WRAP_AT_EOL_OUTPUT), L"Set wrap at EOL."); } else { VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, 0), L"Make sure wrap at EOL is off."); } COORD const coordZero = { 0 }; VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer."); // Fill first row of the buffer with Z characters until 1 away from the end. for (SHORT i = 0; i < csbiexOriginal.dwSize.X - 1; i++) { WriteFile(hOut, "Z", 1, nullptr, nullptr); } CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 }; csbiexBefore.cbSize = sizeof(csbiexBefore); CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 }; csbiexAfter.cbSize = sizeof(csbiexAfter); COORD coordExpected = { 0 }; VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexBefore), L"Get cursor position information before attempting to wrap at end of line."); VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, "Y", 1, nullptr, nullptr), L"Write of final character in line succeeded."); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexAfter), L"Get cursor position information after attempting to wrap at end of line."); if (fFlagOn) { Log::Comment(L"Cursor should go down a row if we tried to print at end of line."); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.Y++; coordExpected.X = 0; } else { Log::Comment(L"Cursor shouldn't move when printing at end of line."); coordExpected = csbiexBefore.dwCursorPosition; } VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved as expected based on flag state."); }
void FileTests::TestWriteFileSuspended() { HANDLE const hOut = GetStdOutputHandle(); VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle."); HANDLE const hIn = GetStdInputHandle(); VERIFY_IS_NOT_NULL(hIn, L"Verify we have the standard input handle."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexOriginal = { 0 }; csbiexOriginal.cbSize = sizeof(csbiexOriginal); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexOriginal), L"Retrieve screen buffer properties at beginning of test."); DWORD dwMode = 0; VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, dwMode), L"Set console mode for test."); COORD const coordZero = { 0 }; VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer."); VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, "abc", 3, nullptr, nullptr), L"Test first write success."); PauseHelper(hIn); auto BlockedWrite = std::async([&] { Log::Comment(L"Background WriteFile scheduled."); VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, "def", 3, nullptr, nullptr), L"Test second write success."); }); UnpauseHelper(hIn); BlockedWrite.wait(); }
void WriteFileHelper(HANDLE hOut, CONSOLE_SCREEN_BUFFER_INFOEX& csbiexBefore, CONSOLE_SCREEN_BUFFER_INFOEX& csbiexAfter, PCSTR psTest, DWORD cchTest) { csbiexBefore.cbSize = sizeof(csbiexBefore); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexBefore), L"Retrieve screen buffer properties before writing."); DWORD dwWritten = 0; VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, psTest, cchTest, &dwWritten, nullptr), L"Write text into buffer using WriteFile"); VERIFY_ARE_EQUAL(cchTest, dwWritten, L"Verify all characters were written."); csbiexAfter.cbSize = sizeof(csbiexAfter); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexAfter), L"Retrieve screen buffer properties after writing."); }
void FileTests::TestWriteFileRaw() { // \x7 is bell // \x8 is backspace // \x9 is tab // \xa is linefeed // \xd is carriage return // All should be ignored/printed in raw mode. PCSTR strTest = "z\x7y\x8z\x9y\xaz\xdy"; DWORD const cchTest = (DWORD)strlen(strTest); String strReadBackExpected(strTest); HANDLE const hOut = GetStdOutputHandle(); VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 }; csbiexBefore.cbSize = sizeof(csbiexBefore); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexBefore), L"Retrieve screen buffer properties before writing."); VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, 0), L"Set raw write mode."); COORD const coordZero = { 0 }; VERIFY_ARE_EQUAL(coordZero, csbiexBefore.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer."); DWORD dwWritten = 0; VERIFY_WIN32_BOOL_SUCCEEDED(WriteFile(hOut, strTest, cchTest, &dwWritten, nullptr), L"Write text into buffer using WriteFile"); VERIFY_ARE_EQUAL(cchTest, dwWritten); CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 }; csbiexAfter.cbSize = sizeof(csbiexAfter); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexAfter), L"Retrieve screen buffer properties after writing."); csbiexBefore.dwCursorPosition.X += (SHORT)cchTest; VERIFY_ARE_EQUAL(csbiexBefore.dwCursorPosition, csbiexAfter.dwCursorPosition, L"Verify cursor moved expected number of squares for the write length."); DWORD const cbReadBackBuffer = cchTest + 2; // +1 so we can read back a "space" that should be after what we wrote. +1 more so this can be null terminated for String class comparison. wistd::unique_ptr<char[]> strReadBack = wil::make_unique_failfast<char[]>(cbReadBackBuffer); ZeroMemory(strReadBack.get(), cbReadBackBuffer * sizeof(char)); DWORD dwRead = 0; VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleOutputCharacterA(hOut, strReadBack.get(), cchTest + 1, coordZero, &dwRead), L"Read back the data in the buffer."); // +1 to read back the space that should be after the text we wrote strReadBackExpected += " "; // add in the space that should appear after the written text (buffer should be space filled when empty) VERIFY_ARE_EQUAL(strReadBackExpected, String(strReadBack.get()), L"Ensure that the buffer contents match what we expected based on what we wrote."); }
void FileTests::TestWriteFileDisableNewlineAutoReturn() { bool fDisableAutoReturn; VERIFY_SUCCEEDED(TestData::TryGetValue(L"fDisableAutoReturn", fDisableAutoReturn)); bool fProcessedOn; VERIFY_SUCCEEDED(TestData::TryGetValue(L"fProcessedOn", fProcessedOn)); HANDLE const hOut = GetStdOutputHandle(); VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexOriginal = { 0 }; csbiexOriginal.cbSize = sizeof(csbiexOriginal); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexOriginal), L"Retrieve screen buffer properties at beginning of test."); DWORD dwMode = 0; WI_SetFlagIf(dwMode, DISABLE_NEWLINE_AUTO_RETURN, fDisableAutoReturn); WI_SetFlagIf(dwMode, ENABLE_PROCESSED_OUTPUT, fProcessedOn); VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, dwMode), L"Set console mode for test."); COORD const coordZero = { 0 }; VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 }; csbiexBefore.cbSize = sizeof(csbiexBefore); CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 }; csbiexAfter.cbSize = sizeof(csbiexAfter); COORD coordExpected = { 0 }; WriteFileHelper(hOut, csbiexBefore, csbiexAfter, "abc", 3); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 3; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Cursor should have moved right to the end of the text written."); WriteFileHelper(hOut, csbiexBefore, csbiexAfter, "\n", 1); if (fProcessedOn) { if (fDisableAutoReturn) { coordExpected = csbiexBefore.dwCursorPosition; coordExpected.Y += 1; } else { coordExpected = csbiexBefore.dwCursorPosition; coordExpected.Y += 1; coordExpected.X = 0; } } else { coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 1; } VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Cursor should move to expected position."); }
void FileTests::TestWriteFileVTProcessing() { bool fVtOn; VERIFY_SUCCEEDED(TestData::TryGetValue(L"fVtOn", fVtOn)); bool fProcessedOn; VERIFY_SUCCEEDED(TestData::TryGetValue(L"fProcessedOn", fProcessedOn)); HANDLE const hOut = GetStdOutputHandle(); VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexOriginal = { 0 }; csbiexOriginal.cbSize = sizeof(csbiexOriginal); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexOriginal), L"Retrieve screen buffer properties at beginning of test."); DWORD dwFlags = 0; WI_SetFlagIf(dwFlags, ENABLE_VIRTUAL_TERMINAL_PROCESSING, fVtOn); WI_SetFlagIf(dwFlags, ENABLE_PROCESSED_OUTPUT, fProcessedOn); VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, dwFlags), L"Turn on relevant flags for test."); COORD const coordZero = { 0 }; VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer."); PCSTR pszTestString = "\x1b" "[14m"; DWORD const cchTest = (DWORD)strlen(pszTestString); CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 }; csbiexBefore.cbSize = sizeof(csbiexBefore); CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 }; csbiexAfter.cbSize = sizeof(csbiexAfter); WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTestString, cchTest); // We only expect characters to be processed and not printed if both processed mode and VT mode are on. bool const fProcessedNotPrinted = fProcessedOn && fVtOn; if (fProcessedNotPrinted) { PCSTR pszReadBackExpected = " "; DWORD const cchReadBackExpected = (DWORD)strlen(pszReadBackExpected); VERIFY_ARE_EQUAL(csbiexBefore.dwCursorPosition, csbiexAfter.dwCursorPosition, L"Verify cursor didn't move because the VT sequence was processed instead of printed."); wistd::unique_ptr<char[]> pszReadBack; ReadBackHelper(hOut, coordZero, cchReadBackExpected, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify that nothing was printed into the buffer."); } else { COORD coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += (SHORT)cchTest; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved as characters should have been emitted, not consumed."); wistd::unique_ptr<char[]> pszReadBack; ReadBackHelper(hOut, coordZero, cchTest, pszReadBack); VERIFY_ARE_EQUAL(String(pszTestString), String(pszReadBack.get()), L"Verify that original test string was printed into the buffer."); } }
void CursorTests::TestSetConsoleCursorPosition() { // Get initial buffer value for boundaries CONSOLE_SCREEN_BUFFER_INFOEX sbiInitial = { 0 }; sbiInitial.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); BOOL bResult = GetConsoleScreenBufferInfoEx(Common::_hConsole, &sbiInitial); VERIFY_WIN32_BOOL_SUCCEEDED(bResult, L"Retrieve the initial buffer information to calculate the boundaries for testing."); // Try several cases TestSetConsoleCursorPositionImpl(0, 0, TRUE); // Top left corner of buffer TestSetConsoleCursorPositionImpl(sbiInitial.dwSize.X - 1, sbiInitial.dwSize.Y - 1, TRUE); // Bottom right corner of buffer TestSetConsoleCursorPositionImpl(sbiInitial.dwSize.X, sbiInitial.dwSize.Y, FALSE); // 1 beyond bottom right corner (the size is 1 larger than the array indicies) TestSetConsoleCursorPositionImpl(MAXWORD, MAXWORD, FALSE); // Max values }
int ColorTableLookup(unsigned int ColorArgb) { if (m_ColorTable.IsEmpty()) { CONSOLE_SCREEN_BUFFER_INFOEX ConsoleInfo; ConsoleInfo.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); GetConsoleScreenBufferInfoEx(m_ConsoleHandle, &ConsoleInfo); for (int i = 0; i < 16; i++) { m_ColorTable.Add(Color::FromAbgr(ConsoleInfo.ColorTable[i])); } } Color TargetColor(ColorArgb); return TargetColor.FindClosestPaletteIndex(m_ColorTable); }
JNIEXPORT void JNICALL Java_com_yifanlu_Josh_Josh_SETCONSOLESCREENBUFFERINFOEX (JNIEnv *env, jclass jcls, jlong pointer, jint sizeX, jint sizeY, jint cursorX, jint cursorY, jint attributes, jint windowLeft, jint windowTop, jint windowRight, jint windowBottom, jint maxX, jint maxY) { HANDLE hConsole = pointerToHandle(pointer); COORD dwSize = {sizeX, sizeY}; COORD dwCursorPosition = {cursorX, cursorY}; WORD wAttributes = attributes; SMALL_RECT srWindow = {windowLeft, windowTop, windowRight, windowBottom}; COORD dwMaximumWindowSize = {maxX, maxY}; CONSOLE_SCREEN_BUFFER_INFOEX bufferInfo; GetConsoleScreenBufferInfoEx(hConsole, &bufferInfo); bufferInfo.dwSize = dwSize; bufferInfo.dwCursorPosition = dwCursorPosition; bufferInfo.wAttributes = wAttributes; bufferInfo.srWindow = srWindow; bufferInfo.dwMaximumWindowSize = dwMaximumWindowSize; SetConsoleScreenBufferInfoEx(hConsole, &bufferInfo); }
void FileTests::TestWriteFileProcessed() { // \x7 is bell // \x8 is backspace // \x9 is tab // \xa is linefeed // \xd is carriage return // All should cause activity in processed mode. HANDLE const hOut = GetStdOutputHandle(); VERIFY_IS_NOT_NULL(hOut, L"Verify we have the standard output handle."); CONSOLE_SCREEN_BUFFER_INFOEX csbiexOriginal = { 0 }; csbiexOriginal.cbSize = sizeof(csbiexOriginal); VERIFY_WIN32_BOOL_SUCCEEDED(GetConsoleScreenBufferInfoEx(hOut, &csbiexOriginal), L"Retrieve screen buffer properties at beginning of test."); VERIFY_WIN32_BOOL_SUCCEEDED(SetConsoleMode(hOut, ENABLE_PROCESSED_OUTPUT), L"Set processed write mode."); COORD const coordZero = { 0 }; VERIFY_ARE_EQUAL(coordZero, csbiexOriginal.dwCursorPosition, L"Cursor should be at 0,0 in fresh buffer."); // Declare variables needed for each character test. CONSOLE_SCREEN_BUFFER_INFOEX csbiexBefore = { 0 }; CONSOLE_SCREEN_BUFFER_INFOEX csbiexAfter = { 0 }; COORD coordExpected = { 0 }; PCSTR pszTest; DWORD cchTest; PCSTR pszReadBackExpected; DWORD cchReadBack; wistd::unique_ptr<char[]> pszReadBack; // 1. Test bell (\x7) { pszTest = "z\x7"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "z "; cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write z and a bell. Cursor should move once as bell should have made audible noise (can't really test) and not moved or printed anything. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 1; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved once for printable character and not for bell."); // Read back written data. ReadBackHelper(hOut, csbiexBefore.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 2. Test backspace (\x8) { pszTest = "yx\x8"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "yx "; cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write two characters and a backspace. Cursor should move only one forward as the backspace should have moved the cursor back one after printing the second character. // The backspace character itself is typically non-destructive so it should only affect the cursor, not the buffer contents. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 1; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved twice forward for printable characters and once backward for backspace."); // Read back written data. ReadBackHelper(hOut, csbiexBefore.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 3. Test tab (\x9) { // The tab character will space pad out the buffer to the next multiple-of-8 boundary. // NOTE: This is dependent on the previous tests running first. pszTest = "\x9"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = " "; cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write tab character. Cursor should move out to the next multiple-of-8 and leave space characters in its wake. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X = 8; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved forward to position 8 for tab."); // Read back written data. ReadBackHelper(hOut, csbiexBefore.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 4. Test linefeed (\xa) { // The line feed character should move us down to the next line. pszTest = "\xaQ"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "Q "; cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write line feed character. Cursor should move down a line and then the Q from our string should be printed. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected.X = 1; coordExpected.Y = 1; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved down a line and then one character over for linefeed + Q."); // Read back written data from the 2nd line. COORD coordRead; coordRead.Y = 1; coordRead.X = 0; ReadBackHelper(hOut, coordRead, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 5. Test carriage return (\xd) { // The carriage return character should move us to the front of the line. pszTest = "J\xd"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "QJ "; // J written, then move to beginning of line. cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write text and carriage return character. Cursor should end up at the beginning of this line. The J should have been printed in the line before we moved. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X = 0; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved to beginning of line for carriage return character."); // Read back text written from the 2nd line. ReadBackHelper(hOut, csbiexAfter.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } // 6. Print a character over the top of the existing { // After the carriage return, try typing on top of the Q with a K pszTest = "K"; cchTest = (DWORD)strlen(pszTest); pszReadBackExpected = "KJ "; // NOTE: This is based on the previous test(s). cchReadBack = (DWORD)strlen(pszReadBackExpected); // Write text. Cursor should end up on top of the J. WriteFileHelper(hOut, csbiexBefore, csbiexAfter, pszTest, cchTest); coordExpected = csbiexBefore.dwCursorPosition; coordExpected.X += 1; VERIFY_ARE_EQUAL(coordExpected, csbiexAfter.dwCursorPosition, L"Verify cursor moved over one for printing character."); // Read back text written from the 2nd line. ReadBackHelper(hOut, csbiexBefore.dwCursorPosition, cchReadBack, pszReadBack); VERIFY_ARE_EQUAL(String(pszReadBackExpected), String(pszReadBack.get()), L"Verify text matches what we expected to be written into the buffer."); } }
void CnsMgr::Init() { // get std handles h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); if(h_stdout == INVALID_HANDLE_VALUE) { throw cyerr("failed to get stdout handle", 8002); } h_stdin = GetStdHandle(STD_INPUT_HANDLE); if(h_stdin == INVALID_HANDLE_VALUE) { throw cyerr("failed to get stdin handle", 8003); } // create mysb, set as active h_mysb = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); if(h_mysb == INVALID_HANDLE_VALUE) { throw cyerr("failed to create screen buffer", 8004); } { // cursor info CONSOLE_CURSOR_INFO cci; cci.dwSize = 1; // anything 1-100 because not visible anyway cci.bVisible = FALSE; if(!SetConsoleCursorInfo(h_mysb, &cci)) { throw cyerr("failed to set screen buffer cursor info", 8005); } } { // screen buffer/window size // set both at once CONSOLE_SCREEN_BUFFER_INFOEX new_csbi; new_csbi.cbSize = sizeof(new_csbi); if(!GetConsoleScreenBufferInfoEx(h_mysb, &new_csbi)) { throw cyerr("failed to get screen buffer info", 8007); } if(new_csbi.dwMaximumWindowSize.X < WND_W || new_csbi.dwMaximumWindowSize.Y < WND_H) { throw cyerr("maximum window size too small", 8008); } new_csbi.dwSize = {WND_W, WND_H}; new_csbi.dwCursorPosition = {0, 0}; new_csbi.srWindow = {0, 0, WND_W-1, WND_H-1}; new_csbi.wAttributes = 0; if(!SetConsoleScreenBufferInfoEx(h_mysb, &new_csbi)) { throw cyerr("failed to set window/buffer size", 8006); } } if(!SetConsoleMode(h_mysb, NULL)) // no output processing { throw cyerr("failed to set console output mode", 8010); } if(!SetConsoleActiveScreenBuffer(h_mysb)) { throw cyerr("failed to set active screen buffer", 8009); } // change settings of stdin if(!GetConsoleMode(h_stdin, &ori_stdin_mode)) { SetConsoleActiveScreenBuffer(h_stdout); throw cyerr("failed to get stdin console mode", 8011); } if(!SetConsoleMode(h_stdin, ENABLE_EXTENDED_FLAGS | ENABLE_MOUSE_INPUT)) { SetConsoleActiveScreenBuffer(h_stdout); throw cyerr("failed to set console input mode", 8012); } // try to change window title ori_title = new char[100]; if(GetConsoleOriginalTitle(ori_title, 100)) { if(!SetConsoleTitle("CCA")) { title_changed = false; } else { title_changed = true; } } else { title_changed = false; } // create (our) buffer buf = new CHAR_INFO[WND_W * WND_H]; // done. initialized = true; // clear screen Fill(' ', 0); // black|black Flip(); }