У меня есть следующая процедура перехвата мыши (упрощенная для объяснения).
SetWindowsHookEx(WH_MOUSE_LL, mouseHookProc, GetModuleHandle(NULL), 0) ;
LRESULT mouseHookProc(int code, WPARAM wParam, LPARAM lParam){
if(code==HC_ACTION){
const auto& data = *(MSLLHOOKSTRUCT*)lParam ;
data.pt ; //This point gives physical coordinates. It ignores the monitor's scaling factor.
//https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-msllhookstruct
}
return CallNextHookEx(NULL, code, wParam, lParam) ;
}
Координаты мыши, которые я получаю от перехватчика, не регулируются коэффициентом масштабирования монитора. Независимо от того, устанавливаю ли я коэффициент масштабирования монитора на 100% или 200%, крючок мыши всегда дает мне физические пиксели.
С другой стороны, функция GetCursorPos
winapi выдает координаты в логических пикселях. т.е. если коэффициент масштабирования равен 200%, GetCursorPos
даст координаты, разделенные на 2, тогда как крючок мыши даст числа без корректировки.
Согласно этому: https://docs.microsoft.com/en-us/windows/win32/api/shellscalingapi/ne-shellscalingapi-process_dpi_awareness
если программа НЕ поддерживает DPI, система компенсирует коэффициент масштабирования, чтобы программа продолжала работать, как будто ничего не произошло.
Именно это происходит с возвращенным значением GetCursorPos
. Это дает логические пиксели, а не физические.
С другой стороны, процедура подключения мыши не регулируется системой.
Я попытался настроить свою программу как не поддерживающую DPI в manifest, с этим:
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">unaware</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
Но это не имеет значения. Я также попытался объявить его как поддерживающий DPI, вот так:
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<dpiAware>True/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
И это тоже не имело никакого значения.
Есть ли какие-то настройки, которые я могу добавить в свою программу, либо через манифест или иначе, что заставит процедуру перехвата мыши давать логические координаты, как GetCursorPos
?
Я тестирую все это в Windows 10.
ПОСЛЕДУЮЩИЕ:
Я обнаружил проблему. Мой файл манифеста был неверным. Пространства имен XML не были установлены должным образом.
Вот тот, который работает.
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity version="1.0.0.0" name="AppName" type="win32"/>
<asmv3:application>
<asmv3:windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
Чтобы система давала программе логические координаты, программа должна быть С учетом DPI. Программы, в которых отсутствует поддержка DPI, будут обрабатывать координаты непоследовательно повсюду, не только на крючке мыши, но и в BitBlt, IAccesibility, UIAutomation и т. Д. c.
Я не понимаю, почему Microsoft решила сделать это наоборот. Программы, в которых отсутствует поддержка DPI, должны вести себя как обычно, а не наоборот.
Это означает, что всякий раз, когда на мониторе установлен коэффициент масштабирования, большинство программ по умолчанию перестают работать. Чтобы их разблокировать, они должны быть осведомлены о DPI и ... вот так ... они снова будут работать.