From 0c3ce81c9437efa9fce25da21b987b33b8a9176b Mon Sep 17 00:00:00 2001 From: Enrico Giordani Date: Fri, 30 Apr 2021 07:04:53 -0700 Subject: [PATCH] [KBM Editor] Support WM_DPICHANGED event (#11015) * [KBM Editor] Support WM_DPICHANGED event * [spell checker] add term * [KBM editor] properly cast new DPI value --- .github/actions/spell-check/expect.txt | 1 + src/common/Display/dpi_aware.cpp | 45 +++++++----- src/common/Display/dpi_aware.h | 6 +- .../EditKeyboardWindow.cpp | 68 ++++++++++++------- .../EditShortcutsWindow.cpp | 49 +++++++++++-- .../common/KeyboardManagerConstants.h | 17 +++-- src/modules/powerrename/ui/PowerRenameUI.cpp | 7 +- 7 files changed, 134 insertions(+), 59 deletions(-) diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 10d263221e..24a5b0055a 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -766,6 +766,7 @@ GDISCALED generatesqlfromuserquery GETDISPINFO GETDLGCODE +GETDPISCALEDSIZE GETEMPTYMARKUP GETICON getline diff --git a/src/common/Display/dpi_aware.cpp b/src/common/Display/dpi_aware.cpp index 63f7424370..169583316d 100644 --- a/src/common/Display/dpi_aware.cpp +++ b/src/common/Display/dpi_aware.cpp @@ -5,34 +5,43 @@ namespace DPIAware { - HRESULT GetScreenDPIForWindow(HWND hwnd, UINT& dpi_x, UINT& dpi_y) + HRESULT GetScreenDPIForMonitor(HMONITOR targetMonitor, UINT& dpi) { - auto monitor_handle = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); - dpi_x = 0; - dpi_y = 0; - if (monitor_handle != nullptr) + if (targetMonitor != nullptr) { - return GetDpiForMonitor(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y); + UINT dummy = 0; + return GetDpiForMonitor(targetMonitor, MDT_EFFECTIVE_DPI, &dpi, &dummy); } else { + dpi = DPIAware::DEFAULT_DPI; return E_FAIL; } } - HRESULT GetScreenDPIForPoint(POINT p, UINT& dpi_x, UINT& dpi_y) + HRESULT GetScreenDPIForWindow(HWND hwnd, UINT& dpi) { - auto monitor_handle = MonitorFromPoint(p, MONITOR_DEFAULTTONEAREST); - dpi_x = 0; - dpi_y = 0; - if (monitor_handle != nullptr) + auto targetMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + return GetScreenDPIForMonitor(targetMonitor, dpi); + } + + HRESULT GetScreenDPIForPoint(POINT point, UINT& dpi) + { + auto targetMonitor = MonitorFromPoint(point, MONITOR_DEFAULTTONEAREST); + return GetScreenDPIForMonitor(targetMonitor, dpi); + } + + HRESULT GetScreenDPIForCursor(UINT& dpi) + { + HMONITOR targetMonitor = nullptr; + POINT currentCursorPos{ 0 }; + + if (GetCursorPos(¤tCursorPos)) { - return GetDpiForMonitor(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y); - } - else - { - return E_FAIL; + targetMonitor = MonitorFromPoint(currentCursorPos, MONITOR_DEFAULTTOPRIMARY); } + + return GetScreenDPIForMonitor(targetMonitor, dpi); } void Convert(HMONITOR monitor_handle, int& width, int& height) @@ -54,7 +63,7 @@ namespace DPIAware void ConvertByCursorPosition(int& width, int& height) { HMONITOR targetMonitor = nullptr; - POINT currentCursorPos{}; + POINT currentCursorPos{ 0 }; if (GetCursorPos(¤tCursorPos)) { @@ -96,7 +105,7 @@ namespace DPIAware { if (AreDpiAwarenessContextsEqual(levels[i], system_returned_value)) { - return static_cast(i); + return static_cast(i); } } return AwarenessLevel::UNAWARE; diff --git a/src/common/Display/dpi_aware.h b/src/common/Display/dpi_aware.h index 7f1f7b19f5..4853621fef 100644 --- a/src/common/Display/dpi_aware.h +++ b/src/common/Display/dpi_aware.h @@ -7,8 +7,10 @@ namespace DPIAware { constexpr inline int DEFAULT_DPI = 96; - HRESULT GetScreenDPIForWindow(HWND hwnd, UINT& dpi_x, UINT& dpi_y); - HRESULT GetScreenDPIForPoint(POINT p, UINT& dpi_x, UINT& dpi_y); + HRESULT GetScreenDPIForMonitor(HMONITOR targetMonitor, UINT& dpi); + HRESULT GetScreenDPIForWindow(HWND hwnd, UINT& dpi); + HRESULT GetScreenDPIForPoint(POINT p, UINT& dpi); + HRESULT GetScreenDPIForCursor(UINT& dpi); void Convert(HMONITOR monitor_handle, int& width, int& height); void ConvertByCursorPosition(int& width, int& height); void InverseConvert(HMONITOR monitor_handle, int& width, int& height); diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp index 2265a917d9..ec285fccb8 100644 --- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp +++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp @@ -23,6 +23,8 @@ using namespace winrt::Windows::Foundation; +static UINT g_currentDPI = DPIAware::DEFAULT_DPI; + LRESULT CALLBACK EditKeyboardWindowProc(HWND, UINT, WPARAM, LPARAM); // This Hwnd will be the window handler for the Xaml Island: A child window that contains Xaml. @@ -144,6 +146,7 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KeyboardManagerState& int windowHeight = KeyboardManagerConstants::DefaultEditKeyboardWindowHeight; DPIAware::ConvertByCursorPosition(windowWidth, windowHeight); + DPIAware::GetScreenDPIForCursor(g_currentDPI); // Window Creation HWND _hWndEditKeyboardWindow = CreateWindow( @@ -385,47 +388,62 @@ void CreateEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan TerminateProcess(GetCurrentProcess(), 0); } -inline std::wstring getMessage(UINT messageCode) -{ - switch (messageCode) - { - case WM_SIZE: - return L"WM_SIZE"; - case WM_NCDESTROY: - return L"WM_NCDESTROY"; - default: - return L""; - } -} - LRESULT CALLBACK EditKeyboardWindowProc(HWND hWnd, UINT messageCode, WPARAM wParam, LPARAM lParam) { - RECT rcClient; - auto message = getMessage(messageCode); - if (message != L"") - { - Logger::trace(L"EditKeyboardWindowProc() messageCode={}", getMessage(messageCode)); - } - switch (messageCode) { // Resize the XAML window whenever the parent window is painted or resized case WM_PAINT: case WM_SIZE: { - GetClientRect(hWnd, &rcClient); - SetWindowPos(hWndXamlIslandEditKeyboardWindow, 0, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom, SWP_SHOWWINDOW); + RECT rect = { 0 }; + GetClientRect(hWnd, &rect); + SetWindowPos(hWndXamlIslandEditKeyboardWindow, 0, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW); } break; // To avoid UI elements overlapping on making the window smaller enforce a minimum window size case WM_GETMINMAXINFO: { - LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; + LPMINMAXINFO mmi = (LPMINMAXINFO)lParam; int minWidth = KeyboardManagerConstants::MinimumEditKeyboardWindowWidth; int minHeight = KeyboardManagerConstants::MinimumEditKeyboardWindowHeight; DPIAware::Convert(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONULL), minWidth, minHeight); - lpMMI->ptMinTrackSize.x = minWidth; - lpMMI->ptMinTrackSize.y = minHeight; + mmi->ptMinTrackSize.x = minWidth; + mmi->ptMinTrackSize.y = minHeight; + } + break; + case WM_GETDPISCALEDSIZE: + { + UINT newDPI = static_cast(wParam); + SIZE* size = reinterpret_cast(lParam); + Logger::trace(L"WM_GETDPISCALEDSIZE: DPI {} size X {} Y {}", newDPI, size->cx, size->cy); + + float scalingFactor = static_cast(newDPI) / g_currentDPI; + Logger::trace(L"WM_GETDPISCALEDSIZE: scaling factor {}", scalingFactor); + + size->cx = static_cast(size->cx * scalingFactor); + size->cy = static_cast(size->cy * scalingFactor); + + return 1; + } + break; + case WM_DPICHANGED: + { + UINT newDPI = static_cast(LOWORD(wParam)); + g_currentDPI = newDPI; + + RECT* rect = reinterpret_cast(lParam); + SetWindowPos( + hWnd, + nullptr, + rect->left, + rect->top, + rect->right - rect->left, + rect->bottom - rect->top, + SWP_NOZORDER | SWP_NOACTIVATE + ); + + Logger::trace(L"WM_DPICHANGED: new dpi {} rect {} {} ", newDPI, rect->right - rect->left, rect->bottom - rect->top); } break; default: diff --git a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditShortcutsWindow.cpp b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditShortcutsWindow.cpp index f850c156b7..5bc7551024 100644 --- a/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditShortcutsWindow.cpp +++ b/src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditShortcutsWindow.cpp @@ -18,6 +18,8 @@ using namespace winrt::Windows::Foundation; +static UINT g_currentDPI = DPIAware::DEFAULT_DPI; + LRESULT CALLBACK EditShortcutsWindowProc(HWND, UINT, WPARAM, LPARAM); // This Hwnd will be the window handler for the Xaml Island: A child window that contains Xaml. @@ -96,6 +98,7 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KeyboardManagerState& int windowWidth = KeyboardManagerConstants::DefaultEditShortcutsWindowWidth; int windowHeight = KeyboardManagerConstants::DefaultEditShortcutsWindowHeight; DPIAware::ConvertByCursorPosition(windowWidth, windowHeight); + DPIAware::GetScreenDPIForCursor(g_currentDPI); // Window Creation HWND _hWndEditShortcutsWindow = CreateWindow( @@ -360,26 +363,60 @@ void CreateEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa LRESULT CALLBACK EditShortcutsWindowProc(HWND hWnd, UINT messageCode, WPARAM wParam, LPARAM lParam) { - RECT rcClient; switch (messageCode) { // Resize the XAML window whenever the parent window is painted or resized case WM_PAINT: case WM_SIZE: { - GetClientRect(hWnd, &rcClient); - SetWindowPos(hWndXamlIslandEditShortcutsWindow, 0, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom, SWP_SHOWWINDOW); + RECT rect = { 0 }; + GetClientRect(hWnd, &rect); + SetWindowPos(hWndXamlIslandEditShortcutsWindow, 0, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW); } break; // To avoid UI elements overlapping on making the window smaller enforce a minimum window size case WM_GETMINMAXINFO: { - LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; + LPMINMAXINFO mmi = (LPMINMAXINFO)lParam; int minWidth = KeyboardManagerConstants::MinimumEditShortcutsWindowWidth; int minHeight = KeyboardManagerConstants::MinimumEditShortcutsWindowHeight; DPIAware::Convert(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONULL), minWidth, minHeight); - lpMMI->ptMinTrackSize.x = minWidth; - lpMMI->ptMinTrackSize.y = minHeight; + mmi->ptMinTrackSize.x = minWidth; + mmi->ptMinTrackSize.y = minHeight; + } + break; + case WM_GETDPISCALEDSIZE: + { + UINT newDPI = static_cast(wParam); + SIZE* size = reinterpret_cast(lParam); + Logger::trace(L"WM_GETDPISCALEDSIZE: DPI {} size X {} Y {}", newDPI, size->cx, size->cy); + + float scalingFactor = static_cast(newDPI) / g_currentDPI; + Logger::trace(L"WM_GETDPISCALEDSIZE: scaling factor {}", scalingFactor); + + size->cx = static_cast(size->cx * scalingFactor); + size->cy = static_cast(size->cy * scalingFactor); + + return 1; + } + break; + case WM_DPICHANGED: + { + UINT newDPI = static_cast(LOWORD(wParam)); + g_currentDPI = newDPI; + + RECT* rect = reinterpret_cast(lParam); + SetWindowPos( + hWnd, + nullptr, + rect->left, + rect->top, + rect->right - rect->left, + rect->bottom - rect->top, + SWP_NOZORDER | SWP_NOACTIVATE + ); + + Logger::trace(L"WM_DPICHANGED: new dpi {} rect {} {} ", newDPI, rect->right - rect->left, rect->bottom - rect->top); } break; default: diff --git a/src/modules/keyboardmanager/common/KeyboardManagerConstants.h b/src/modules/keyboardmanager/common/KeyboardManagerConstants.h index 9e925d7c3a..dfbd07f691 100644 --- a/src/modules/keyboardmanager/common/KeyboardManagerConstants.h +++ b/src/modules/keyboardmanager/common/KeyboardManagerConstants.h @@ -50,13 +50,22 @@ namespace KeyboardManagerConstants // Default window sizes inline const int DefaultEditKeyboardWindowWidth = 800; inline const int DefaultEditKeyboardWindowHeight = 600; - inline const int MinimumEditKeyboardWindowWidth = 500; - inline const int MinimumEditKeyboardWindowHeight = 450; + + // Increasing the min size can cause issues when moving the window between + // monitors with different DPI scaling factor + inline const int MinimumEditKeyboardWindowWidth = 200; + inline const int MinimumEditKeyboardWindowHeight = 200; + inline const int EditKeyboardTableMinWidth = 700; + inline const int DefaultEditShortcutsWindowWidth = 1050; inline const int DefaultEditShortcutsWindowHeight = 600; - inline const int MinimumEditShortcutsWindowWidth = 500; - inline const int MinimumEditShortcutsWindowHeight = 500; + + // Increasing the min size can cause issues when moving the window between + // monitors with different DPI scaling factor + inline const int MinimumEditShortcutsWindowWidth = 200; + inline const int MinimumEditShortcutsWindowHeight = 200; + inline const int EditShortcutsTableMinWidth = 1000; // Key Remap table constants diff --git a/src/modules/powerrename/ui/PowerRenameUI.cpp b/src/modules/powerrename/ui/PowerRenameUI.cpp index 7f063b49f1..55964d8b90 100644 --- a/src/modules/powerrename/ui/PowerRenameUI.cpp +++ b/src/modules/powerrename/ui/PowerRenameUI.cpp @@ -667,8 +667,7 @@ void CPowerRenameUI::_OnInitDlg() m_initialWidth = RECT_WIDTH(rc); m_initialHeight = RECT_HEIGHT(rc); - UINT dummy = 0; - DPIAware::GetScreenDPIForWindow(m_hwnd, m_initialDPI, dummy); + DPIAware::GetScreenDPIForWindow(m_hwnd, m_initialDPI); for (UINT u = 0; u < ARRAYSIZE(g_repositionMap); u++) { @@ -887,8 +886,8 @@ void CPowerRenameUI::_MoveControl(_In_ DWORD id, _In_ DWORD repositionFlags) int width = rcWindow.right - rcWindow.left; int height = rcWindow.bottom - rcWindow.top; - UINT currentDPI = 0, dummy; - DPIAware::GetScreenDPIForWindow(m_hwnd, currentDPI, dummy); + UINT currentDPI = 0; + DPIAware::GetScreenDPIForWindow(m_hwnd, currentDPI); float scale = (float)currentDPI / m_initialDPI; switch (id)