summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2019-12-23 15:44:19 +0100
committerNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2019-12-23 15:44:19 +0100
commit390576c3839ee7abb845e27b7267de45495e6b2f (patch)
treec481c37c868ccc65a3476f60b17369b21a90b79b /src/device/virtual_device.c
parent4355548f79375a62bb5e3bb5695190d48e4c0bc3 (diff)
Starting to turn relabsd into a proper daemon...
Diffstat (limited to 'src/device/virtual_device.c')
-rw-r--r--src/device/virtual_device.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/src/device/virtual_device.c b/src/device/virtual_device.c
new file mode 100644
index 0000000..19d1097
--- /dev/null
+++ b/src/device/virtual_device.c
@@ -0,0 +1,272 @@
+
+
+static void replace_rel_axes
+(
+ struct relabsd_virtual_device * const dev,
+ const struct relabsd_config * const config
+)
+{
+ int i;
+ struct input_absinfo absinfo;
+ unsigned int abs_code, rel_code;
+
+ for (i = RELABSD_VALID_AXES_COUNT; i --> 0;)
+ {
+ if (config->axis[i].enabled)
+ {
+ rel_code = relabsd_axis_to_rel((enum relabsd_axis) i);
+ abs_code = relabsd_axis_to_abs((enum relabsd_axis) i);
+
+ relabsd_config_get_absinfo(config, (enum relabsd_axis) i, &absinfo);
+ libevdev_disable_event_code(dev->dev, EV_REL, rel_code);
+ libevdev_enable_event_code(dev->dev, EV_ABS, abs_code, &absinfo);
+ }
+ }
+
+}
+
+static int rename_device
+(
+ struct libevdev * const dev,
+ const struct relabsd_config * const config
+)
+{
+ size_t new_name_size;
+ char * new_name;
+ const char * real_name;
+
+ /* +2: One for the \0, one for the space between prefix and 'real_name'. */
+ new_name_size = strlen(RELABSD_DEVICE_PREFIX) + 2;
+
+ if (config->device_name == (char *) NULL)
+ {
+ /* XXX
+ * "The name is never NULL but it may be the empty string."
+ * I'm assuming that since they use the term 'string', it is \0
+ * terminated.
+ */
+ real_name = libevdev_get_name(dev);
+ }
+ else
+ {
+ real_name = config->device_name;
+ }
+
+ new_name_size += strlen(real_name);
+
+ new_name = (char *) calloc(new_name_size, sizeof(char));
+
+ if (new_name == (char *) NULL)
+ {
+ RELABSD_ERROR
+ (
+ "Attempt at allocating memory to create the virtual device's name "
+ "failed: %s.",
+ strerror(errno)
+ );
+
+ /* This frees whatever came from 'libevdev_get_name'. */
+ libevdev_set_name(dev, RELABSD_DEVICE_PREFIX);
+
+ return -1;
+ }
+
+ if
+ (
+ snprintf
+ (
+ new_name,
+ new_name_size,
+ "%s %s",
+ RELABSD_DEVICE_PREFIX,
+ real_name
+ )
+ != ((int) (new_name_size - 1))
+ )
+ {
+ /* This makes for a great message when strerror(errno) returns SUCCESS. */
+ RELABSD_ERROR
+ (
+ "Something unexpected happened while renaming the virtual device: %s.",
+ strerror(errno)
+ );
+
+ /* This frees whatever came from 'libevdev_get_name'. */
+ libevdev_set_name(dev, RELABSD_DEVICE_PREFIX);
+
+ free((void *) new_name);
+
+ return -1;
+ }
+
+ /* This frees whatever came from 'libevdev_get_name'. */
+ libevdev_set_name(dev, new_name);
+ free((void *) new_name);
+
+ return 0;
+}
+
+int relabsd_virtual_device_create
+(
+ struct relabsd_virtual_device * const dev,
+ const struct relabsd_config * const config
+)
+{
+ int fd;
+
+ RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Creating virtual device...");
+
+ fd = open(config->input_file, O_RDONLY);
+
+ if (fd < 0)
+ {
+ RELABSD_FATAL
+ (
+ "Could not open device '%s' in read only mode: %s.",
+ config->input_file,
+ strerror(errno)
+ );
+
+ return -1;
+ }
+
+ if (libevdev_new_from_fd(fd, &(dev->dev)) < 0)
+ {
+ RELABSD_FATAL
+ (
+ "libevdev could not open '%s': '%s'.",
+ config->input_file,
+ strerror(errno)
+ );
+
+ close(fd);
+
+ return -1;
+ }
+
+ if (rename_device(dev->dev, config) < 0)
+ {
+ libevdev_free(dev->dev);
+ close(fd);
+
+ return -1;
+ }
+
+ libevdev_enable_event_type(dev->dev, EV_ABS);
+
+ replace_rel_axes(dev, config);
+
+ if
+ (
+ libevdev_uinput_create_from_device
+ (
+ dev->dev,
+ /* See top of the file. */
+ RELABSD_UINPUT_OPEN_MANAGED,
+ &(dev->uidev)
+ )
+ < 0
+ )
+ {
+ RELABSD_FATAL("Could not create relabsd device: %s.", strerror(errno));
+
+ libevdev_free(dev->dev);
+
+ close(fd);
+
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+void relabsd_virtual_device_destroy (const struct relabsd_virtual_device * const dev)
+{
+ RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Destroying virtual device...");
+
+ libevdev_uinput_destroy(dev->uidev);
+ libevdev_free(dev->dev);
+}
+
+int relabsd_virtual_device_write_evdev_event
+(
+ const struct relabsd_virtual_device * const dev,
+ unsigned int const type,
+ unsigned int const code,
+ int const value
+)
+{
+ RELABSD_DEBUG
+ (
+ RELABSD_DEBUG_VIRTUAL_EVENTS,
+ "Sending event: {type = %s; code = %s; value = %d}.",
+ libevdev_event_type_get_name(type),
+ libevdev_event_code_get_name(type, code),
+ value
+ );
+
+ /*
+ * We'll also send the 'EV_SYN' events when we receive them from the input
+ * device.
+ * OPTIMIZE: prevent 'EV_SYN' from being sent if we haven't sent any new
+ * values. (It might not be worth it though)
+ */
+ if (libevdev_uinput_write_event(dev->uidev, type, code, value) == 0)
+ {
+ /* FIXME:
+ * Why does activating the timeout trigger the EV_KEYS event to not be
+ * followed by EV_SYN?
+ */
+ if (type == EV_KEY)
+ {
+ libevdev_uinput_write_event
+ (
+ dev->uidev,
+ EV_SYN,
+ SYN_REPORT,
+ 0
+ );
+ }
+
+ return 0;
+ }
+
+ return -1;
+}
+
+void relabsd_virtual_device_set_axes_to_zero
+(
+ const struct relabsd_virtual_device * const dev,
+ const struct relabsd_config * const config
+)
+{
+ int i;
+
+ for (i = 0; i < RELABSD_VALID_AXES_COUNT; ++i)
+ {
+ if (config->axis[i].enabled)
+ {
+ relabsd_virtual_device_write_evdev_event
+ (
+ dev,
+ EV_ABS,
+ relabsd_axis_to_abs((enum relabsd_axis) i),
+ 0
+ );
+ }
+ }
+
+ /*
+ * Also send a SYN event when the axes have been modified.
+ */
+ libevdev_uinput_write_event
+ (
+ dev->uidev,
+ EV_SYN,
+ SYN_REPORT,
+ 0
+ );
+}
+