windows用enumdisplaysettings(传enum_current_settings)获取刷新率,需校验dmsize和返回值;linux用x11 api计算真实刷新率,wayland需协议支持;macos需遍历显示器并筛选当前模式;所有平台均非硬件实时采样,应监听系统事件捕获变更。

Windows平台用EnumDisplaySettings查当前显示器刷新率
Windows下最直接的方式是调用GDI API的EnumDisplaySettings,它能拿到当前活动显示模式的dmDisplayFrequency字段。注意:必须传ENUM_CURRENT_SETTINGS(值为-1),而不是设备名字符串——传空字符串或NULL会导致返回默认/上一次设置,不是实时值。
常见错误是忽略DEVMODE结构体大小校验:dmSize必须设为sizeof(DEVMODE),否则调用失败且不报错;还要检查返回值是否为TRUE,失败时dmDisplayFrequency是未定义值。
- 只对主显示器有效?不对,需先用
EnumDisplayDevices枚举所有显示器,再对每个调用EnumDisplaySettings - 多显示器场景下,每个显示器可能有不同刷新率,不能假设一致
-
dmDisplayFrequency单位是Hz,但某些驱动返回0(如虚拟显示器、远程桌面),需容错处理
Linux上通过xrandr命令解析或X11 API获取
Linux桌面环境通常依赖X11,xrandr --verbose输出里每块输出(output)的当前模式行会带+标识和<code>Hz字样,比如1920x1080+0+0 60.00*+中的60.00就是当前刷新率。程序里可fork+exec读取stdout,但更可靠的是用X11库直接调用XRRGetScreenResources和XRRGetCrtcInfo。
关键点在于:X11的“当前模式”不等于“首选模式”,crtc->mode对应的是实际生效的模式ID,需从resources->modes数组中查找匹配的id,再读其dotClock / (hTotal * vTotal)算出真实刷新率——很多教程直接读mode->name里的数字,但那是名称字符串,不可靠。
- Wayland环境下
xrandr失效,需走xdg-output或wp-output-management协议,目前无统一C++接口 - 部分嵌入式Linux用DRM/KMS,得读
/sys/class/drm/*/modes并解析当前status和mode文件 - 刷新率可能动态切换(如VRR),单次查询只能反映此刻状态
macOS用CGDisplayModeGetRefreshRate获取主屏,多屏需遍历
macOS Core Graphics提供CGDisplayModeGetRefreshRate,但仅对当前活跃显示模式有效。必须先用CGGetActiveDisplayList拿到所有显示器ID,再对每个ID调用CGDisplayCopyAllDisplayModes,遍历结果找CGDisplayModeIsUsable为TRUE且CGDisplayModeGetIOFlags含kCGDisplayModeCurrentFlag的模式——这才是当前正在用的模式。
容易被忽略的是:macOS High Sierra以后支持ProMotion(120Hz),但CGDisplayModeGetRefreshRate对ProMotion屏返回的是标称最大值(如120.0),而非当前动态帧率;真实VRR值需通过I/O Kit监听IOFramebuffer事件,C++层几乎不可行。
- Retina屏的缩放模式不影响刷新率,但
CGDisplayModeGetWidth等返回的是逻辑分辨率,别混淆 - 外接显示器可能报告0.0,尤其是USB-C转接器兼容性差时,需fallback到
CGDisplayModeGetPixelWidth+CGDisplayModeGetRefreshRate组合判断 - 沙盒应用需声明
com.apple.security.device.graphics权限,否则CGGetActiveDisplayList返回空
跨平台封装要注意刷新率“实时性”的本质限制
所有平台的API返回的都是“最近一次显卡驱动提交的模式配置”,不是硬件传感器实时采样值。GPU驱动可能缓存设置、VSync信号抖动、或系统策略延迟生效(如Windows的“自动选择最佳刷新率”开关),所以两次调用间隔短于1秒时,结果大概率不变。
真正需要高频监测的场景(如游戏引擎动态适配),不能依赖反复调用API,而应监听系统事件:Windows用WM_DISPLAYCHANGE,X11监听RandR ScreenChangeNotify,macOS注册CGDisplayRegisterReconfigurationCallback。回调里再查一次,才能确保捕捉到变化。
- 没有跨平台标准库能统一这事,
SDL2的SDL_GetDesktopDisplayMode只返回初始值,不响应运行时变更 - 某些笔记本在合盖/外接屏热插拔后,旧句柄可能失效,需重新枚举设备
- 所谓“实时”其实是“驱动层最后确认的配置”,和显示器面板实际扫描频率可能有±1Hz偏差,尤其低端面板
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











