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

@ -8,14 +8,31 @@ set(QJOYPAD_PATCH 0)
find_package(Qt4 REQUIRED)
set(WITH_LIBUDEV ON CACHE PATH "Use libudev for automatically updating joypad devices.")
if(WITH_LIBUDEV)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBUDEV libudev)
if(LIBUDEV_FOUND)
message(STATUS "libudev found")
else()
message(ERROR "libudev not found. If you don't want to compile with libudev support use -DWITH_LIBUDEV=OFF")
endif()
link_directories(${LIBUDEV_LIBRARY_DIRS})
include_directories(${LIBUDEV_INCLUDE_DIRS})
endif()
set(DEVICE_DIR "/dev/input" CACHE PATH "Set the path where QJoyPad will look for your joystick devices. If your devices are /dev/js0, /dev/js1, etc., this should be just \"/dev\". By default, this is /dev/input.")
set(PLAIN_KEYS OFF CACHE BOOL "Force QJoyPad to use standard XWindows keynames without filtering them for appearance. This will make displays less attractive and readable, but will save processor power and ensure that you see the right names for keys you press.")
message("-- Using device directory: ${DEVICE_DIR}")
message(STATUS "Using device directory: ${DEVICE_DIR}")
if(PLAIN_KEYS)
message("-- Using regular XWindows key names.")
message(STATUS "Using regular XWindows key names.")
add_definitions(-DPLAIN_KEYS)
endif()

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