Linux: Detect joystick hotplug
Interface with libudev to get notified when a new joystick appears. The code is in IH_Linux_Event rather than IH_Linux_Joystick because it seemed like the former uses evdev (standard for most devices nowadays) whereas the latter uses the old joydev API. The result should be the same in any case... Implementation is a bit messy due to LinuxInputManager only scanning for devices from its constructor, this forces RageInput to have an exception for LinuxInputManager. Possibly with more involved surgery a cleaner solution could be devised...
This commit is contained in:
@@ -6,6 +6,11 @@
|
||||
#include "LuaManager.h"
|
||||
#include "LocalizedString.h"
|
||||
|
||||
#if LINUX
|
||||
// FIXME: bit gross to include this here, see GH issue #73
|
||||
#include "arch/InputHandler/LinuxInputManager.h"
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -60,6 +65,11 @@ void RageInput::LoadDrivers()
|
||||
m_InputHandlers.clear();
|
||||
g_mapDeviceToHandler.clear();
|
||||
|
||||
#if LINUX
|
||||
// Recreating this forces it to re-scan for devices.
|
||||
LINUXINPUT = new LinuxInputManager;
|
||||
#endif
|
||||
|
||||
// Init optional devices.
|
||||
std::vector<InputHandler *> apDevices;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/input.h>
|
||||
#include <libudev.h>
|
||||
|
||||
REGISTER_INPUT_HANDLER_CLASS2( LinuxEvent, Linux_Event );
|
||||
|
||||
@@ -266,15 +267,33 @@ EventDevice::~EventDevice()
|
||||
}
|
||||
|
||||
InputHandler_Linux_Event::InputHandler_Linux_Event()
|
||||
: m_NextDevice(DEVICE_JOY10)
|
||||
: m_InputMutex("InputHandler_Linux")
|
||||
, m_NextDevice(DEVICE_JOY10)
|
||||
, m_bShutdown(true)
|
||||
, m_bDevicesChanged(false)
|
||||
, m_udev_fd(-1)
|
||||
{
|
||||
if(LINUXINPUT == nullptr) LINUXINPUT = new LinuxInputManager;
|
||||
LINUXINPUT->InitDriver(this);
|
||||
|
||||
if( ! g_apEventDevices.empty() ) // LinuxInputManager found at least one valid device for us
|
||||
StartThread();
|
||||
m_udev = udev_new();
|
||||
if( ! m_udev )
|
||||
LOG->Warn( "Failed to create udev object" );
|
||||
|
||||
m_udev_monitor = udev_monitor_new_from_netlink(m_udev, "udev");
|
||||
if( ! m_udev_monitor )
|
||||
{
|
||||
LOG->Warn( "Failed to create udev object" );
|
||||
udev_unref(m_udev);
|
||||
}
|
||||
|
||||
udev_monitor_filter_add_match_subsystem_devtype(m_udev_monitor, "input", NULL);
|
||||
udev_monitor_enable_receiving(m_udev_monitor);
|
||||
|
||||
m_udev_fd = udev_monitor_get_fd(m_udev_monitor);
|
||||
|
||||
// Always start thread, if only to monitor udev events
|
||||
StartThread();
|
||||
}
|
||||
|
||||
InputHandler_Linux_Event::~InputHandler_Linux_Event()
|
||||
@@ -284,6 +303,9 @@ InputHandler_Linux_Event::~InputHandler_Linux_Event()
|
||||
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
|
||||
delete g_apEventDevices[i];
|
||||
g_apEventDevices.clear();
|
||||
|
||||
udev_monitor_unref(m_udev_monitor);
|
||||
udev_unref(m_udev);
|
||||
}
|
||||
|
||||
void InputHandler_Linux_Event::StartThread()
|
||||
@@ -315,7 +337,11 @@ bool InputHandler_Linux_Event::TryDevice(RString devfile)
|
||||
if( hotplug ) StartThread();
|
||||
|
||||
m_NextDevice = enum_add2(m_NextDevice, 1);
|
||||
|
||||
m_InputMutex.Lock();
|
||||
m_bDevicesChanged = true;
|
||||
m_InputMutex.Unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -343,6 +369,12 @@ void InputHandler_Linux_Event::InputThread()
|
||||
FD_ZERO( &fdset );
|
||||
int iMaxFD = -1;
|
||||
|
||||
if( m_udev_fd >= 0 )
|
||||
{
|
||||
FD_SET( m_udev_fd, &fdset );
|
||||
iMaxFD = std::max( iMaxFD, m_udev_fd );
|
||||
}
|
||||
|
||||
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
|
||||
{
|
||||
int iFD = g_apEventDevices[i]->m_iFD;
|
||||
@@ -361,6 +393,31 @@ void InputHandler_Linux_Event::InputThread()
|
||||
continue;
|
||||
RageTimer now;
|
||||
|
||||
if( FD_ISSET(m_udev_fd, &fdset) )
|
||||
{
|
||||
struct udev_device* device = udev_monitor_receive_device(m_udev_monitor);
|
||||
if( device )
|
||||
{
|
||||
const char *action = udev_device_get_action(device);
|
||||
const char *devnode = udev_device_get_devnode(device);
|
||||
|
||||
if( action && devnode && strcmp(action, "add") == 0 )
|
||||
{
|
||||
// Check if the device is a joystick
|
||||
const char *devtype = udev_device_get_property_value(device, "ID_INPUT_JOYSTICK");
|
||||
if( devtype && strcmp(devtype, "1") == 0 )
|
||||
{
|
||||
m_InputMutex.Lock();
|
||||
m_bDevicesChanged = true;
|
||||
m_InputMutex.Unlock();
|
||||
LOG->Info("LinuxEvent: New joystick detected: %s\n", devnode);
|
||||
}
|
||||
}
|
||||
|
||||
udev_device_unref(device);
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < (int) g_apEventDevices.size(); ++i )
|
||||
{
|
||||
if( !g_apEventDevices[i]->IsOpen() )
|
||||
@@ -375,6 +432,9 @@ void InputHandler_Linux_Event::InputThread()
|
||||
{
|
||||
LOG->Warn( "Error reading from %s: %s; disabled", g_apEventDevices[i]->m_sPath.c_str(), strerror(errno) );
|
||||
g_apEventDevices[i]->Close();
|
||||
m_InputMutex.Lock();
|
||||
m_bDevicesChanged = true;
|
||||
m_InputMutex.Unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -382,6 +442,9 @@ void InputHandler_Linux_Event::InputThread()
|
||||
{
|
||||
LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i);
|
||||
g_apEventDevices[i]->Close();
|
||||
m_InputMutex.Lock();
|
||||
m_bDevicesChanged = true;
|
||||
m_InputMutex.Unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -441,7 +504,9 @@ void InputHandler_Linux_Event::GetDevicesAndDescriptions( std::vector<InputDevic
|
||||
vDevicesOut.push_back( InputDeviceInfo(pDev->m_Dev, pDev->m_sName) );
|
||||
}
|
||||
|
||||
m_InputMutex.Lock();
|
||||
m_bDevicesChanged = false;
|
||||
m_InputMutex.Unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -25,8 +25,14 @@ private:
|
||||
void InputThread();
|
||||
|
||||
RageThread m_InputThread;
|
||||
// Currently only m_bDevicesChanged is guarded by this mutex
|
||||
RageMutex m_InputMutex;
|
||||
InputDevice m_NextDevice;
|
||||
bool m_bShutdown, m_bDevicesChanged;
|
||||
// Used to monitor for new devices
|
||||
int m_udev_fd;
|
||||
struct udev* m_udev;
|
||||
struct udev_monitor* m_udev_monitor;
|
||||
};
|
||||
#define USE_INPUT_HANDLER_LINUX_JOYSTICK
|
||||
|
||||
|
||||
Reference in New Issue
Block a user