If a window is open, only update joystick connections on WM_DEVICECHANGE message

This commit is contained in:
jonathan.r.paton@googlemail.com 2017-02-22 11:50:42 +00:00 committed by Lukas Dürrenberger
parent 4cde8bb69c
commit f053871a6c
3 changed files with 80 additions and 27 deletions

View File

@ -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)

View File

@ -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
///

View File

@ -55,10 +55,15 @@
#define MAPVK_VK_TO_VSC (0)
#endif
// Avoid including <Dbt.h> 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<LONG_PTR>(this));
m_callback = SetWindowLongPtrW(m_handle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&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;
}
}
}