summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2019-12-27 17:06:53 +0100
committerNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2019-12-27 17:06:53 +0100
commit60283fb1407fcd1de0586c960ed8d106f59483e9 (patch)
tree306d3daa5c409b0449b4151fa8939f88ddc84884 /src/device/virtual/virtual_device.c
parent4a9df9b604cec6ee4b4a6f01ef940443583f7573 (diff)
Got a clue about the pesky "SYN" messages.
I must not have read libevdev's documentation well enough. Hopefully this new approach will work better. The risk would be that the conversion takes too long and properly handling all events leads to an increasing lag between the physical and the virtual device. I should probably add an option to let users indicate they would prefer dropping missed events.
Diffstat (limited to 'src/device/virtual/virtual_device.c')
-rw-r--r--src/device/virtual/virtual_device.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/src/device/virtual/virtual_device.c b/src/device/virtual/virtual_device.c
new file mode 100644
index 0000000..19d1097
--- /dev/null
+++ b/src/device/virtual/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
+ );
+}
+