From 7598e5770466a75972e3160e8f0413a3cfff70ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 8 Aug 2023 23:19:22 +0800 Subject: [PATCH] NativeResolution (Windows): add support --- CMakeLists.txt | 2 +- .../nativeresolution_windows.c | 48 +++++++++++++++++++ src/util/edidHelper.c | 4 +- src/util/windows/registry.c | 18 +++++++ src/util/windows/registry.h | 1 + 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 src/detection/nativeresolution/nativeresolution_windows.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dc60b91e..ad8904a8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -588,7 +588,7 @@ elseif(WIN32) src/detection/gamepad/gamepad_windows.c src/detection/media/media_nosupport.c src/detection/memory/memory_windows.c - src/detection/nativeresolution/nativeresolution_nosupport.c + src/detection/nativeresolution/nativeresolution_windows.c src/detection/opengl/opengl_windows.c src/detection/os/os_windows.cpp src/detection/packages/packages_windows.c diff --git a/src/detection/nativeresolution/nativeresolution_windows.c b/src/detection/nativeresolution/nativeresolution_windows.c new file mode 100644 index 000000000..e5b9a5d16 --- /dev/null +++ b/src/detection/nativeresolution/nativeresolution_windows.c @@ -0,0 +1,48 @@ +#include "nativeresolution.h" + +#include "common/io/io.h" +#include "util/edidHelper.h" +#include "util/stringUtils.h" +#include "util/windows/registry.h" +#include "util/windows/unicode.h" + +#include +#include +#include + +static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev) +{ + if(*hdev) + SetupDiDestroyDeviceInfoList(*hdev); +} + +const char* ffDetectNativeResolution(FFlist* results) +{ + //https://learn.microsoft.com/en-us/windows/win32/power/enumerating-battery-devices + HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) = + SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, 0, 0, DIGCF_PRESENT); + if(hdev == INVALID_HANDLE_VALUE) + return "SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR) failed"; + + SP_DEVINFO_DATA did = { .cbSize = sizeof(did) }; + for (DWORD idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); ++idev) + { + FF_HKEY_AUTO_DESTROY hKey = SetupDiOpenDevRegKey(hdev, &did, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); + if (!hKey) continue; + + uint8_t edidData[256] = {}; + if (!ffRegReadData(hKey, L"EDID", edidData, sizeof(edidData), NULL)) continue; + uint32_t width, height; + ffEdidGetNativeResolution(edidData, &width, &height); + if (width == 0 || height == 0) continue; + + wchar_t wName[MAX_PATH] = {}; // MONITOR\BOE09F9 + if (!SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_HARDWAREID, NULL, (BYTE*) wName, sizeof(wName), NULL)) continue; + + FFNativeResolutionResult* display = (FFNativeResolutionResult*) ffListAdd(results); + display->width = width; + display->height = height; + ffStrbufInitWS(&display->name, wcschr(wName, L'\\') + 1); + } + return NULL; +} diff --git a/src/util/edidHelper.c b/src/util/edidHelper.c index fa765d55f..bbd87cc17 100644 --- a/src/util/edidHelper.c +++ b/src/util/edidHelper.c @@ -3,6 +3,6 @@ void ffEdidGetNativeResolution(uint8_t edid[128], uint32_t* width, uint32_t* height) { const int dtd = 54; - *width = ((edid[dtd + 4] >> 4) << 8) | edid[dtd + 2]; - *height = ((edid[dtd + 7] >> 4) << 8) | edid[dtd + 5]; + *width = (((uint32_t) edid[dtd + 4] >> 4) << 8) | edid[dtd + 2]; + *height = (((uint32_t) edid[dtd + 7] >> 4) << 8) | edid[dtd + 5]; } diff --git a/src/util/windows/registry.c b/src/util/windows/registry.c index d4dbffa93..f56d59c50 100644 --- a/src/util/windows/registry.c +++ b/src/util/windows/registry.c @@ -64,6 +64,24 @@ bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFs return true; } +bool ffRegReadData(HKEY hKey, const wchar_t* valueNameW, uint8_t* result, uint32_t bufSize, FFstrbuf* error) +{ + static_assert(sizeof(DWORD) == sizeof(uint32_t), ""); + LONG err = RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_BINARY, NULL, result, (DWORD*) &bufSize); + if(err != ERROR_SUCCESS) + { + if(error) + { + if(!valueNameW) + valueNameW = L"(default)"; + FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); + ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_SZ) failed", valueNameA.chars); + } + return false; + } + return true; +} + bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error) { DWORD bufSize = sizeof(*result); diff --git a/src/util/windows/registry.h b/src/util/windows/registry.h index 222b468a7..8e582ac54 100644 --- a/src/util/windows/registry.h +++ b/src/util/windows/registry.h @@ -17,6 +17,7 @@ static inline void wrapRegCloseKey(HKEY* phKey) bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error); bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error); +bool ffRegReadData(HKEY hKey, const wchar_t* valueNameW, uint8_t* result, uint32_t bufSize, FFstrbuf* error); bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error); bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error); bool ffRegGetSubKey(HKEY hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error);