[gnome-games] gamepad: Add fallback support for gamepads without udev



commit 6abbc5cba83d428ce8cc1d34ef5ffa630415cbcf
Author: Bastien Nocera <hadess hadess net>
Date:   Mon Aug 15 01:14:23 2016 +0200

    gamepad: Add fallback support for gamepads without udev
    
    udev doesn't have a stable ABI/API, so is not available in
    flatpak runtimes. Add a fallback implementation that loads
    the joysticks available on startup.
    
    The detection code comes from the input_id.c helper in
    systemd/udev, ported to libevdev.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=769904

 configure.ac                                       |    9 +++-
 src/Makefile.am                                    |   19 +++++++-
 .../linux/linux-raw-gamepad-monitor-fallback.vala  |   53 ++++++++++++++++++++
 src/gamepad/linux/linux-raw-gamepad-monitor.vala   |    4 +-
 src/gamepad/linux/linux-raw-gamepad.vala           |   30 +++++++++++
 5 files changed, 112 insertions(+), 3 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index d3c4c2e..26edb1a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,11 +59,18 @@ PKG_CHECK_MODULES(GNOME_GAMES, [
 ])
 
 PKG_CHECK_MODULES(GAMEPADS, [
-       gudev-1.0
        libevdev
 ], [enable_gamepads=yes], [enable_gamepads=no])
 AM_CONDITIONAL([ENABLE_GAMEPADS], [test x$enable_gamepads != xno])
 
+enable_udev=no
+if test x$enable_gamepads = xyes ; then
+       PKG_CHECK_MODULES(UDEV, [
+               gudev-1.0
+       ], [enable_udev=yes], [enable_udev=no])
+fi
+AM_CONDITIONAL([ENABLE_UDEV], [test x$enable_udev = xyes])
+
 AC_CONFIG_FILES([
        Makefile
        data/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 625455b..1164247 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -129,8 +129,17 @@ gnome_games_SOURCES = \
 if ENABLE_GAMEPADS
 gnome_games_SOURCES += \
        gamepad/linux/linux-raw-gamepad.vala \
+       $(NULL)
+
+if ENABLE_UDEV
+gnome_games_SOURCES += \
        gamepad/linux/linux-raw-gamepad-monitor.vala \
        $(NULL)
+else
+gnome_games_SOURCES += \
+       gamepad/linux/linux-raw-gamepad-monitor-fallback.vala \
+       $(NULL)
+endif
 endif
 
 gnome_games_VALAFLAGS = \
@@ -153,15 +162,22 @@ gnome_games_VALAFLAGS = \
 if ENABLE_GAMEPADS
 gnome_games_VALAFLAGS += \
        --vapidir=gamepad/linux/ \
-       --pkg gudev-1.0 \
        --pkg libevdev \
        --define ENABLE_LINUX_GAMEPADS
        $(NULL)
 endif
 
+if ENABLE_UDEV
+gnome_games_VALAFLAGS += \
+       --vapidir=gamepad/linux/ \
+       --pkg gudev-1.0 \
+       --define ENABLE_UDEV
+endif
+
 gnome_games_CFLAGS = \
        $(GNOME_GAMES_CFLAGS) \
        $(GAMEPADS_CFLAGS) \
+       $(UDEV_CFLAGS) \
        -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
        -DGAMES_PLUGINS_DIR=\"$(libdir)/gnome-games/plugins\" \
        $(NULL)
@@ -174,6 +190,7 @@ gnome_games_CPPFLAGS = \
 gnome_games_LDADD = \
        $(GNOME_GAMES_LIBS) \
        $(GAMEPADS_LIBS) \
+       $(UDEV_LIBS) \
        $(NULL)
 
 gnome_gamesincludedir = $(includedir)
diff --git a/src/gamepad/linux/linux-raw-gamepad-monitor-fallback.vala 
b/src/gamepad/linux/linux-raw-gamepad-monitor-fallback.vala
new file mode 100644
index 0000000..9e331f7
--- /dev/null
+++ b/src/gamepad/linux/linux-raw-gamepad-monitor-fallback.vala
@@ -0,0 +1,53 @@
+// This file is part of GNOME Games. License: GPLv3
+
+// FIXME Workaround the autotools working poorly with Vala.
+#if ENABLE_LINUX_GAMEPADS
+#if !ENABLE_UDEV
+private class Games.LinuxRawGamepadMonitor : Object, RawGamepadMonitor {
+       private static LinuxRawGamepadMonitor instance;
+
+       private HashTable<string, RawGamepad> raw_gamepads;
+
+       private LinuxRawGamepadMonitor () {
+               raw_gamepads = new HashTable<string, RawGamepad> (str_hash, str_equal);
+
+               // Coldplug gamepads
+               try {
+                       string directory = "/dev/input";
+                       Dir dir = Dir.open (directory, 0);
+                       string? name = null;
+                       while ((name = dir.read_name ()) != null) {
+                               string path = Path.build_filename (directory, name);
+                               RawGamepad raw_gamepad;
+                               try {
+                                       raw_gamepad = new LinuxRawGamepad (path);
+                               }
+                               catch (FileError e) {
+                                       if (!(e is FileError.NXIO))
+                                               debug ("Failed to open gamepad %s: %s\n", path, e.message);
+
+                                       continue;
+                               }
+
+                               raw_gamepads[name] = raw_gamepad;
+                               gamepad_plugged (raw_gamepad);
+                       }
+               } catch (FileError err) {
+                       debug (err.message);
+               }
+       }
+
+       public static LinuxRawGamepadMonitor get_instance () {
+               if (instance == null)
+                       instance = new LinuxRawGamepadMonitor ();
+
+               return instance;
+       }
+
+       public void foreach_gamepad (RawGamepadCallback callback) {
+               raw_gamepads.foreach((identifier, raw_gamepad) => callback (raw_gamepad));
+       }
+}
+
+#endif
+#endif
diff --git a/src/gamepad/linux/linux-raw-gamepad-monitor.vala 
b/src/gamepad/linux/linux-raw-gamepad-monitor.vala
index 908ad5c..ecc7376 100644
--- a/src/gamepad/linux/linux-raw-gamepad-monitor.vala
+++ b/src/gamepad/linux/linux-raw-gamepad-monitor.vala
@@ -2,6 +2,7 @@
 
 // FIXME Workaround the autotools working poorly with Vala.
 #if ENABLE_LINUX_GAMEPADS
+#if ENABLE_UDEV
 
 private class Games.LinuxRawGamepadMonitor : Object, RawGamepadMonitor {
        private static LinuxRawGamepadMonitor instance;
@@ -15,7 +16,7 @@ private class Games.LinuxRawGamepadMonitor : Object, RawGamepadMonitor {
 
                raw_gamepads = new HashTable<string, RawGamepad> (str_hash, str_equal);
 
-               // Initialize initially plugged in gamepads
+               // Coldplug gamepads
                var initial_devices_list = client.query_by_subsystem ("input");
                foreach (var device in initial_devices_list) {
                        if (device.get_device_file () == null)
@@ -99,3 +100,4 @@ private class Games.LinuxRawGamepadMonitor : Object, RawGamepadMonitor {
 }
 
 #endif
+#endif
diff --git a/src/gamepad/linux/linux-raw-gamepad.vala b/src/gamepad/linux/linux-raw-gamepad.vala
index e83c0ce..8a6bfaf 100644
--- a/src/gamepad/linux/linux-raw-gamepad.vala
+++ b/src/gamepad/linux/linux-raw-gamepad.vala
@@ -45,6 +45,9 @@ private class Games.LinuxRawGamepad : Object, RawGamepad {
                if (device.set_fd (fd) < 0)
                        throw new FileError.FAILED (_("Evdev is unable to open '%s': %s"), file_name, 
Posix.strerror (Posix.errno));
 
+               if (!is_joystick ())
+                       throw new FileError.NXIO ("'%s' is not a joystick", file_name);
+
                // Poll the events in the default main loop
                var channel = new IOChannel.unix_new (fd);
                event_source_id = channel.add_watch (IOCondition.IN, poll_events);
@@ -95,6 +98,33 @@ private class Games.LinuxRawGamepad : Object, RawGamepad {
                return true;
        }
 
+       private bool has_key (uint code) {
+               return device.has_event_code (Linux.Input.EV_KEY, code);
+       }
+
+       private bool has_abs (uint code) {
+               return device.has_event_code (Linux.Input.EV_ABS, code);
+       }
+
+       private bool is_joystick () {
+               /* Same detection code as udev-builtin-input_id.c in systemd
+                * joysticks don't necessarily have buttons; e. g.
+                * rudders/pedals are joystick-like, but buttonless; they have
+                * other fancy axes */
+               bool has_joystick_axes_or_buttons = has_key (Linux.Input.BTN_TRIGGER) ||
+                       has_key (Linux.Input.BTN_A) ||
+                       has_key (Linux.Input.BTN_1) ||
+                       has_abs (Linux.Input.ABS_RX) ||
+                       has_abs (Linux.Input.ABS_RY) ||
+                       has_abs (Linux.Input.ABS_RZ) ||
+                       has_abs (Linux.Input.ABS_THROTTLE) ||
+                       has_abs (Linux.Input.ABS_RUDDER) ||
+                       has_abs (Linux.Input.ABS_WHEEL) ||
+                       has_abs (Linux.Input.ABS_GAS) ||
+                       has_abs (Linux.Input.ABS_BRAKE);
+               return has_joystick_axes_or_buttons;
+       }
+
        private void handle_evdev_event () {
                Linux.Input.Event event;
                if (device.next_event (Libevdev.ReadFlag.NORMAL, out event) != 0)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]