mirror of
https://github.com/SFML/SFML.git
synced 2024-11-29 06:41:05 +08:00
Now using inotify on Linux to avoid constantly polling joystick connections (#96)
This commit is contained in:
parent
af81ac60f3
commit
6ec100aeb7
@ -93,6 +93,7 @@ void JoystickManager::update()
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickManager::JoystickManager()
|
||||
{
|
||||
JoystickImpl::initialize();
|
||||
}
|
||||
|
||||
|
||||
@ -104,6 +105,8 @@ JoystickManager::~JoystickManager()
|
||||
if (m_joysticks[i].state.connected)
|
||||
m_joysticks[i].joystick.close();
|
||||
}
|
||||
|
||||
JoystickImpl::cleanup();
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
@ -26,39 +26,121 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/JoystickImpl.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
int notifyFd = -1;
|
||||
int inputFd = -1;
|
||||
bool plugged[sf::Joystick::Count];
|
||||
|
||||
void updatePluggedList()
|
||||
{
|
||||
for (unsigned int i = 0; i < sf::Joystick::Count; ++i)
|
||||
{
|
||||
char name[32];
|
||||
std::snprintf(name, sizeof(name), "/dev/input/js%u", i);
|
||||
struct stat info;
|
||||
plugged[i] = (stat(name, &info) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool canRead(int descriptor)
|
||||
{
|
||||
fd_set set;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(descriptor, &set);
|
||||
timeval timeout = {0, 0};
|
||||
return select(descriptor + 1, &set, NULL, NULL, &timeout) > 0 &&
|
||||
FD_ISSET(notifyFd, &set);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::initialize()
|
||||
{
|
||||
// Reset the array of plugged joysticks
|
||||
std::fill(plugged, plugged + Joystick::Count, false);
|
||||
|
||||
// Create the inotify instance
|
||||
notifyFd = inotify_init();
|
||||
if (notifyFd < 0)
|
||||
{
|
||||
err() << "Failed to initialize inotify, joystick connections and disconnections won't be notified" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Watch nodes created and deleted in the /dev/input directory
|
||||
inputFd = inotify_add_watch(notifyFd, "/dev/input", IN_CREATE | IN_DELETE);
|
||||
if (inputFd < 0)
|
||||
{
|
||||
err() << "Failed to initialize inotify, joystick connections and disconnections won't be notified" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do an initial scan
|
||||
updatePluggedList();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::cleanup()
|
||||
{
|
||||
// Stop watching the /dev/input directory
|
||||
if (inputFd >= 0)
|
||||
inotify_rm_watch(notifyFd, inputFd);
|
||||
|
||||
// Close the inotify file descriptor
|
||||
if (inputFd >= 0)
|
||||
::close(notifyFd);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::isConnected(unsigned int index)
|
||||
{
|
||||
char name[32];
|
||||
std::sprintf(name, "/dev/input/js%u", index);
|
||||
// First check if new joysticks were added/removed since last update
|
||||
if (canRead(notifyFd))
|
||||
{
|
||||
// Don't bother decomposing and interpreting the filename, just do a full scan
|
||||
updatePluggedList();
|
||||
|
||||
struct stat info;
|
||||
return stat(name, &info) == 0;
|
||||
// Flush all the pending events
|
||||
while (canRead(notifyFd))
|
||||
{
|
||||
char buffer[128];
|
||||
read(notifyFd, buffer, sizeof(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
// Then check if the joystick is connected
|
||||
return plugged[index];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::open(unsigned int index)
|
||||
{
|
||||
char name[32];
|
||||
std::sprintf(name, "/dev/input/js%u", index);
|
||||
|
||||
m_file = ::open(name, O_RDONLY);
|
||||
if (m_file > 0)
|
||||
if (plugged[index])
|
||||
{
|
||||
// Use non-blocking mode
|
||||
fcntl(m_file, F_SETFL, O_NONBLOCK);
|
||||
char name[32];
|
||||
std::snprintf(name, sizeof(name), "/dev/input/js%u", index);
|
||||
|
||||
// Open the joystick's file descriptor (read-only and non-blocking)
|
||||
m_file = ::open(name, O_RDONLY | O_NONBLOCK);
|
||||
if (m_file >= 0)
|
||||
{
|
||||
// Retrieve the axes mapping
|
||||
ioctl(m_file, JSIOCGAXMAP, m_mapping);
|
||||
|
||||
@ -72,6 +154,11 @@ bool JoystickImpl::open(unsigned int index)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -49,6 +49,18 @@ class JoystickImpl
|
||||
{
|
||||
public :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global initialization of the joystick module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void initialize();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global cleanup of the joystick module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void cleanup();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a joystick is currently connected
|
||||
///
|
||||
|
@ -30,15 +30,16 @@
|
||||
#include <SFML/Window/OSX/HIDInputManager.hpp>
|
||||
#include <SFML/Window/OSX/HIDJoystickManager.hpp>
|
||||
|
||||
// Translation unit namespace
|
||||
namespace {
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
bool JoystickButtonSortPredicate(IOHIDElementRef b1, IOHIDElementRef b2)
|
||||
{
|
||||
return IOHIDElementGetUsage(b1) < IOHIDElementGetUsage(b2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
@ -47,6 +48,20 @@ namespace priv
|
||||
JoystickImpl::Location JoystickImpl::m_locationIDs[sf::Joystick::Count] = { 0 };
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::initialize()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::cleanup()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::isConnected(unsigned int index)
|
||||
{
|
||||
|
@ -46,6 +46,18 @@ class JoystickImpl
|
||||
{
|
||||
public :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global initialization of the joystick module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void initialize();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global cleanup of the joystick module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void cleanup();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a joystick is currently connected
|
||||
///
|
||||
|
@ -35,10 +35,9 @@ namespace
|
||||
{
|
||||
struct ConnectionCache
|
||||
{
|
||||
ConnectionCache() : connected(false), firstTime(true) {}
|
||||
ConnectionCache() : connected(false) {}
|
||||
bool connected;
|
||||
sf::Clock timer;
|
||||
bool firstTime;
|
||||
};
|
||||
|
||||
const sf::Time connectionRefreshDelay = sf::milliseconds(500);
|
||||
@ -49,6 +48,33 @@ namespace sf
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::cleanup()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::isConnected(unsigned int index)
|
||||
{
|
||||
@ -56,10 +82,9 @@ bool JoystickImpl::isConnected(unsigned int index)
|
||||
// because of a strange (buggy?) behaviour of joyGetPosEx when joysticks
|
||||
// are just plugged/unplugged -- it takes really long and kills the app performances
|
||||
ConnectionCache& cache = connectionCache[index];
|
||||
if (cache.firstTime || (cache.timer.getElapsedTime() > connectionRefreshDelay))
|
||||
if (cache.timer.getElapsedTime() > connectionRefreshDelay)
|
||||
{
|
||||
cache.timer.restart();
|
||||
cache.firstTime = false;
|
||||
|
||||
JOYINFOEX joyInfo;
|
||||
joyInfo.dwSize = sizeof(joyInfo);
|
||||
|
@ -54,6 +54,18 @@ class JoystickImpl
|
||||
{
|
||||
public :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global initialization of the joystick module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void initialize();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global cleanup of the joystick module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void cleanup();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a joystick is currently connected
|
||||
///
|
||||
|
Loading…
Reference in New Issue
Block a user