Last active
February 17, 2024 20:39
-
-
Save jcoester/52817d1fd7b8018e8127b57c56079804 to your computer and use it in GitHub Desktop.
Java: Retrieve current Windows Display Scale during runtime, e.g. 1.0 = 100%, 1.25 = 125%, 1.5 = 150%, 1.75 = 175%, 2.0 = 200%
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.sun.jna.platform.win32.GDI32; | |
import com.sun.jna.platform.win32.WinDef; | |
import java.awt.Toolkit; | |
import java.math.BigDecimal; | |
import java.math.RoundingMode; | |
import java.util.concurrent.Executors; | |
import java.util.concurrent.ScheduledExecutorService; | |
import java.util.concurrent.TimeUnit; | |
/** | |
* This <code>WindowsDisplayScale</code> class retrieves the current <code>Windows Display | |
* Scale</code> throughout a <code>Java</code> applications' runtime, e.g. | |
* <code>1.0 = 100%, 1.25 = 125%, 1.5 = 150%, 1.75 = 175%, 2.0 = 200%</code>. | |
* | |
* <p>It uses <code>Java AWT</code> and the <code>Java Native Access (JNA) platform</code> | |
* to access the <code>Display Device Context (DC)</code> from <code>Microsoft | |
* Windows graphics device interface (GDI)</code></p> | |
* | |
* @implNote Requires <code>net.java.dev.jna.platform (Maven)</code> | |
* <p>Full support for <code>Java 8</code> on <code>Windows 11</code>: Value updates throughout runtime</p> | |
* <p>Partial support for <code>Java 11</code> on <code>Windows 11</code>: Value from application startup</p> | |
* | |
* @author <a href="https://gist.github.com/jcoester/52817d1fd7b8018e8127b57c56079804">jcoester</a> | |
* @author built on previous version from <a href="https://gist.github.com/tresf/00a8ed7c9860e3bd73cebf764a49789f">tresf</a> | |
* @version 1.0 (2024 Feb. 17) | |
*/ | |
public class WindowsDisplayScale { | |
public static void main(String[] args) { | |
// For demonstration: Check Windows Display Scale every 5 seconds | |
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); | |
scheduler.scheduleAtFixedRate(WindowsDisplayScale::update, 0, 5, TimeUnit.SECONDS); | |
} | |
private static void update() { | |
// Retrieval of the Windows Display Scale | |
double scaleDecimal = detectWindowsDisplayScale(); | |
int scalePercentage = (int) (scaleDecimal * 100); | |
// Usage of the Windows Display Scale | |
System.out.println("Windows Display Scale (double): " + scaleDecimal); // e.g. 1.0, 1.25, 1.5, 1.75, 2.0 | |
System.out.println("Windows Display Scale ( int% ): " + scalePercentage); // e.g. 100, 125, 150, 175, 200 | |
System.out.println(); // Easier readability during demonstration | |
} | |
public static double detectWindowsDisplayScale() { | |
/* Retrieve AWT scale | |
* (Detects the Windows Display Scale once during application startup) */ | |
double awtScale = Toolkit.getDefaultToolkit().getScreenResolution() / 96.0f; | |
// Retrieve HDC (Handle to Device Context (DC)) | |
WinDef.HDC hdc = GDI32.INSTANCE.CreateCompatibleDC(null); | |
if (hdc == null) | |
return 0; | |
/* Retrieve HDC Display info | |
* (Detects changes to the Windows Display Scale during the application runtime) */ | |
double a = GDI32.INSTANCE.GetDeviceCaps(hdc, 10); // 10=VERTRES | |
double b = GDI32.INSTANCE.GetDeviceCaps(hdc, 117); // 117=DESKTOPVERTRES | |
GDI32.INSTANCE.DeleteDC(hdc); | |
if (a == 0 || b == 0) | |
return 0; | |
// Offset HDC Vertical pixels with the initial AWT scale | |
b = b * awtScale; | |
// Calculate Windows Display Scale | |
double windowsDisplayScale = a > b ? a / b : b / a; | |
// Round to two decimals and return | |
return BigDecimal.valueOf(windowsDisplayScale).setScale(2, RoundingMode.HALF_UP).doubleValue(); | |
} | |
} |
Author
jcoester
commented
Feb 17, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment