windows應用程序高分屏適配之座標系--多屏場景

  windows系統下爲了滿足不同場景的應用,座標系主要分爲兩類:邏輯座標系和設備座標系,一般而言GDI的文本和圖形處理使用邏輯座標系,而窗口以及鼠標的移動一般採用設備座標系進行管理。

邏輯座標系

  邏輯座標系是面向GDI繪製是主要使用的對象DC(Device Context)應用,這種座標系不考慮設備的具體類型,在繪製圖形和文字時,windows會根據當前設置的映射模式將邏輯座標自動轉爲設備座標。

設備座標系

  設備座標是面向物理設備的座標系,比如顯示器,打印機等,這種座標以像素或者設備所能表示的最小度量單位爲基本單位。這種座標系採用向下向右爲正,橫向爲x軸方向,縱向爲y軸方向,座標原點根據
具體的設備鏈接和設置的不同存在一定差異。其中設備座標系又可細分爲屏幕座標系、窗口座標系和客戶區座標系三種相互獨立的座標系。三種座標系示意圖如下圖所示。

window座標系示意圖

  • 1.屏幕座標系

      屏幕座標系是以主屏幕左上角爲座標原點,向右向下爲正,見上圖黑色字體。在多屏場景中,windows系統存在主副屏概念
    ,當前顯示器的標識和是否爲主屏可以通過[win7:桌面下鼠標右鍵->屏幕分辨率->設爲主顯示器]、[win10:設置->顯示->設置爲主顯示器]進行主顯示器設置,與此同時,當不清楚當前顯示器具體位置時可以通過點擊標識按鈕,
    系統將會在每個顯示器界面上標識出1,2,…的數字字樣。同時可以通過拖動虛擬顯示器位置改變顯示器在屏幕座標系的位置。
      當主屏在其他屏幕的左上側時,此時屏幕上所顯示的位置在屏幕座標系的座標均爲正值,當一個顯示器位於屏幕主顯示器的左上角時,該顯示器的點在座標系中的位置存在負值。具體來說,當屏幕位於主顯示器左側時,
    x軸值爲負值,當顯示器位於主顯示器上側時,y軸座標系爲負值。一些與整個屏幕有關的函數均採用屏幕座標系,如:GetCursorPos()、SetCursorPos()、CreateWindow()、MoveWindow()等。

  • 2.窗口座標系

      窗口座標系與屏幕座標系相似,不同的是窗口座標系是以當前窗口的左上角爲座標系的原點,向右向下爲正。窗口包括標題欄、菜單欄、工具欄以及客戶區等。座標軸如上圖所示。

  • 3.客戶區座標系

      在窗口的大部分區域也即是客戶區,客戶區座標系比窗口座標系更加細化,如上圖所示。在該區域是窗口主要功能的展示區,其中包括客戶區的繪圖輸出和窗口消息的處理等。

  本文主要記錄在多屏場景中屏幕座標系相關內容,尤其是高分屏場景的適配場景。

  在介紹高分屏適配之前需要了解2個概念,也即是DPI和DWM。其中DPI也即是(Dots Per Inch)每英寸像素點數量,在顯示器上就是每英寸的像素個數,Window上一般默認是96 dpi 作爲100% 的縮放比率,其他平臺略有不同,例如mac端默認爲72。
在windows系統中爲了滿足不同DPI屏幕顯示自適應縮放,保證應用程序界面在不同的DPI顯示器下正常顯示,關於高DPI的支持, Windows XP時代就開始有了,
那時關於高DPI的支持比較簡單,僅僅通過手動設置的方式進行文字或圖片顯示比例的調整,
但是從Vista/Win7 到現在Win8 /Win8.1, Windows關於高DPI的支持已經發生了很大的變化,也就是我們需要了解的另外一個概念DWM。

  DWM(Desktop Window Manager),該技術其實是用於實現當應用程序不能進行高DPI適應或者未禁止DWM虛擬化時,系統自動通過DWM進行調整,具體來說就是應用程序不需要自己實現不同分辨率顯示器的文字或圖片的縮放,只需要按照相同的處理邏輯按照100%顯示比例進行應用程序界面的繪製,在最終顯示之前系統會通過DWM自動將應用程序進行縮放,保證同樣一個應用程序在1080p顯示器上能看到正常的畫面,但是在4K屏上就變的極其小的情況。
  對於win8.1以上系統DPI設置可以根據不同的需要設置當前應用程序是否開啓DPI感知,以及開啓DPI感知的具體級別。

typedef enum _Process_DPI_Awareness {
  Process_DPI_Unaware            = 0,
  Process_System_DPI_Aware       = 1,
  Process_Per_Monitor_DPI_Aware  = 2
} Process_DPI_Awareness;

  第一種Unaware, 該種方式是告訴系統, 我的程序不支持DPI aware, 請通過DWM虛擬化幫我們實現。 該方式通過GetWindowRect取到的座標都是經過DWM縮放後的, 無論對方窗口是不是支持DWM虛擬化。

  第二種方式是System DPI aware, 該方式下告訴系統, 我的程序會在啓動的顯示器上自己支持DPI aware, 所以不需要對我進行DWM 虛擬化。 但是當我的程序被拖動到其他DPI不一樣的顯示器時, 請對我們先進行system DWM虛擬化縮放。

  第三種方式是Per Monitor DPI aware, 該方式是告訴系統, 請永遠不要對我進行DWM虛擬化,我會自己針對不同的Monitor的DPi縮放比率進行縮放。 這種方式需要自己完成對高DPI的支持。
chrome 是設置的Per Monitor DPI aware 猜測其UI應該自己內部實現了對高DPI的支持,基於CEF的開發 建議設置System DPI aware 來完成對高DPI的支持。

  在windows8.1以上系統可以通過以下API獲取或設置系統DPI相關的信息:

GetDpiForMonitor	    # Queries the DPI information associated with a monitor.
GetDpiForSystem	        # Returns the system DPI.
GetDpiForWindow	        # Returns the current DPI for the specified window.
GetProcessDpiAwareness	# Retrieves the DPI virtualization mode of the specified process.
GetSystemMetricsForDpi	# A variant of GetSystemMetrics that returns values scaled to a specific DPI.
SetProcessDpiAwareness	# Sets the DPI virtualization mode for the current process.
GetSystemDpiForProcess	# Retrieves the system DPI associated with a given process.

更多詳細的函數信息,可以參閱這個鏈接:https://docs.microsoft.com/zh-cn/windows/win32/hidpi/high-dpi-reference

就先記錄到這裏吧,下篇我們將整理一下windows高DPI下鼠標座標相關問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章