windows可通过sendmessage向桌面窗口发送sc_monitorpower关闭显示器,linux依赖xset或ddcutil,macos仅支持系统级显示睡眠且受限严格,跨平台无法统一实现。

Windows平台下用SendMessage发送WM_SYSCOMMAND控制显示器
Windows不提供标准API直接开关显示器,但可通过向桌面窗口发送系统命令模拟硬件行为。核心是调用SendMessage向GetDesktopWindow()发送SC_MONITORPOWER指令。
-
SC_MONITORPOWER参数值为0xF170,需配合wParam控制状态:-1(开启)、1(关闭)、2(待机) - 必须在GUI线程中调用,控制台程序需显式创建窗口或使用
FindWindow(L"Shell_TrayWnd", nullptr)替代桌面句柄 - 部分系统(如Win10 2004+)可能忽略该消息,尤其启用了“快速启动”或连接了多显示器时
- 示例代码片段:
HWND hwnd = GetDesktopWindow(); SendMessage(hwnd, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM)2); // 待机
Linux下通过system()调用xset或ddcutil
Linux没有统一内核接口,依赖X11工具链或DDC/CI协议。普通用户权限下xset最常用,但仅对当前X session生效;需要硬件级控制则必须用ddcutil(需root和I2C权限)。
-
xset dpms force off可立即关闭屏幕,但唤醒需移动鼠标或敲击键盘——它只触发DPMS状态,不切断电源 -
ddcutil setvcp 0x10 0x00(亮度设为0)或0xD6 0x01(关闭显示器)才真正断信号,但需显示器支持DDC/CI且已启用 -
system("xset -display :0 dpms force off")中:0必须匹配当前DISPLAY环境变量,否则静默失败 - Wayland会话下
xset完全无效,只能通过swaymsg output ... dpms off(Sway)或hyprctl output ... dpms off(Hyprland)等合成器专用命令
macOS上用IOPowerSources和私有API的现实限制
macOS禁止第三方应用直接控制显示器电源,官方API仅暴露电池与电源状态查询(IOPowerSources),无开关接口。所有“关屏”方案本质都是触发系统级休眠或屏幕保护。
- 调用
CGDisplaySleep(需com.apple.security.device.video权限)可使指定显示器进入睡眠,但仅对外接显示器有效,内置屏会被系统拦截 - 常见hack是执行
pmset displaysleepnow,这实际触发的是整个系统的显示睡眠,且要求用户未禁用“防止自动睡眠”选项 - 任何试图绕过签名验证调用
IODisplayWrangler等私有类的行为,在macOS 12+会触发Hardened Runtime崩溃,日志显示deny mach-lookup - 无法实现“仅关闭显示器而不影响CPU/硬盘”的精细控制——这是Apple刻意设计的限制
跨平台封装要注意的兼容性陷阱
写一个turn_off_display()函数时,别指望同一段逻辑能在三端运行。每个平台的权限模型、生命周期和底层协议差异太大,硬封装只会掩盖问题。
- Windows下若进程以服务方式运行(Session 0),
GetDesktopWindow()返回NULL,必须切换到交互式Session再操作 - Linux脚本路径硬编码
/usr/bin/xset可能失败,应先which xset检测存在性,且需处理DISPLAY为空的场景 - macOS调用
system("pmset ...")会弹出权限提示框,若应用未签名或未在Accessibility列表中授权,命令将被系统静默丢弃 - 没有“安全唤醒”机制——关屏后若用户手动按电源键,系统可能直接关机而非唤醒,这点在嵌入式Kiosk场景中必须提前测试
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











