sort by location

This commit is contained in:
din
2025-03-01 23:25:47 -08:00
committed by teejusb
parent 4d8d22d223
commit f0394b721e
2 changed files with 101 additions and 23 deletions
+86 -18
View File
@@ -13,15 +13,23 @@
#include <dirent.h>
#endif
#if defined(HAVE_FCNTL_H)
#include <fcntl.h>
#endif
#include <linux/input.h>
#include <errno.h>
Preference<bool> g_bInputLinuxOrderByLocation( "InputLinuxOrderByLocation", false );
RString getDevice(RString inputDir, RString type)
{
RString result = "";
DIR* dir = opendir( inputDir.c_str() );
if(dir == nullptr)
{ LOG->Warn("LinuxInputManager: Couldn't open %s: %s.", inputDir.c_str(), strerror(errno) ); return ""; }
struct dirent* d;
while( ( d = readdir(dir) ) != nullptr)
if( strncmp( type.c_str(), d->d_name, type.size() ) == 0)
@@ -29,7 +37,7 @@ RString getDevice(RString inputDir, RString type)
result = RString("/dev/input/") + d->d_name;
break;
}
closedir(dir);
return result;
}
@@ -46,10 +54,10 @@ LinuxInputManager::LinuxInputManager()
// HACK: If empty, assume both are enabled
if( g_sInputDrivers.Get() == "" )
{ m_bEventEnabled = true; m_bJoystickEnabled = true; }
m_EventDriver = nullptr;
m_JoystickDriver = nullptr;
// XXX: Can I use RageFile for this?
DIR* sysClassInput = opendir("/sys/class/input");
if( sysClassInput == nullptr)
@@ -58,33 +66,93 @@ LinuxInputManager::LinuxInputManager()
LOG->Warn("Couldn't open /sys/class/input: %s. Joysticks will not work!", strerror(errno) );
return;
}
struct dirent* d;
while( ( d = readdir(sysClassInput) ) != nullptr)
{
if( strncmp( "input", d->d_name, 5) != 0) continue;
RString dName = RString("/sys/class/input/") + d->d_name;
bool bEventPresent = getDevice(dName, "event") != "";
if( m_bEventEnabled && bEventPresent )
if( m_bEventEnabled && bEventPresent )
{ m_vsPendingEventDevices.push_back(dName); continue; }
bool bJoystickPresent = getDevice(dName, "js") != "";
if( m_bJoystickEnabled && bJoystickPresent )
{ m_vsPendingJoystickDevices.push_back(dName); continue; }
if( !bEventPresent && !bJoystickPresent )
LOG->Info("LinuxInputManager: %s seems to have no eventNN or jsNN.", dName.c_str() );
}
// Sort devices for more consistent numbering.
std::sort(m_vsPendingEventDevices.begin(), m_vsPendingEventDevices.end(), cmpDevices);
std::sort(m_vsPendingJoystickDevices.begin(), m_vsPendingJoystickDevices.end(), cmpDevices);
if(g_bInputLinuxOrderByLocation)
{
// use Presort to sort the devices by unique location (like USB port/hub number.)
PresortPhysical(m_vsPendingEventDevices, "event");
PresortPhysical(m_vsPendingJoystickDevices, "js");
}
else
{
// Sort devices for more consistent numbering.
std::sort(m_vsPendingEventDevices.begin(), m_vsPendingEventDevices.end(), cmpDevices);
std::sort(m_vsPendingJoystickDevices.begin(), m_vsPendingJoystickDevices.end(), cmpDevices);
}
closedir(sysClassInput);
}
static bool presort_cmpDevices(LinuxInputSort a, LinuxInputSort b)
{
return a.UniqueString < b.UniqueString;
}
void LinuxInputManager::PresortPhysical(std::vector<RString>& sortingArray, RString sortBy)
{
m_vPreSort.clear();
for (RString &dev : sortingArray)
{
LinuxInputSort entry;
entry.DeviceName = dev;
entry.UniqueString = "";
int m_iFD = open(getDevice(dev, sortBy.c_str()).c_str(), O_RDWR);
if(m_iFD >= 0)
{
char szLocation[1024];
// EVIOCGPHYS can return values like "usb-0000:0d:00.3-4"
// telling us where the device is located physically on the computer.
if(ioctl(m_iFD, EVIOCGPHYS(sizeof(szLocation)), szLocation) != -1)
{
entry.UniqueString += szLocation;
}
close(m_iFD);
}
// in the event we didn't get a unique location from ioctl
// default to the name so that sorting by number still works as intended.
entry.UniqueString += entry.DeviceName;
m_vPreSort.push_back(entry);
}
std::sort(m_vPreSort.begin(), m_vPreSort.end(), presort_cmpDevices);
sortingArray.clear();
for (LinuxInputSort &dev : m_vPreSort)
{
// LOG->Info("%s -> %s", dev.DeviceName.c_str(), dev.UniqueString.c_str());
sortingArray.push_back(dev.DeviceName);
}
}
void LinuxInputManager::InitDriver(InputHandler_Linux_Event* driver)
{
m_EventDriver = driver;
@@ -93,7 +161,7 @@ void LinuxInputManager::InitDriver(InputHandler_Linux_Event* driver)
{
RString devFile = getDevice(dev, "event");
ASSERT( devFile != "" );
if( ! driver->TryDevice(devFile) && m_bJoystickEnabled && getDevice(dev, "js") != "" )
m_vsPendingJoystickDevices.push_back(dev);
}
@@ -105,7 +173,7 @@ void LinuxInputManager::InitDriver(InputHandler_Linux_Event* driver)
void LinuxInputManager::InitDriver(InputHandler_Linux_Joystick* driver)
{
m_JoystickDriver = driver;
// Discard all the joystick devices if they were assigned manually via
// Discard all the joystick devices if they were assigned manually via
// InputDeviceOrder
if( g_sInputDeviceOrder.Get() != "" ) {
m_vsPendingJoystickDevices.clear();
@@ -115,7 +183,7 @@ void LinuxInputManager::InitDriver(InputHandler_Linux_Joystick* driver)
{
RString devFile = getDevice(dev, "js");
ASSERT( devFile != "" );
driver->TryDevice(devFile);
}
@@ -134,7 +202,7 @@ LinuxInputManager* LINUXINPUT = nullptr; // global and accessible anywhere in ou
/*
* (c) 2013 Ben "root" Anderson
* All rights reserved.
*
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
@@ -144,7 +212,7 @@ LinuxInputManager* LINUXINPUT = nullptr; // global and accessible anywhere in ou
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+15 -5
View File
@@ -7,9 +7,16 @@
class InputHandler_Linux_Joystick;
class InputHandler_Linux_Event;
// Enumerates the input devices on the system and dispatches them to
// Enumerates the input devices on the system and dispatches them to
// IH_Linux_Event and IH_Linux_Joystick as appropriate.
// Helper struct for keeping track of inputs.
struct LinuxInputSort
{
RString DeviceName;
RString UniqueString;
};
class LinuxInputManager
{
public:
@@ -18,10 +25,13 @@ public:
void InitDriver(InputHandler_Linux_Event* drv);
~LinuxInputManager();
private:
std::vector<LinuxInputSort> m_vPreSort;
void PresortPhysical(std::vector<RString>& sortingArray, RString sortBy);
bool m_bEventEnabled;
InputHandler_Linux_Event* m_EventDriver;
std::vector<RString> m_vsPendingEventDevices;
bool m_bJoystickEnabled;
InputHandler_Linux_Joystick* m_JoystickDriver;
std::vector<RString> m_vsPendingJoystickDevices;
@@ -34,7 +44,7 @@ extern LinuxInputManager* LINUXINPUT; // global and accessible from anywhere in
/*
* (c) 2013 Ben "root" Anderson
* All rights reserved.
*
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
@@ -44,7 +54,7 @@ extern LinuxInputManager* LINUXINPUT; // global and accessible from anywhere in
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
@@ -54,4 +64,4 @@ extern LinuxInputManager* LINUXINPUT; // global and accessible from anywhere in
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
*/