Skip to content

Instantly share code, notes, and snippets.

@zadjii-msft
Created March 24, 2023 14:21
Show Gist options
  • Save zadjii-msft/13d2f14e2125b674fdcb92525e2bde97 to your computer and use it in GitHub Desktop.
Save zadjii-msft/13d2f14e2125b674fdcb92525e2bde97 to your computer and use it in GitHub Desktop.
Listen for console screen buffer size changes
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include <windows.h>
#include <stdio.h>
// WIL
#include <wil/Common.h>
#include <wil/Result.h>
#include <wil/nt_result_macros.h>
#include <wil/resource.h>
#include <wil/wistd_memory.h>
#include <wil/stl.h>
#include <wil/com.h>
#include <wil/filesystem.h>
#include <wil/win32_helpers.h>
bool g_exitRequested = false;
HANDLE g_hOut;
HANDLE g_hIn;
void handleResize(const WINDOW_BUFFER_SIZE_RECORD& bufferRecord)
{
CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 };
csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
bool fSuccess = !!GetConsoleScreenBufferInfoEx(g_hOut, &csbiex);
if (fSuccess)
{
SMALL_RECT srViewport = csbiex.srWindow;
unsigned short width = srViewport.Right - srViewport.Left + 1;
unsigned short height = srViewport.Bottom - srViewport.Top + 1;
// Print the size from the buffer record
wprintf(L"bufferRecord: %d x %d\n", bufferRecord.dwSize.X, bufferRecord.dwSize.Y);
// Print the current size of the viewport.
wprintf(L"Current size of the viewport: %d x %d\n\n", width, height);
}
}
static void ScrollWindow(short Offset)
{
const auto Out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO Info;
GetConsoleScreenBufferInfo(Out, &Info);
Info.srWindow.Top += Offset;
Info.srWindow.Bottom += Offset;
SetConsoleWindowInfo(Out, true, &Info.srWindow);
}
void handleManyEvents(const INPUT_RECORD* const inputBuffer, int cEvents)
{
for (int i = 0; i < cEvents; ++i)
{
INPUT_RECORD event = inputBuffer[i];
if (event.EventType == KEY_EVENT)
{
KEY_EVENT_RECORD keyEvent = event.Event.KeyEvent;
// if the keyevent was a ctrl+c, then we'll want to exit.
if (keyEvent.bKeyDown &&
keyEvent.wVirtualKeyCode == 'C' &&
keyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
{
wprintf(L"Ctrl+C pressed\n");
g_exitRequested = true;
break;
}
// From GH#281
if (keyEvent.bKeyDown)
{
switch (keyEvent.wVirtualKeyCode)
{
case VK_UP:
ScrollWindow(-1);
break;
case VK_DOWN:
ScrollWindow(1);
break;
}
}
}
else if (event.EventType == WINDOW_BUFFER_SIZE_EVENT)
{
WINDOW_BUFFER_SIZE_RECORD resize = event.Event.WindowBufferSizeEvent;
handleResize(resize);
}
}
}
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
// Handle the CTRL-C signal.
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
g_exitRequested = true;
return true;
}
return false;
}
// This wmain exists for help in writing scratch programs while debugging.
int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/)
{
g_hOut = GetStdHandle(STD_OUTPUT_HANDLE);
g_hIn = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleCtrlHandler(CtrlHandler, TRUE);
unsigned int launchOutputCP = GetConsoleOutputCP();
unsigned int launchCP = GetConsoleCP();
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
// Enable VT input mode
DWORD originalMode = 0;
if (GetConsoleMode(g_hIn, &originalMode))
{
// const auto newMode = originalMode | ENABLE_VIRTUAL_TERMINAL_INPUT;
// SetConsoleMode(g_hIn, newMode);
}
auto restore = wil::scope_exit([&] {
wprintf(L"exiting\n");
SetConsoleMode(g_hIn, originalMode);
SetConsoleOutputCP(launchOutputCP);
SetConsoleCP(launchCP);
});
wprintf(L"buffer resize test. Press ^C to exit\n");
while (!g_exitRequested)
{
INPUT_RECORD rc[256];
DWORD dwRead = 0;
// Not to future self: You can't read utf-8 from the console yet.
bool fSuccess = !!ReadConsoleInput(g_hIn, rc, 256, &dwRead);
if (fSuccess)
{
handleManyEvents(rc, dwRead);
}
else
{
exit(GetLastError());
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment