optional libudev support for auto update devices

This commit is contained in:
Mathias Panzenböck
2014-02-22 23:24:05 +01:00
parent d8c8459afb
commit 7805757447
5 changed files with 202 additions and 47 deletions

View File

@ -23,25 +23,25 @@ set(qjoypad_SOURCES
quickset.cpp)
set(qjoypad_QOBJECT_HEADERS
axis_edit.h
axis.h
axisw.h
button_edit.h
button.h
buttonw.h
flash.h
getkey.h
icon.h
joypad.h
joypadw.h
joyslider.h
keycode.h
layout_edit.h
layout.h
quickset.h)
axis_edit.h
axis.h
axisw.h
button_edit.h
button.h
buttonw.h
flash.h
getkey.h
icon.h
joypad.h
joypadw.h
joyslider.h
keycode.h
layout_edit.h
layout.h
quickset.h)
QT4_WRAP_CPP(qjoypad_HEADERS_MOC ${qjoypad_QOBJECT_HEADERS})
add_executable(qjoypad ${qjoypad_SOURCES} ${qjoypad_HEADERS_MOC})
target_link_libraries(qjoypad ${QT_LIBRARIES} Xtst X11)
target_link_libraries(qjoypad ${QT_LIBRARIES} Xtst X11 ${LIBUDEV_LIBRARIES})
install(TARGETS qjoypad RUNTIME DESTINATION "bin")

View File

@ -12,4 +12,6 @@
#define QJOYPAD_ICON24 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/24x24/apps/qjoypad.png"
#define QJOYPAD_ICON64 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/64x64/apps/qjoypad.png"
#cmakedefine WITH_LIBUDEV
#endif

View File

@ -15,6 +15,18 @@ LayoutManager::LayoutManager( bool useTrayIcon, const QString &devdir, const QSt
updateLayoutsAction(new QAction(QIcon::fromTheme("view-refresh"),"Update &Layout List",this)),
quitAction(new QAction(QIcon::fromTheme("application-exit"),"&Quit",this)),
le(0) {
#ifdef WITH_LIBUDEV
udevNotifier = 0;
udev = 0;
monitor = 0;
if (!initUDev()) {
errorBox("UDev Error", "Error creating udev monitor. "
"QJoyPad will still work, but it won't automatically update the joypad device list.");
}
#endif
//prepare the popup first.
titleAction->setEnabled(false);
fillPopup();
@ -49,8 +61,99 @@ LayoutManager::~LayoutManager() {
le->close();
le = 0;
}
#ifdef WITH_LIBUDEV
if (udevNotifier) {
udevNotifier->blockSignals(true);
}
if (monitor) {
udev_monitor_unref(monitor);
monitor = 0;
}
if (udev) {
udev_unref(udev);
udev = 0;
}
#endif
}
#ifdef WITH_LIBUDEV
bool LayoutManager::initUDev() {
udev = udev_new();
debug_mesg("init udev\n");
if (udev) {
debug_mesg("udev ok\n");
monitor = udev_monitor_new_from_netlink(udev, "udev");
if (monitor) {
debug_mesg("monitor ok\n");
int errnum = udev_monitor_filter_add_match_subsystem_devtype(
monitor, "input", NULL);
if (errnum != 0) {
debug_mesg("udev_monitor_filter_add_match_subsystem_devtype: %s\n",
strerror(errnum));
udev_monitor_unref(monitor);
udev_unref(udev);
monitor = 0;
udev = 0;
return false;
}
errnum = udev_monitor_enable_receiving(monitor);
if (errnum != 0) {
debug_mesg("udev_monitor_enable_receiving: %s\n",
strerror(errnum));
udev_monitor_unref(monitor);
udev_unref(udev);
monitor = 0;
udev = 0;
return false;
}
udevNotifier = new QSocketNotifier(udev_monitor_get_fd(monitor), QSocketNotifier::Read, this);
connect(udevNotifier, SIGNAL(activated(int)), this, SLOT(udevUpdate()));
debug_mesg("notifier ok\n");
}
else {
udev_unref(udev);
udev = 0;
}
}
return udev != 0;
}
void LayoutManager::udevUpdate() {
struct udev_device *dev = udev_monitor_receive_device(monitor);
if (dev) {
QRegExp devicename("/js(\\d+)$");
QString path = QString("/sys%1").arg(udev_device_get_devpath(dev));
const char *action = udev_device_get_action(dev);
if (devicename.indexIn(path) >= 0) {
int index = devicename.cap(1).toInt();
if (strcmp(action,"add") == 0 || strcmp(action,"online") == 0) {
addJoyPad(index, path);
}
else if (strcmp(action,"remove") == 0 || strcmp(action,"offline") == 0) {
removeJoyPad(index);
}
else if (strcmp(action,"change") == 0) {
removeJoyPad(index);
addJoyPad(index, path);
}
fillPopup();
if (le) {
le->updateJoypadWidgets();
}
}
udev_device_unref(dev);
}
}
#endif
QString LayoutManager::getFileName(const QString& layoutname ) {
return QString("%1%2.lyt").arg(settingsDir, layoutname);
}
@ -390,42 +493,57 @@ void LayoutManager::updateJoyDevs() {
QDir deviceDir(devdir);
QStringList devices = deviceDir.entryList(QStringList("js*"), QDir::System);
QRegExp devicename("js(\\d+)");
int joydev = -1;
int index = -1;
//for every joystick device in the directory listing...
//(note, with devfs, only available devices are listed)
foreach (const QString &device, devices) {
QString devpath = QString("%1/%2").arg(devdir, device);
debug_mesg("found a device file, %s\n", qPrintable(devpath));
//try opening the device.
joydev = open( qPrintable(devpath), O_RDONLY | O_NONBLOCK);
//if it worked, then we have a live joystick! Make sure it's properly
//setup.
if (joydev >= 0) {
devicename.indexIn(device);
index = devicename.cap(1).toInt();
JoyPad* joypad = joypads[index];
//if we've never seen this device before, make a new one!
if (joypad == 0) {
joypad = new JoyPad( index, joydev, this );
joypads.insert(index,joypad);
}
else {
debug_mesg("found previously open joypad with index %d, ignoring", index);
joypad->open(joydev);
}
//make this joystick device available.
available.insert(index,joypad);
}
else {
perror(qPrintable(devpath));
if (devicename.indexIn(device) >= 0) {
int index = devicename.cap(1).toInt();
QString devpath = QString("%1/%2").arg(devdir, device);
addJoyPad(index, devpath);
}
}
//when it's all done, rebuild the popup menu so it displays the correct
//information.
fillPopup();
if(le) {
if (le) {
le->updateJoypadWidgets();
}
debug_mesg("done updating joydevs\n");
}
void LayoutManager::addJoyPad(int index) {
addJoyPad(index, QString("%1/js%2").arg(devdir, index));
}
void LayoutManager::addJoyPad(int index, const QString& devpath) {
debug_mesg("opening %s\n", qPrintable(devpath));
//try opening the device.
int joydev = open(qPrintable(devpath), O_RDONLY | O_NONBLOCK);
//if it worked, then we have a live joystick! Make sure it's properly
//setup.
if (joydev >= 0) {
JoyPad* joypad = joypads[index];
//if we've never seen this device before, make a new one!
if (joypad == 0) {
joypad = new JoyPad( index, joydev, this );
joypads.insert(index,joypad);
}
else {
debug_mesg("found previously open joypad with index %d, ignoring", index);
joypad->open(joydev);
}
//make this joystick device available.
available.insert(index,joypad);
}
else {
perror(qPrintable(devpath));
}
}
void LayoutManager::removeJoyPad(int index) {
JoyPad *joypad = available[index];
if (joypad) {
joypad->close();
available.remove(index);
}
}

View File

@ -17,6 +17,12 @@
#include <QInputDialog>
#include <QSystemTrayIcon>
#include "config.h"
#ifdef WITH_LIBUDEV
#include <libudev.h>
#endif
//a layout handles several joypads
#include "joypad.h"
//for errors
@ -66,7 +72,10 @@ class LayoutManager : public QObject {
private slots:
//when the user selects an item on the tray's popup menu
void layoutTriggered();
private:
private:
void addJoyPad(int index);
void addJoyPad(int index, const QString& devpath);
void removeJoyPad(int index);
//change to the given layout name and make all the necesary adjustments
void setLayoutName(const QString& name);
//get the file name for a layout name
@ -90,6 +99,15 @@ class LayoutManager : public QObject {
QHash<int, JoyPad*> available;
QHash<int, JoyPad*> joypads;
#ifdef WITH_LIBUDEV
bool initUDev();
QSocketNotifier *udevNotifier;
struct udev *udev;
struct udev_monitor *monitor;
private slots:
void udevUpdate();
#endif
};
#endif