Преобразование HIMETRIC в пиксели в среде с несколькими DPI

Моя структура пользовательского интерфейса использует двойные значения для координат пикселей, что дает мне хорошие дробные виртуальные координаты на дисплеях Retina. Для этого я получаю координаты мыши из Windows в единицах HIMETRIC. Однако я столкнулся с ошибкой, которую не могу понять.

У меня есть Surface Book 2 (3000x2000 @ 225%), подключенный к док-станции с двумя внешними мониторами (1920x1080 @ 100%). Если я вхожу в Windows с подключенной док-станцией (и внешний монитор @ 100% установлен в качестве основного), я получаю правильные координаты HIMETRIC, которые работают как на внешнем дисплее, так и на дисплее сетчатки.

Однако, если я войду в Windows, когда док-станция отключена, так что есть только монитор Retina, затем подключу док-станцию, затем запущу свое приложение — теперь оно получает координаты HIMETRIC, масштабированные по коэффициент масштабирования дисплея, который был основным при входе в Windows.

Я установил осведомленность о DPI моего приложения на PerMonitorV2, поэтому я нахожу настолько странным, что настройка масштаба DPI для каждой системы даже имеет отношение к моему приложению.

Это функция, которую я использую для преобразования из HIMETRIC:

double fromHimetric(uint i)
{
    return (double)i / 2540 * Monitor::DefaultDPI; 
}

Monitor::DefaultDPI — константа, равная 96.

Я что-то пропустил? Нужно ли добавлять в формулу коэффициент масштабирования системы? В таком случае, как я могу узнать, какой монитор был основным при входе в Windows? Потому что это, кажется, остается постоянным независимо от того, на какой монитор я перемещаю свое окно, поскольку я получаю значения HIMETRIC, которые, по-видимому, масштабируются значением из прошлого.

Редактировать: поскольку работу с несколькими мониторами сложно описать в Интернете, я снял небольшое видео, показывающее, как эта ошибка проявляется у меня. https://www.youtube.com/watch?v=pTZiTZFXsc0

Редактировать 2: чтобы еще больше уточнить, мое приложение полностью учитывает DPI для каждого монитора, весь мой пользовательский интерфейс векторен, поэтому он правильно масштабируется, я обрабатываю WM_DISPLAYCHANGE и WM_DPICHANGED и все такое прочее. Координаты пера и касания работают нормально во всех случаях.

Единственное, что ломается, если я изначально запускаю свой компьютер без пристыковки, это то, что координаты HIMETRIC, которые я получаю для мыши от GetPointerInfo(), масштабируются по масштабу дисплея монитора, который был основным при запуске компьютера.

Я много работал, чтобы убедиться, что я ХОРОШО справляюсь с ситуациями с несколькими мониторами и несколькими DPI. Я буду чувствовать себя очень глупо, если я проглядел простую вещь, которая ломает все.

Изменить 3. Посмотрите, насколько велики полосы прокрутки в Chrome. https://imgur.com/a/F3dFHAj

Или студия OBS: https://imgur.com/a/11aG5Kw

Кажется, они страдают от подобных ошибок. Не знаю, имеют ли они какое-либо отношение к HIMETRIC, но эти элементы отображаются по-разному в зависимости от того, как я запускаю компьютер.

Определяет ли Win32 что-то вроде монитора запуска?

Редактировать 4: Причина, по которой я не использую AtlHiMetricToPixel() и PhysicalToLogicalPoint(), заключается в том, что они возвращают целочисленные логические координаты, и мне особенно нужны двойники в логическом пространстве, поскольку весь мой пользовательский интерфейс основан на векторах. Я делаю все масштабирование самостоятельно, и, похоже, все работает нормально, за исключением одного случая. :(


person Alex    schedule 17.10.2018    source источник


Ответы (1)


Для всех, кто когда-либо будет заинтересован в этом, я получил ответ здесь.

DPI основного монитора при входе в сеанс равен

HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics | AppliedDPI

Я проверил это, и это всегда правильно в зависимости от того, как я вхожу в систему. Так что в моем случае мое приложение просто должно прочитать это из реестра при запуске, а затем использовать его для настройки входящих координат HIMETRIC для мыши.

person Alex    schedule 20.09.2019