C++实现显示器刷新率变化的非轮询式检测(Windows/Android)
编程检测显示器刷新率变化(无需持续轮询)
可以实现无需持续轮询的显示器刷新率变化检测,以下是Windows和Android平台的具体方案:
Windows平台
方法1:处理WM_DISPLAYCHANGE消息
你之前提到的WM_DISPLAYCHANGE并非仅检测分辨率变化——显示器刷新率变更时系统同样会发送该消息。只需在窗口过程中捕获此消息,再单次调用EnumDisplaySettings获取当前刷新率即可,无需轮询:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DISPLAYCHANGE: { DEVMODE dm = {0}; dm.dmSize = sizeof(DEVMODE); if (EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &dm)) { DWORD currentRefreshRate = dm.dmDisplayFrequency; // 在这里处理刷新率变化的业务逻辑 } break; } // 其他消息处理逻辑... } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
方法2:Display Config回调(Windows 10+)
如果需要更精准的显示配置变更通知,可使用Windows 10及以上提供的Display Config API,通过注册回调实现无轮询检测:
- 实现
IDisplayConfigCallback接口,重写OnDisplayConfigChanged方法——该方法会在显示配置(包括刷新率)变更时触发。 - 调用
RegisterDisplayConfigChangeNotification注册回调,指定监听范围(单个设备或所有设备)。 - 不再需要时调用
UnregisterDisplayConfigChangeNotification注销。
核心代码示例:
class DisplayConfigCallback : public IDisplayConfigCallback { public: HRESULT STDMETHODCALLTYPE OnDisplayConfigChanged( DISPLAY_CONFIG_TOPOLOGY_ID newTopologyId, DISPLAY_CONFIG_PATH_INFO* pathArray, UINT32 pathCount, DISPLAY_CONFIG_MODE_INFO* modeArray, UINT32 modeCount) override { // 遍历modeArray可获取各显示器的最新刷新率参数 // 处理刷新率变化逻辑 return S_OK; } // 实现IUnknown接口的基础方法 ULONG STDMETHODCALLTYPE AddRef() override { return 1; } ULONG STDMETHODCALLTYPE Release() override { return 0; } HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override { if (riid == IID_IDisplayConfigCallback || riid == IID_IUnknown) { *ppvObject = this; return S_OK; } return E_NOINTERFACE; } }; // 注册回调 DisplayConfigCallback callback; LARGE_INTEGER notificationCookie; HRESULT hr = RegisterDisplayConfigChangeNotification(&callback, ¬ificationCookie);
Android平台
方法1:DisplayManager.DisplayListener监听
通过系统的DisplayManager注册显示器状态监听器,当显示器参数(包括刷新率)变更时会触发回调:
DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE); DisplayListener displayListener = new DisplayListener() { @Override public void onDisplayAdded(int displayId) {} @Override public void onDisplayRemoved(int displayId) {} @Override public void onDisplayChanged(int displayId) { Display targetDisplay = displayManager.getDisplay(displayId); if (targetDisplay != null) { float currentRefreshRate = targetDisplay.getRefreshRate(); // 处理刷新率变化逻辑 } } }; // 注册监听 displayManager.registerDisplayListener(displayListener, null); // 不再需要时注销监听 // displayManager.unregisterDisplayListener(displayListener);
方法2:监听系统设置变更
通过ContentObserver监听系统刷新率设置的变更,适合关注系统全局刷新率调整的场景:
ContentObserver refreshRateObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); float currentRefreshRate = Settings.System.getFloat( getContentResolver(), Settings.System.REFRESH_RATE, 60.0f); // 默认值60Hz // 处理刷新率变化逻辑 } }; // 注册观察者 getContentResolver().registerContentObserver( Settings.System.getUriFor(Settings.System.REFRESH_RATE), false, refreshRateObserver); // 注销观察者 // getContentResolver().unregisterContentObserver(refreshRateObserver);
内容的提问来源于stack exchange,提问作者iexav
相关产品推荐
相关产品推荐

