在Java中检测显示器背光开启事件(Windows 8.1环境)
在Java中检测Windows 8.1显示器背光状态的方法
Java标准库本身没有提供直接检测显示器背光状态的API,不过我们可以通过调用Windows原生系统API来实现这个需求,最便捷的方式是使用JNA(Java Native Access)库——它能让我们不用编写C/C++代码就能直接调用Windows的DLL函数。
核心思路
Windows系统会在电源状态(包括显示器背光)变化时广播WM_POWERBROADCAST消息,我们可以监听这个消息来捕获显示器从关闭到开启的事件;另外也可以通过轮询的方式主动查询显示器的电源状态。下面分别介绍这两种方案:
方案一:监听系统电源广播消息(推荐,高效)
这种方式能实时捕获显示器状态变化,不需要轮询,步骤如下:
- 引入JNA依赖
如果用Maven管理项目,添加以下依赖到pom.xml:
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.13.0</version> </dependency>
- 编写代码监听电源消息
我们需要创建一个隐藏的Windows窗口来接收系统广播的电源消息,然后在消息回调中处理显示器开启事件:
import com.sun.jna.Native; import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.WinDef; import com.sun.jna.platform.win32.WinUser; public class MonitorPowerListener { // 显示器电源状态对应的系统GUID private static final String GUID_MONITOR_POWER_ON = "02731015-4510-4526-99E6-E5A17EBD1AEA"; public static void main(String[] args) { // 注册窗口类,用于接收系统消息 WinUser.WNDCLASSEX wClass = new WinUser.WNDCLASSEX(); wClass.lpfnWndProc = new WinUser.WindowProc() { @Override public WinDef.LRESULT callback(WinDef.HWND hwnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) { // 处理电源广播消息 if (uMsg == WinUser.WM_POWERBROADCAST) { if (wParam.intValue() == WinUser.PBT_POWERSETTINGCHANGE) { WinUser.POWERBROADCAST_SETTING setting = new WinUser.POWERBROADCAST_SETTING(lParam); // 判断是否是显示器电源状态变化 if (GUID_MONITOR_POWER_ON.equals(setting.PowerSetting.toString())) { // Data[0]的值:0=关闭,1=开启,2=待机 int powerState = setting.Data[0]; if (powerState == 1) { // 显示器已开启,执行自定义函数 onMonitorTurnedOn(); } } } return new WinDef.LRESULT(1); // 告知系统已处理该消息 } return User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam); } }; wClass.lpszClassName = Native.malloc(100); Native.setWideString(wClass.lpszClassName, "MonitorPowerListenerClass"); User32.INSTANCE.RegisterClassEx(wClass); WinDef.HWND hwnd = User32.INSTANCE.CreateWindowEx(0, wClass.lpszClassName, "MonitorPowerListener", 0, 0, 0, 0, 0, null, null, null, null); // 注册监听显示器电源设置变化 WinDef.GUID guid = new WinDef.GUID(GUID_MONITOR_POWER_ON); User32.INSTANCE.RegisterPowerSettingNotification(hwnd, guid, 0); // 启动消息循环,保持程序运行以接收消息 WinUser.MSG msg = new WinUser.MSG(); while (User32.INSTANCE.GetMessage(msg, null, 0, 0) != 0) { User32.INSTANCE.TranslateMessage(msg); User32.INSTANCE.DispatchMessage(msg); } // 清理资源 User32.INSTANCE.UnregisterClass(wClass.lpszClassName, null); Native.free(wClass.lpszClassName); } // 自定义的显示器开启时执行的函数 private static void onMonitorTurnedOn() { System.out.println("显示器已开启,执行指定操作..."); // 这里替换成你的业务逻辑代码 } }
方案二:轮询查询显示器状态(简单,适合小型程序)
如果不想处理复杂的消息监听,可以每隔一段时间主动查询显示器的电源状态:
import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.WinDef; import com.sun.jna.ptr.IntByReference; public class MonitorPowerPoller { // 显示器电源状态常量:1=开启,3=关闭 private static final int MONITOR_ON = 1; private static final int MONITOR_OFF = 3; public static void main(String[] args) throws InterruptedException { boolean wasOff = false; // 每隔1秒查询一次状态(可根据需求调整间隔) while (true) { WinDef.HWND desktopHwnd = User32.INSTANCE.GetDesktopWindow(); IntByReference powerState = new IntByReference(); if (User32.INSTANCE.GetMonitorPowerState(desktopHwnd, powerState)) { int currentState = powerState.getValue(); // 判断是否是从关闭变为开启 if (wasOff && currentState == MONITOR_ON) { onMonitorTurnedOn(); wasOff = false; } else if (currentState == MONITOR_OFF) { wasOff = true; } } Thread.sleep(1000); } } private static void onMonitorTurnedOn() { System.out.println("显示器已开启,执行指定操作..."); // 这里替换成你的业务逻辑代码 } }
注意事项
- 以上代码仅适用于Windows系统,在其他操作系统上无法运行;
- 确保JNA依赖版本正确,避免出现兼容性问题;
- 监听消息的方式需要保持消息循环运行,否则无法接收系统广播;
- 轮询间隔越小越灵敏,但会消耗更多CPU资源,建议根据实际需求调整。
内容的提问来源于stack exchange,提问作者user9566632
相关产品推荐
相关产品推荐

