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:
@@ -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();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user