diff --git a/steam-runtime-tools/meson.build b/steam-runtime-tools/meson.build
index c9c3edd5d4b424b82c226263c095ba5986b19026..f92ef4792c4e63d16b36494b46d6e7bb65045a3d 100644
--- a/steam-runtime-tools/meson.build
+++ b/steam-runtime-tools/meson.build
@@ -50,6 +50,8 @@ libsteamrt_sources = [
     'resolve-in-sysroot.c',
     'runtime-internal.h',
     'runtime.c',
+    'simple-input-device-internal.h',
+    'simple-input-device.c',
     'steam-internal.h',
     'steam.c',
     'system-info.c',
diff --git a/steam-runtime-tools/simple-input-device-internal.h b/steam-runtime-tools/simple-input-device-internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..49c158368157daee8617fe21ff9352f4ef839b8d
--- /dev/null
+++ b/steam-runtime-tools/simple-input-device-internal.h
@@ -0,0 +1,108 @@
+/*<private_header>*/
+/*
+ * Copyright © 1997-2020 Sam Lantinga <slouken@libsdl.org>
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: Zlib
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#pragma once
+
+#include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/input-device-internal.h"
+
+#include <json-glib/json-glib.h>
+
+#define SRT_TYPE_SIMPLE_INPUT_DEVICE (_srt_simple_input_device_get_type ())
+
+typedef struct _SrtSimpleInputDevice SrtSimpleInputDevice;
+typedef struct _SrtSimpleInputDeviceClass SrtSimpleInputDeviceClass;
+
+#define SRT_TYPE_SIMPLE_INPUT_DEVICE (_srt_simple_input_device_get_type ())
+#define SRT_SIMPLE_INPUT_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SRT_TYPE_SIMPLE_INPUT_DEVICE, SrtSimpleInputDevice))
+#define SRT_IS_SIMPLE_INPUT_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SRT_TYPE_SIMPLE_INPUT_DEVICE))
+#define SRT_SIMPLE_INPUT_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SRT_TYPE_SIMPLE_INPUT_DEVICE, SrtSimpleInputDeviceClass))
+#define SRT_SIMPLE_INPUT_DEVICE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), SRT_TYPE_SIMPLE_INPUT_DEVICE, SrtSimpleInputDeviceClass))
+#define SRT_IS_SIMPLE_INPUT_DEVICE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), SRT_TYPE_SIMPLE_INPUT_DEVICE))
+
+G_GNUC_INTERNAL
+GType _srt_simple_input_device_get_type (void);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (SrtSimpleInputDevice, g_object_unref)
+
+struct _SrtSimpleInputDevice
+{
+  GObject parent;
+
+  gchar *dev_node;
+  gchar *sys_path;
+  gchar *subsystem;
+  gchar **udev_properties;
+  gchar *uevent;
+
+  struct
+  {
+    gchar *sys_path;
+    gchar *uevent;
+    gchar *name;
+    gchar *phys;
+    gchar *uniq;
+    guint32 bus_type;
+    guint32 product_id;
+    guint32 vendor_id;
+  } hid_ancestor;
+
+  struct
+  {
+    gchar *sys_path;
+    gchar *uevent;
+    gchar *name;
+    gchar *phys;
+    gchar *uniq;
+    guint32 bus_type;
+    guint32 product_id;
+    guint32 vendor_id;
+    guint32 version;
+  } input_ancestor;
+
+  struct
+  {
+    gchar *sys_path;
+    gchar *uevent;
+    gchar *manufacturer;
+    gchar *product;
+    gchar *serial;
+    guint32 product_id;
+    guint32 vendor_id;
+    guint32 device_version;
+  } usb_device_ancestor;
+
+  SrtEvdevCapabilities evdev_caps;
+  SrtInputDeviceInterfaceFlags iface_flags;
+  SrtInputDeviceTypeFlags type_flags;
+  guint32 bus_type;
+  guint32 vendor_id;
+  guint32 product_id;
+  guint32 version;
+};
+
+struct _SrtSimpleInputDeviceClass
+{
+  GObjectClass parent;
+};
diff --git a/steam-runtime-tools/simple-input-device.c b/steam-runtime-tools/simple-input-device.c
new file mode 100644
index 0000000000000000000000000000000000000000..9542c998f8addadca4eaef5eff9d630bc35d8842
--- /dev/null
+++ b/steam-runtime-tools/simple-input-device.c
@@ -0,0 +1,367 @@
+/*
+ * An input device loaded from JSON or similar.
+ *
+ * Copyright © 1997-2020 Sam Lantinga <slouken@libsdl.org>
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: Zlib
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include "steam-runtime-tools/simple-input-device-internal.h"
+
+#include <libglnx.h>
+
+#include "steam-runtime-tools/enums.h"
+#include "steam-runtime-tools/glib-backports-internal.h"
+#include "steam-runtime-tools/input-device.h"
+#include "steam-runtime-tools/input-device-internal.h"
+#include "steam-runtime-tools/utils-internal.h"
+
+static void srt_simple_input_device_iface_init (SrtInputDeviceInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (SrtSimpleInputDevice,
+                         _srt_simple_input_device,
+                         G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (SRT_TYPE_INPUT_DEVICE,
+                                                srt_simple_input_device_iface_init))
+
+static void
+_srt_simple_input_device_init (SrtSimpleInputDevice *self)
+{
+}
+
+static void
+srt_simple_input_device_finalize (GObject *object)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (object);
+
+  g_free (self->dev_node);
+  g_free (self->sys_path);
+  g_free (self->subsystem);
+  g_strfreev (self->udev_properties);
+  g_free (self->uevent);
+
+  g_free (self->hid_ancestor.sys_path);
+  g_free (self->hid_ancestor.uevent);
+  g_free (self->hid_ancestor.name);
+  g_free (self->hid_ancestor.phys);
+  g_free (self->hid_ancestor.uniq);
+
+  g_free (self->input_ancestor.sys_path);
+  g_free (self->input_ancestor.uevent);
+  g_free (self->input_ancestor.name);
+  g_free (self->input_ancestor.phys);
+  g_free (self->input_ancestor.uniq);
+
+  g_free (self->usb_device_ancestor.sys_path);
+  g_free (self->usb_device_ancestor.uevent);
+  g_free (self->usb_device_ancestor.manufacturer);
+  g_free (self->usb_device_ancestor.product);
+  g_free (self->usb_device_ancestor.serial);
+
+  G_OBJECT_CLASS (_srt_simple_input_device_parent_class)->finalize (object);
+}
+
+static void
+_srt_simple_input_device_class_init (SrtSimpleInputDeviceClass *cls)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (cls);
+
+  object_class->finalize = srt_simple_input_device_finalize;
+}
+
+static SrtInputDeviceInterfaceFlags
+srt_simple_input_device_get_interface_flags (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return self->iface_flags;
+}
+
+static SrtInputDeviceTypeFlags
+srt_simple_input_device_get_type_flags (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return self->type_flags;
+}
+
+static const char *
+srt_simple_input_device_get_dev_node (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return self->dev_node;
+}
+
+static const char *
+srt_simple_input_device_get_subsystem (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return self->subsystem;
+}
+
+static const char *
+srt_simple_input_device_get_sys_path (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return self->sys_path;
+}
+
+static gboolean
+srt_simple_input_device_get_identity (SrtInputDevice *device,
+                                      unsigned int *bus_type,
+                                      unsigned int *vendor_id,
+                                      unsigned int *product_id,
+                                      unsigned int *version)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  if (self->bus_type == 0
+      && self->vendor_id == 0
+      && self->product_id == 0
+      && self->version == 0)
+    return FALSE;
+
+  if (bus_type != NULL)
+    *bus_type = self->bus_type;
+
+  if (vendor_id != NULL)
+    *vendor_id = self->vendor_id;
+
+  if (product_id != NULL)
+    *product_id = self->product_id;
+
+  if (version != NULL)
+    *version = self->version;
+
+  return TRUE;
+}
+
+static gchar **
+srt_simple_input_device_dup_udev_properties (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return g_strdupv (self->udev_properties);
+}
+
+static gchar *
+srt_simple_input_device_dup_uevent (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return g_strdup (self->uevent);
+}
+
+static const SrtEvdevCapabilities *
+srt_simple_input_device_peek_event_capabilities (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return &self->evdev_caps;
+}
+
+static const char *
+srt_simple_input_device_get_hid_sys_path (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return self->hid_ancestor.sys_path;
+}
+
+static gboolean
+srt_simple_input_device_get_hid_identity (SrtInputDevice *device,
+                                          unsigned int *bus_type,
+                                          unsigned int *vendor_id,
+                                          unsigned int *product_id,
+                                          const char **name,
+                                          const char **phys,
+                                          const char **uniq)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  if (self->hid_ancestor.sys_path == NULL)
+    return FALSE;
+
+  if (bus_type != NULL)
+    *bus_type = self->hid_ancestor.bus_type;
+
+  if (vendor_id != NULL)
+    *vendor_id = self->hid_ancestor.vendor_id;
+
+  if (product_id != NULL)
+    *product_id = self->hid_ancestor.product_id;
+
+  if (name != NULL)
+    *name = self->hid_ancestor.name;
+
+  if (phys != NULL)
+    *phys = self->hid_ancestor.phys;
+
+  if (uniq != NULL)
+    *uniq = self->hid_ancestor.uniq;
+
+  return TRUE;
+}
+
+static gchar *
+srt_simple_input_device_dup_hid_uevent (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return g_strdup (self->hid_ancestor.uevent);
+}
+
+static const char *
+srt_simple_input_device_get_input_sys_path (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return self->input_ancestor.sys_path;
+}
+
+static gboolean
+srt_simple_input_device_get_input_identity (SrtInputDevice *device,
+                                            unsigned int *bus_type,
+                                            unsigned int *vendor_id,
+                                            unsigned int *product_id,
+                                            unsigned int *version,
+                                            const char **name,
+                                            const char **phys,
+                                            const char **uniq)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  if (self->input_ancestor.sys_path == NULL)
+    return FALSE;
+
+  if (bus_type != NULL)
+    *bus_type = self->input_ancestor.bus_type;
+
+  if (vendor_id != NULL)
+    *vendor_id = self->input_ancestor.vendor_id;
+
+  if (product_id != NULL)
+    *product_id = self->input_ancestor.product_id;
+
+  if (version != NULL)
+    *version = self->input_ancestor.version;
+
+  if (name != NULL)
+    *name = self->input_ancestor.name;
+
+  if (phys != NULL)
+    *phys = self->input_ancestor.phys;
+
+  if (uniq != NULL)
+    *uniq = self->input_ancestor.uniq;
+
+  return TRUE;
+}
+
+static gchar *
+srt_simple_input_device_dup_input_uevent (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return g_strdup (self->input_ancestor.uevent);
+}
+
+static const char *
+srt_simple_input_device_get_usb_device_sys_path (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return self->usb_device_ancestor.sys_path;
+}
+
+static gboolean
+srt_simple_input_device_get_usb_device_identity (SrtInputDevice *device,
+                                                 unsigned int *vendor_id,
+                                                 unsigned int *product_id,
+                                                 unsigned int *version,
+                                                 const char **manufacturer,
+                                                 const char **product,
+                                                 const char **serial)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  if (self->usb_device_ancestor.sys_path == NULL)
+    return FALSE;
+
+  if (vendor_id != NULL)
+    *vendor_id = self->usb_device_ancestor.vendor_id;
+
+  if (product_id != NULL)
+    *product_id = self->usb_device_ancestor.product_id;
+
+  if (version != NULL)
+    *version = self->usb_device_ancestor.device_version;
+
+  if (manufacturer != NULL)
+    *manufacturer = self->usb_device_ancestor.manufacturer;
+
+  if (product != NULL)
+    *product = self->usb_device_ancestor.product;
+
+  if (serial != NULL)
+    *serial = self->usb_device_ancestor.serial;
+
+  return TRUE;
+}
+
+static gchar *
+srt_simple_input_device_dup_usb_device_uevent (SrtInputDevice *device)
+{
+  SrtSimpleInputDevice *self = SRT_SIMPLE_INPUT_DEVICE (device);
+
+  return g_strdup (self->usb_device_ancestor.uevent);
+}
+
+static void
+srt_simple_input_device_iface_init (SrtInputDeviceInterface *iface)
+{
+#define IMPLEMENT(x) iface->x = srt_simple_input_device_ ## x
+
+  IMPLEMENT (get_type_flags);
+  IMPLEMENT (get_interface_flags);
+  IMPLEMENT (get_dev_node);
+  IMPLEMENT (get_sys_path);
+  IMPLEMENT (get_subsystem);
+  IMPLEMENT (get_identity);
+  IMPLEMENT (dup_udev_properties);
+  IMPLEMENT (dup_uevent);
+  IMPLEMENT (peek_event_capabilities);
+
+  IMPLEMENT (get_hid_sys_path);
+  IMPLEMENT (get_hid_identity);
+  IMPLEMENT (get_input_sys_path);
+  IMPLEMENT (get_input_identity);
+  IMPLEMENT (get_usb_device_sys_path);
+  IMPLEMENT (get_usb_device_identity);
+
+  IMPLEMENT (dup_hid_uevent);
+  IMPLEMENT (dup_input_uevent);
+  IMPLEMENT (dup_usb_device_uevent);
+
+#undef IMPLEMENT
+}
diff --git a/tests/mock-input-device.c b/tests/mock-input-device.c
index 591a0f026187cebd1ad0ff0f8c92c365b7869e53..d8308b4f0e353dacad2fa8cddbd05d3716579421 100644
--- a/tests/mock-input-device.c
+++ b/tests/mock-input-device.c
@@ -50,7 +50,7 @@ static void mock_input_device_monitor_iface_init (SrtInputDeviceMonitorInterface
 
 G_DEFINE_TYPE_WITH_CODE (MockInputDevice,
                          mock_input_device,
-                         G_TYPE_OBJECT,
+                         SRT_TYPE_SIMPLE_INPUT_DEVICE,
                          G_IMPLEMENT_INTERFACE (SRT_TYPE_INPUT_DEVICE,
                                                 mock_input_device_iface_init))
 
@@ -65,308 +65,14 @@ mock_input_device_init (MockInputDevice *self)
 {
 }
 
-static void
-mock_input_device_finalize (GObject *object)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (object);
-
-  g_clear_pointer (&self->sys_path, g_free);
-  g_clear_pointer (&self->dev_node, g_free);
-  g_clear_pointer (&self->subsystem, g_free);
-  g_clear_pointer (&self->udev_properties, g_strfreev);
-  g_clear_pointer (&self->uevent, g_free);
-
-  g_clear_pointer (&self->hid_ancestor.sys_path, g_free);
-  g_clear_pointer (&self->hid_ancestor.uevent, g_free);
-
-  g_clear_pointer (&self->input_ancestor.sys_path, g_free);
-  g_clear_pointer (&self->input_ancestor.uevent, g_free);
-
-  g_clear_pointer (&self->usb_device_ancestor.sys_path, g_free);
-  g_clear_pointer (&self->usb_device_ancestor.uevent, g_free);
-
-  G_OBJECT_CLASS (mock_input_device_parent_class)->finalize (object);
-}
-
 static void
 mock_input_device_class_init (MockInputDeviceClass *cls)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (cls);
-
-  object_class->finalize = mock_input_device_finalize;
-}
-
-static SrtInputDeviceTypeFlags
-mock_input_device_get_type_flags (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return self->type_flags;
-}
-
-static SrtInputDeviceInterfaceFlags
-mock_input_device_get_interface_flags (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return self->iface_flags;
-}
-
-static const char *
-mock_input_device_get_dev_node (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return self->dev_node;
-}
-
-static const char *
-mock_input_device_get_subsystem (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return self->subsystem;
-}
-
-static const char *
-mock_input_device_get_sys_path (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return self->sys_path;
-}
-
-static gboolean
-mock_input_device_get_identity (SrtInputDevice *device,
-                                unsigned int *bus_type,
-                                unsigned int *vendor_id,
-                                unsigned int *product_id,
-                                unsigned int *version)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  if (bus_type != NULL)
-    *bus_type = self->bus_type;
-
-  if (vendor_id != NULL)
-    *vendor_id = self->vendor_id;
-
-  if (product_id != NULL)
-    *product_id = self->product_id;
-
-  if (version != NULL)
-    *version = self->version;
-
-  return TRUE;
-}
-
-static gboolean
-mock_input_device_get_hid_identity (SrtInputDevice *device,
-                                        unsigned int *bus_type,
-                                        unsigned int *vendor_id,
-                                        unsigned int *product_id,
-                                        const char **name,
-                                        const char **phys,
-                                        const char **uniq)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  if (self->hid_ancestor.sys_path == NULL)
-    return FALSE;
-
-  if (bus_type != NULL)
-    *bus_type = self->hid_ancestor.bus_type;
-
-  if (vendor_id != NULL)
-    *vendor_id = self->hid_ancestor.vendor_id;
-
-  if (product_id != NULL)
-    *product_id = self->hid_ancestor.product_id;
-
-  if (name != NULL)
-    *name = self->hid_ancestor.name;
-
-  if (phys != NULL)
-    *phys = self->hid_ancestor.phys;
-
-  if (uniq != NULL)
-    *uniq = self->hid_ancestor.uniq;
-
-  return TRUE;
-}
-
-static gboolean
-mock_input_device_get_input_identity (SrtInputDevice *device,
-                                          unsigned int *bus_type,
-                                          unsigned int *vendor_id,
-                                          unsigned int *product_id,
-                                          unsigned int *version,
-                                          const char **name,
-                                          const char **phys,
-                                          const char **uniq)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  if (self->input_ancestor.sys_path == NULL)
-    return FALSE;
-
-  if (bus_type != NULL)
-    *bus_type = self->input_ancestor.bus_type;
-
-  if (vendor_id != NULL)
-    *vendor_id = self->input_ancestor.vendor_id;
-
-  if (product_id != NULL)
-    *product_id = self->input_ancestor.product_id;
-
-  if (version != NULL)
-    *version = self->input_ancestor.version;
-
-  if (name != NULL)
-    *name = self->input_ancestor.name;
-
-  if (phys != NULL)
-    *phys = self->input_ancestor.phys;
-
-  if (uniq != NULL)
-    *uniq = self->input_ancestor.uniq;
-
-  return TRUE;
-}
-
-static gboolean
-mock_input_device_get_usb_device_identity (SrtInputDevice *device,
-                                               unsigned int *vendor_id,
-                                               unsigned int *product_id,
-                                               unsigned int *device_version,
-                                               const char **manufacturer,
-                                               const char **product,
-                                               const char **serial)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  if (self->usb_device_ancestor.sys_path == NULL)
-    return FALSE;
-
-  if (vendor_id != NULL)
-    *vendor_id = self->usb_device_ancestor.vendor_id;
-
-  if (product_id != NULL)
-    *product_id = self->usb_device_ancestor.product_id;
-
-  if (device_version != NULL)
-    *device_version = self->usb_device_ancestor.device_version;
-
-  if (manufacturer != NULL)
-    *manufacturer = self->usb_device_ancestor.manufacturer;
-
-  if (product != NULL)
-    *product = self->usb_device_ancestor.product;
-
-  if (serial != NULL)
-    *serial = self->usb_device_ancestor.serial;
-
-  return TRUE;
-}
-
-static gchar **
-mock_input_device_dup_udev_properties (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return g_strdupv (self->udev_properties);
-}
-
-static gchar *
-mock_input_device_dup_uevent (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return g_strdup (self->uevent);
-}
-
-static const SrtEvdevCapabilities *
-mock_input_device_peek_event_capabilities (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return &self->evdev_caps;
-}
-
-static const char *
-mock_input_device_get_hid_sys_path (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return self->hid_ancestor.sys_path;
-}
-
-static gchar *
-mock_input_device_dup_hid_uevent (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return g_strdup (self->hid_ancestor.uevent);
-}
-
-static const char *
-mock_input_device_get_input_sys_path (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return self->input_ancestor.sys_path;
-}
-
-static gchar *
-mock_input_device_dup_input_uevent (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return g_strdup (self->input_ancestor.uevent);
-}
-
-static const char *
-mock_input_device_get_usb_device_sys_path (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return self->usb_device_ancestor.sys_path;
-}
-
-static gchar *
-mock_input_device_dup_usb_device_uevent (SrtInputDevice *device)
-{
-  MockInputDevice *self = MOCK_INPUT_DEVICE (device);
-
-  return g_strdup (self->usb_device_ancestor.uevent);
 }
 
 static void
 mock_input_device_iface_init (SrtInputDeviceInterface *iface)
 {
-#define IMPLEMENT(x) iface->x = mock_input_device_ ## x
-
-  IMPLEMENT (get_type_flags);
-  IMPLEMENT (get_interface_flags);
-  IMPLEMENT (get_dev_node);
-  IMPLEMENT (get_sys_path);
-  IMPLEMENT (get_subsystem);
-  IMPLEMENT (dup_udev_properties);
-  IMPLEMENT (dup_uevent);
-  IMPLEMENT (get_identity);
-  IMPLEMENT (peek_event_capabilities);
-
-  IMPLEMENT (get_hid_sys_path);
-  IMPLEMENT (dup_hid_uevent);
-  IMPLEMENT (get_hid_identity);
-  IMPLEMENT (get_input_sys_path);
-  IMPLEMENT (dup_input_uevent);
-  IMPLEMENT (get_input_identity);
-  IMPLEMENT (get_usb_device_sys_path);
-  IMPLEMENT (dup_usb_device_uevent);
-  IMPLEMENT (get_usb_device_identity);
-
-#undef IMPLEMENT
 }
 
 MockInputDevice *
@@ -512,7 +218,8 @@ add_steam_controller (MockInputDeviceMonitor *self,
                       const char *tail,
                       MockInputDevice **dev_out)
 {
-  g_autoptr(MockInputDevice) device = mock_input_device_new ();
+  g_autoptr(MockInputDevice) mock = mock_input_device_new ();
+  SrtSimpleInputDevice *device = SRT_SIMPLE_INPUT_DEVICE (mock);
   g_autoptr(GPtrArray) arr = g_ptr_array_new_full (1, g_free);
 
   device->iface_flags = (SRT_INPUT_DEVICE_INTERFACE_FLAGS_EVENT
@@ -582,10 +289,10 @@ add_steam_controller (MockInputDeviceMonitor *self,
   device->usb_device_ancestor.product = g_strdup ("Steam Controller");
   device->usb_device_ancestor.serial = NULL;
 
-  mock_input_device_monitor_add (self, device);
+  mock_input_device_monitor_add (self, mock);
 
   if (dev_out != NULL)
-    *dev_out = g_steal_pointer (&device);
+    *dev_out = g_steal_pointer (&mock);
 }
 
 static gboolean
diff --git a/tests/mock-input-device.h b/tests/mock-input-device.h
index 4124b4a038b593b97cc489aa9f975a7a39cd6830..afca72098ec74a8c797ce5549799910bd762b4a1 100644
--- a/tests/mock-input-device.h
+++ b/tests/mock-input-device.h
@@ -33,6 +33,7 @@
 #include "steam-runtime-tools/glib-backports-internal.h"
 #include "steam-runtime-tools/input-device.h"
 #include "steam-runtime-tools/input-device-internal.h"
+#include "steam-runtime-tools/simple-input-device-internal.h"
 
 typedef struct _MockInputDevice MockInputDevice;
 typedef struct _MockInputDeviceClass MockInputDeviceClass;
@@ -47,64 +48,12 @@ GType mock_input_device_get_type (void);
 
 struct _MockInputDevice
 {
-  GObject parent;
-
-  gchar *sys_path;
-  gchar *dev_node;
-  gchar *subsystem;
-  gchar **udev_properties;
-  gchar *uevent;
-  guint32 bus_type;
-  guint32 product_id;
-  guint32 vendor_id;
-  guint32 version;
-
-  SrtEvdevCapabilities evdev_caps;
-
-  struct
-  {
-    gchar *sys_path;
-    gchar *uevent;
-    gchar *name;
-    gchar *phys;
-    gchar *uniq;
-    guint32 bus_type;
-    guint32 product_id;
-    guint32 vendor_id;
-  } hid_ancestor;
-
-  struct
-  {
-    gchar *sys_path;
-    gchar *uevent;
-    gchar *name;
-    gchar *phys;
-    gchar *uniq;
-    guint32 bus_type;
-    guint32 product_id;
-    guint32 vendor_id;
-    guint32 version;
-  } input_ancestor;
-
-  struct
-  {
-    gchar *sys_path;
-    gchar *uevent;
-    gchar *manufacturer;
-    gchar *product;
-    gchar *serial;
-    guint32 product_id;
-    guint32 vendor_id;
-    guint32 device_version;
-  } usb_device_ancestor;
-
-  SrtInputDeviceTypeFlags type_flags;
-  SrtInputDeviceInterfaceFlags iface_flags;
+  SrtSimpleInputDevice parent;
 };
 
 struct _MockInputDeviceClass
 {
-  GObjectClass parent;
+  SrtSimpleInputDeviceClass parent;
 };
 
 MockInputDevice *mock_input_device_new (void);