Created
February 19, 2024 09:14
-
-
Save Aetopia/cb85bb441637dfa4ee7515b210875fea to your computer and use it in GitHub Desktop.
Simple command line app to switch display modes on Windows via a CLI.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
LONG DisplayConfigSetDisplayMode(DISPLAYCONFIG_PATH_INFO *pPath, PDEVMODEW pDevMode, DWORD dwFlags) | |
{ | |
DISPLAYCONFIG_SOURCE_DEVICE_NAME dcSourceDeviceName = {.header = {.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, | |
.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME), | |
.adapterId = pPath->sourceInfo.adapterId, | |
.id = pPath->sourceInfo.id}}; | |
DisplayConfigGetDeviceInfo(&dcSourceDeviceName.header); | |
return ChangeDisplaySettingsExW(dcSourceDeviceName.viewGdiDeviceName, pDevMode, NULL, dwFlags, NULL); | |
} | |
VOID DisplayConfigOutputDisplayName(DISPLAYCONFIG_PATH_INFO *pPath) | |
{ | |
DISPLAYCONFIG_SOURCE_DEVICE_NAME dcSourceDeviceName = {.header = {.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, | |
.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME), | |
.adapterId = pPath->sourceInfo.adapterId, | |
.id = pPath->sourceInfo.id}}; | |
DisplayConfigGetDeviceInfo(&dcSourceDeviceName.header); | |
DISPLAYCONFIG_TARGET_DEVICE_NAME dcTargetDeviceName = {.header = {.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME, | |
.size = sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME), | |
.adapterId = pPath->targetInfo.adapterId, | |
.id = pPath->targetInfo.id}}; | |
DisplayConfigGetDeviceInfo(&dcTargetDeviceName.header); | |
__builtin_printf("%ls\n", dcTargetDeviceName.flags.friendlyNameFromEdid | |
? dcTargetDeviceName.monitorFriendlyDeviceName | |
: dcSourceDeviceName.viewGdiDeviceName); | |
} | |
VOID DisplayConfigOutputDisplayModes(DISPLAYCONFIG_PATH_INFO *pPath) | |
{ | |
DISPLAYCONFIG_SOURCE_DEVICE_NAME dcSourceDeviceName = {.header = {.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, | |
.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME), | |
.adapterId = pPath->sourceInfo.adapterId, | |
.id = pPath->sourceInfo.id}}; | |
DisplayConfigGetDeviceInfo(&dcSourceDeviceName.header); | |
DEVMODEW dm = {.dmSize = sizeof(DEVMODEW)}; | |
DWORD iModeNum = 0; | |
while (EnumDisplaySettingsW(dcSourceDeviceName.viewGdiDeviceName, iModeNum, &dm)) | |
{ | |
if (!dm.dmDisplayFixedOutput) | |
__builtin_printf("\t%ld x %ld @ %ld Hz%s\n", dm.dmPelsWidth, dm.dmPelsHeight, dm.dmDisplayFrequency, | |
dm.dmDisplayFlags ? " (Interlaced)" : ""); | |
iModeNum++; | |
} | |
} | |
int wmain(int argc, wchar_t *wargv[]) | |
{ | |
UINT fArgument = 0; | |
if (CompareStringOrdinal(L"/enumerate", -1, wargv[1], -1, TRUE) == CSTR_EQUAL && argc == 2) | |
fArgument = 1; | |
else if (CompareStringOrdinal(L"/get", -1, wargv[1], -1, TRUE) == CSTR_EQUAL && argc == 3) | |
fArgument = 2; | |
else if (CompareStringOrdinal(L"/set", -1, wargv[1], -1, TRUE) == CSTR_EQUAL && argc == 7) | |
fArgument = 3; | |
else if (CompareStringOrdinal(L"/save", -1, wargv[1], -1, TRUE) == CSTR_EQUAL && argc == 7) | |
fArgument = 4; | |
else | |
{ | |
__builtin_printf("DisplayConfig:\n\n" | |
"\t/Enumerate\n\t\tEnumerate displays.\n\n" | |
"\t/Get <Index>\n\t\tObtain display modes for a given display.\n\n" | |
"\t/Set <Index> <Width> <Height> <Refresh Rate> <Orientation>\n\t\tSet the display mode with " | |
"specified parameters.\n\n" | |
"\t/Save <Index> <Width> <Height> <Refresh Rate> <Orientation>\n\t\tSaves the specified " | |
"display mode to the registry.\n\n"); | |
return 0; | |
} | |
UINT numPathArrayElements = 0, numModeInfoArrayElements = 0; | |
GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, &numModeInfoArrayElements); | |
HANDLE hHeap = GetProcessHeap(); | |
DISPLAYCONFIG_PATH_INFO *pathArray = HeapAlloc(hHeap, 0, sizeof(DISPLAYCONFIG_PATH_INFO) * numPathArrayElements); | |
DISPLAYCONFIG_MODE_INFO *modeInfoArray = | |
HeapAlloc(hHeap, 0, sizeof(DISPLAYCONFIG_MODE_INFO) * numModeInfoArrayElements); | |
QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pathArray, &numModeInfoArrayElements, | |
modeInfoArray, NULL); | |
switch (fArgument) | |
{ | |
case 1: { | |
for (UINT32 nIndex = 0; nIndex < numPathArrayElements; nIndex++) | |
{ | |
__builtin_printf("%d : ", nIndex); | |
DisplayConfigOutputDisplayName(&pathArray[nIndex]); | |
} | |
} | |
break; | |
case 2: { | |
LONG nIndex = _wtol(wargv[2]); | |
if (numPathArrayElements - 1 >= nIndex) | |
DisplayConfigOutputDisplayModes(&pathArray[nIndex]); | |
else | |
__builtin_printf("Error: Invalid Display Index."); | |
} | |
break; | |
case 3: | |
case 4: { | |
LONG nIndex = _wtol(wargv[2]); | |
DEVMODEW dm = {.dmSize = sizeof(DEVMODEW), | |
.dmPelsWidth = _wtol(wargv[3]), | |
.dmPelsHeight = _wtol(wargv[4]), | |
.dmDisplayFrequency = _wtol(wargv[5]), | |
.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYORIENTATION}; | |
if (CompareStringOrdinal(L"landscape", -1, wargv[6], -1, TRUE) == CSTR_EQUAL) | |
dm.dmDisplayOrientation = DMDO_DEFAULT; | |
else if (CompareStringOrdinal(L"landscape-flipped", -1, wargv[6], -1, TRUE) == CSTR_EQUAL) | |
dm.dmDisplayOrientation = DMDO_180; | |
else if (CompareStringOrdinal(L"portrait", -1, wargv[6], -1, TRUE) == CSTR_EQUAL) | |
dm.dmDisplayOrientation = DMDO_90; | |
else if (CompareStringOrdinal(L"portrait-flipped", -1, wargv[6], -1, TRUE) == CSTR_EQUAL) | |
dm.dmDisplayOrientation = DMDO_270; | |
if (numPathArrayElements - 1 >= nIndex) | |
if (DisplayConfigSetDisplayMode(&pathArray[nIndex], &dm, CDS_TEST)) | |
__builtin_printf("Error: Invalid Display Mode."); | |
else | |
DisplayConfigSetDisplayMode(&pathArray[nIndex], &dm, fArgument == 3 ? 0 : CDS_UPDATEREGISTRY); | |
else | |
__builtin_printf("Error: Invalid Display Index."); | |
} | |
break; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment