From f053871a6c041292ecc059a8a2a435416f176390 Mon Sep 17 00:00:00 2001 From: "jonathan.r.paton@googlemail.com" Date: Wed, 22 Feb 2017 11:50:42 +0000 Subject: [PATCH] If a window is open, only update joystick connections on WM_DEVICECHANGE message --- src/SFML/Window/Win32/JoystickImpl.cpp | 55 ++++++++++++----------- src/SFML/Window/Win32/JoystickImpl.hpp | 14 ++++++ src/SFML/Window/Win32/WindowImplWin32.cpp | 38 +++++++++++++++- 3 files changed, 80 insertions(+), 27 deletions(-) diff --git a/src/SFML/Window/Win32/JoystickImpl.cpp b/src/SFML/Window/Win32/JoystickImpl.cpp index 7ea5df6d..c6defc6f 100644 --- a/src/SFML/Window/Win32/JoystickImpl.cpp +++ b/src/SFML/Window/Win32/JoystickImpl.cpp @@ -44,10 +44,13 @@ namespace bool connected; sf::Clock timer; }; - const sf::Time connectionRefreshDelay = sf::milliseconds(500); + ConnectionCache connectionCache[sf::Joystick::Count]; + // If true, will only update when WM_DEVICECHANGE message is received + bool lazyUpdates = false; + // Get a system error string from an error code std::string getErrorString(DWORD error) { @@ -150,19 +153,7 @@ namespace priv void JoystickImpl::initialize() { // Perform the initial scan and populate the connection cache - for (unsigned int i = 0; i < Joystick::Count; ++i) - { - ConnectionCache& cache = connectionCache[i]; - - // Check if the joystick is connected - JOYINFOEX joyInfo; - joyInfo.dwSize = sizeof(joyInfo); - joyInfo.dwFlags = 0; - cache.connected = joyGetPosEx(JOYSTICKID1 + i, &joyInfo) == JOYERR_NOERROR; - - // start the timeout - cache.timer.restart(); - } + updateConnections(); } @@ -176,27 +167,39 @@ void JoystickImpl::cleanup() //////////////////////////////////////////////////////////// bool JoystickImpl::isConnected(unsigned int index) { - // We check the connection state of joysticks only every N milliseconds, - // because of a strange (buggy?) behavior of joyGetPosEx when joysticks - // are just plugged/unplugged -- it takes really long and kills the app performances ConnectionCache& cache = connectionCache[index]; - if (cache.timer.getElapsedTime() > connectionRefreshDelay) + if (!lazyUpdates && cache.timer.getElapsedTime() > connectionRefreshDelay) { - cache.timer.restart(); - JOYINFOEX joyInfo; joyInfo.dwSize = sizeof(joyInfo); joyInfo.dwFlags = 0; - cache.connected = joyGetPosEx(JOYSTICKID1 + index, &joyInfo) == JOYERR_NOERROR; - return cache.connected; - } - else - { - return cache.connected; + + cache.timer.restart(); } + return cache.connected; } +//////////////////////////////////////////////////////////// +void JoystickImpl::setLazyUpdates(bool status) +{ + lazyUpdates = status; +} + +//////////////////////////////////////////////////////////// +void JoystickImpl::updateConnections() +{ + for (unsigned int i = 0; i < Joystick::Count; ++i) + { + JOYINFOEX joyInfo; + joyInfo.dwSize = sizeof(joyInfo); + joyInfo.dwFlags = 0; + ConnectionCache& cache = connectionCache[i]; + cache.connected = joyGetPosEx(JOYSTICKID1 + i, &joyInfo) == JOYERR_NOERROR; + + cache.timer.restart(); + } +} //////////////////////////////////////////////////////////// bool JoystickImpl::open(unsigned int index) diff --git a/src/SFML/Window/Win32/JoystickImpl.hpp b/src/SFML/Window/Win32/JoystickImpl.hpp index 570634ac..aa93fd1d 100644 --- a/src/SFML/Window/Win32/JoystickImpl.hpp +++ b/src/SFML/Window/Win32/JoystickImpl.hpp @@ -77,6 +77,20 @@ public: //////////////////////////////////////////////////////////// static bool isConnected(unsigned int index); + //////////////////////////////////////////////////////////// + /// \brief Enable or disable lazy enumeration updates + /// + /// \param status Whether to rely on windows triggering enumeration updates + /// + //////////////////////////////////////////////////////////// + static void setLazyUpdates(bool status); + + //////////////////////////////////////////////////////////// + /// \brief Update the connection status of all joysticks + /// + //////////////////////////////////////////////////////////// + static void updateConnections(); + //////////////////////////////////////////////////////////// /// \brief Open the joystick /// diff --git a/src/SFML/Window/Win32/WindowImplWin32.cpp b/src/SFML/Window/Win32/WindowImplWin32.cpp index a6c723ea..f8669b21 100644 --- a/src/SFML/Window/Win32/WindowImplWin32.cpp +++ b/src/SFML/Window/Win32/WindowImplWin32.cpp @@ -55,10 +55,15 @@ #define MAPVK_VK_TO_VSC (0) #endif +// Avoid including just for one define +#ifndef DBT_DEVNODES_CHANGED + #define DBT_DEVNODES_CHANGED 0x0007 +#endif namespace { - unsigned int windowCount = 0; + unsigned int windowCount = 0; // Windows owned by SFML + unsigned int handleCount = 0; // All window handles const wchar_t* className = L"SFML_Window"; sf::priv::WindowImplWin32* fullscreenWindow = NULL; @@ -141,6 +146,12 @@ m_cursorGrabbed (false) if (m_handle) { + // If we're the first window handle, we only need to poll for joysticks when WM_DEVICECHANGE message is received + if (handleCount == 0) + JoystickImpl::setLazyUpdates(true); + + ++handleCount; + // We change the event procedure of the control (it is important to save the old one) SetWindowLongPtrW(m_handle, GWLP_USERDATA, reinterpret_cast(this)); m_callback = SetWindowLongPtrW(m_handle, GWLP_WNDPROC, reinterpret_cast(&WindowImplWin32::globalOnEvent)); @@ -202,6 +213,15 @@ m_cursorGrabbed (m_fullscreen) // Create the window m_handle = CreateWindowW(className, title.toWideString().c_str(), win32Style, left, top, width, height, NULL, NULL, GetModuleHandle(NULL), this); + // If we're the first window handle, we only need to poll for joysticks when WM_DEVICECHANGE message is received + if (m_handle) + { + if (handleCount == 0) + JoystickImpl::setLazyUpdates(true); + + ++handleCount; + } + // By default, the OS limits the size of the window the the desktop size, // we have to resize it after creation to apply the real size setSize(Vector2u(mode.width, mode.height)); @@ -222,6 +242,15 @@ WindowImplWin32::~WindowImplWin32() if (m_icon) DestroyIcon(m_icon); + // If it's the last window handle we have to poll for joysticks again + if (m_handle) + { + --handleCount; + + if (handleCount == 0) + JoystickImpl::setLazyUpdates(false); + } + if (!m_callback) { // Destroy the window @@ -936,6 +965,13 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) pushEvent(event); break; } + case WM_DEVICECHANGE: + { + // Some sort of device change has happened, update joystick connections + if (wParam == DBT_DEVNODES_CHANGED) + JoystickImpl::updateConnections(); + break; + } } }