DPIスケーリング

DPIスケーリングは、オペレーティングシステムまたはアプリケーションによって実行される機能で、ディスプレイの「ドット/インチ」設定に比例してコンテンツの視覚的サイズを拡大する。一般的には、ディスプレイ解像度の異なるシステム上でも同じ物理的サイズでコンテンツを表示したり、少なくとも非常に高解像度のディスプレイでも使用できるようにする。コンテンツをより大きく快適に読むために、DPI設定を大きくすることがある。

A_ScreenDPIは、プライマリ画面の DPI 設定を返す。

AutoHotkeyに関連するDPIスケーリングには2種類あります:GUI DPIスケーリングとOS DPIスケーリング。

GUI DPIスケーリング

自動スケーリングは、デフォルトでGuiとGuiControlのメソッド/プロパティによって実行されるため、ハードコードされた位置、サイズ、マージンを持つGUIスクリプトは、高DPIスクリーン上で適切にスケーリングされる傾向があります。これがスクリプトの邪魔になる場合、あるいはスクリプトが独自のスケーリングを行う場合は、自動スケーリングを無効にすることができる。詳細は-DPIScaleオプションを参照。

OSのDPIスケーリング

DPIを意識していないアプリケーションの場合、オペレーティング・システムは、特定のシステム関数に渡されたり返されたりする座標を自動的にスケーリングします。このタイプのスケーリングは、すべてのスクリーンのDPI設定が同じでない複数のスクリーンを持つシステムでのみAutoHotkeyに影響します。

モニターごとのDPI認識

Windows 8.1以降では、セカンダリスクリーンは異なるDPI設定を持つことができ、"per-monitor DPI-aware"アプリケーションは、ウィンドウがスクリーン間を移動するときに動的に適応し、現在表示されているスクリーンのDPIに従ってウィンドウを拡大縮小することが期待されています。

モニターごとのDPIを意識しないアプリケーションの場合、システムはビットマップのスケーリングを実行し、ウィンドウがスクリーン間を移動するときにサイズを変更できるようにします。そして、アプリケーションが期待するグローバルDPI設定にスケーリングされた座標とサイズを報告することで、アプリケーションからこれを隠します。例えば、11インチの4Kスクリーンでは、96dpi(100%)で表示するようにデザインされたGUIはほとんど使用不可能だが、200%アップスケールすれば使用可能になる。

AutoHotkeyはモニターごとのスケーリングを行うようには設計されていないため、モニターごとのDPIを認識するようにマークされていません。これは、たとえば、GUIウィンドウを100 %のDPIを持つ大きな外部スクリーンと200 %のDPIを持つ小さなスクリーンの間で移動させるときに便利です。しかし、自動スケーリングには否定的な意味合いもある。

システムの自動スケーリングが機能するように、MoveWindowGetWindowRectなどのシステム関数は、それらが受け取るか返す座標を自動的にスケーリングします。AutoHotkeyがこれらの関数を使用して外部ウィンドウを操作する場合、座標がプライマリスクリーン上にない場合、しばしば予期しない結果が生じます。さらに混乱を招くことに、いくつかの関数は、スクリプトの最後にアクティブになったウィンドウがどのスクリーンに表示されていたかに基づいて座標をスケーリングする。

回避策

Windows 10のバージョン1607以降では、SetThreadDpiAwarenessContextシステム関数を使用して、実行時にプログラムのDPI認識設定を変更できます。たとえば、モニターごとのDPI認識を有効にすると、システムによるスケーリングが無効になるため、WinMoveWinGetPosなどの組み込み関数は、DPIスケーリングに影響されずにピクセル単位の座標を受け取ったり返したりします。しかし、GUIが100 %のDPIのスクリーン用にサイズ調整され、その後200 %のDPIのスクリーンに移動した場合、自動的に調整されず、非常に使いにくくなる可能性があります。

モニターごとのDPI認識を有効にするには、通常DPIスケーリングの影響を受ける関数を使用する前に、以下の関数を呼び出します:

DllCall("SetThreadDpiAwarenessContext", "ptr", -3, "ptr")

Windows 10のバージョン1703以降では、-3を-4に置き換えて「Per Monitor v2」モードを有効にすることができます。これにより、ダイアログやメニュー、ツールチップなどの拡大縮小が可能になります。しかし、非クライアント領域(タイトル・バー)も拡大縮小されるため、スクリプトが(WM_DPICHANGEDメッセージに応答するなどして)調整するように設計されていない限り、ウィンドウのクライアント領域が小さくなりすぎる可能性があります。これは、GUIを作成する前にコンテキストを-3に設定し、ツールチップ、メニュー、ダイアログを作成する前に-4に設定することで回避できます。

ユーザーがスクリプトのウィンドウを移動しているときや、スクリプトがダイアログを表示しているときに、スレッドのDPI認識が一時的に変更されることがあります。そのため、DPIに依存する機能を使用する前に、DPIを設定するのが最も安全です。

コンパイル済みスクリプト

モニタごとの DPI 認識は、コンパイルされたスクリプトのマニフェストリソースの <dpiAware>要素の内容をtrue(基本のAutoHotkey実行ファイルに設定されているデフォルト)からtrue/pmに変更することで、プロセス全体で有効にすることができます。