From 2647678b0f18e74691ab64c9db570fd2038cec0a Mon Sep 17 00:00:00 2001 From: Quantum Date: Mon, 22 Sep 2025 00:27:01 -0400 Subject: [PATCH] [idd] helper: add parser for mode settings in registry --- idd/LGIdd/LGIdd.vcxproj.filters | 3 + idd/LGIddHelper/CRegistrySettings.cpp | 119 ++++++++++++++++++++ idd/LGIddHelper/CRegistrySettings.h | 29 +++++ idd/LGIddHelper/LGIddHelper.vcxproj | 8 +- idd/LGIddHelper/LGIddHelper.vcxproj.filters | 9 ++ 5 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 idd/LGIddHelper/CRegistrySettings.cpp create mode 100644 idd/LGIddHelper/CRegistrySettings.h diff --git a/idd/LGIdd/LGIdd.vcxproj.filters b/idd/LGIdd/LGIdd.vcxproj.filters index a14c45fe..1ec1c809 100644 --- a/idd/LGIdd/LGIdd.vcxproj.filters +++ b/idd/LGIdd/LGIdd.vcxproj.filters @@ -85,6 +85,8 @@ Header Files + + @@ -137,5 +139,6 @@ Source Files + \ No newline at end of file diff --git a/idd/LGIddHelper/CRegistrySettings.cpp b/idd/LGIddHelper/CRegistrySettings.cpp new file mode 100644 index 00000000..c3076cba --- /dev/null +++ b/idd/LGIddHelper/CRegistrySettings.cpp @@ -0,0 +1,119 @@ +#include "CRegistrySettings.h" + +#include +#include +#include + +#define LGIDD_REGKEY L"SOFTWARE\\LookingGlass\\IDD" + +CRegistrySettings::CRegistrySettings() : hKey(nullptr) {} + +CRegistrySettings::~CRegistrySettings() +{ + if (hKey) + RegCloseKey(hKey); +} + +LSTATUS CRegistrySettings::open() +{ + HKEY key; + LSTATUS result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, LGIDD_REGKEY, 0, KEY_QUERY_VALUE, &key); + + if (result == ERROR_SUCCESS) + hKey = key; + + return result; +} + +template +static std::basic_string trim(const std::basic_string &s) +{ + size_t b = 0, e = s.size(); + while (b < e && iswspace(s[b])) + ++b; + while (e > b && iswspace(s[e - 1])) + --e; + return s.substr(b, e - b); +} + +static std::wregex displayMode(L"(\\d+)x(\\d+)@(\\d+)(\\*)?"); + +static std::optional parseDisplayMode(const std::wstring &str) +{ + std::wstring trimmed = trim(str); + std::wsmatch match; + + if (!std::regex_match(trimmed, match, displayMode)) + return {}; + + DisplayMode mode; + mode.width = std::stoul(match[1]); + mode.height = std::stoul(match[2]); + mode.refresh = std::stoul(match[3]); + mode.preferred = match[4] == L"*"; + return mode; +} + +std::optional> CRegistrySettings::getModes() +{ + LSTATUS status; + + DWORD type = 0, cb = 0; + status = RegGetValue(hKey, nullptr, L"Modes", RRF_RT_REG_MULTI_SZ, &type, nullptr, &cb); + if (status != ERROR_SUCCESS) + { + DEBUG_ERROR_HR(status, "RegGetValue(Modes) length computation"); + return {}; + } + + LPWSTR buf = (LPWSTR) malloc(cb); + if (!buf) + { + DEBUG_ERROR("Failed to allocate memory for RegGetValue(Modes)"); + return {}; + } + + status = RegGetValueW(hKey, nullptr, L"Modes", RRF_RT_REG_MULTI_SZ, &type, buf, &cb); + if (status != ERROR_SUCCESS) + { + DEBUG_ERROR_HR(status, "RegGetValue(Modes) read"); + free(buf); + return {}; + } + + std::vector result; + for (LPWSTR s = buf; *s; s += wcslen(s) + 1) + { + auto mode = parseDisplayMode(s); + if (mode.has_value()) + result.emplace_back(std::move(mode.value())); + } + free(buf); + return result; +} + +LSTATUS CRegistrySettings::setModes(const std::vector &modes) +{ + std::wstring serialized; + for (auto mode : modes) + { + serialized.append(mode.toString()); + serialized.push_back('\0'); + } + + return RegSetValueEx(hKey, L"Modes", 0, REG_MULTI_SZ, (PBYTE)serialized.c_str(), + (DWORD)(serialized.length() + 1) * sizeof(wchar_t)); +} + +std::wstring DisplayMode::toString() +{ + std::wstring serialized; + serialized.append(std::to_wstring(width)); + serialized.push_back('x'); + serialized.append(std::to_wstring(height)); + serialized.push_back('@'); + serialized.append(std::to_wstring(refresh)); + if (preferred) + serialized.push_back('*'); + return serialized; +} diff --git a/idd/LGIddHelper/CRegistrySettings.h b/idd/LGIddHelper/CRegistrySettings.h new file mode 100644 index 00000000..21b6f697 --- /dev/null +++ b/idd/LGIddHelper/CRegistrySettings.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include + +struct DisplayMode { + unsigned width; + unsigned height; + unsigned refresh; + bool preferred; + + std::wstring toString(); +}; + +class CRegistrySettings { + HKEY hKey; + +public: + CRegistrySettings(); + ~CRegistrySettings(); + + LSTATUS open(); + bool isOpen() { return !!hKey; } + + std::optional> getModes(); + LSTATUS setModes(const std::vector &modes); +}; diff --git a/idd/LGIddHelper/LGIddHelper.vcxproj b/idd/LGIddHelper/LGIddHelper.vcxproj index f8b796af..35dad7ac 100644 --- a/idd/LGIddHelper/LGIddHelper.vcxproj +++ b/idd/LGIddHelper/LGIddHelper.vcxproj @@ -78,6 +78,7 @@ WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) true $(SolutionDir)LGCommon;%(AdditionalIncludeDirectories) + stdcpp17 Console @@ -102,6 +103,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) true $(SolutionDir)LGCommon;%(AdditionalIncludeDirectories) + stdcpp17 Console @@ -125,7 +127,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd true _DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) true - Default + stdcpp17 Default $(SolutionDir)LGCommon;%(AdditionalIncludeDirectories) MultiThreadedDebug @@ -153,7 +155,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd true NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) true - Default + stdcpp17 Default $(SolutionDir)LGCommon;%(AdditionalIncludeDirectories) MultiThreaded @@ -180,6 +182,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd + @@ -190,6 +193,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd + diff --git a/idd/LGIddHelper/LGIddHelper.vcxproj.filters b/idd/LGIddHelper/LGIddHelper.vcxproj.filters index b39d6583..899737ac 100644 --- a/idd/LGIddHelper/LGIddHelper.vcxproj.filters +++ b/idd/LGIddHelper/LGIddHelper.vcxproj.filters @@ -39,6 +39,10 @@ Source Files + + + Source Files + @@ -67,6 +71,11 @@ Header Files + + + + Header Files +