aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2015-09-03 18:13:24 +0200
committerNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2015-09-03 18:13:24 +0200
commit385a3d17995dafde4f2b57f8d3a42d4d4782119d (patch)
tree13422e28afbb7e8957ad061c662d159c28a930c4
parent480288ca001564fa8c9fbdd72be442bbe7ee3d97 (diff)
downloadrelabsd-385a3d17995dafde4f2b57f8d3a42d4d4782119d.zip
relabsd-385a3d17995dafde4f2b57f8d3a42d4d4782119d.tar.bz2
Now support 'real' relative input devices, introduces 'options', the virtual device name is now prefixed to help matching it with udev.
-rw-r--r--CMakeLists.txt44
-rw-r--r--conf/space_navigator.conf14
-rw-r--r--src/config.c283
-rw-r--r--src/config.h15
-rw-r--r--src/relabsd_device.c91
-rw-r--r--udev.rules1
6 files changed, 400 insertions, 48 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3d274bd..003697f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,5 @@
-cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
+# 3.0 introduces line continuation.
project("relabsd")
@@ -66,10 +67,37 @@ else ()
endif (RELABSD_ENABLE_ERROR_LOCATION)
-option(RELABSD_REAL_FUZZ "Fuzz is relative to the real device's events." ON)
-if (RELABSD_REAL_FUZZ)
- target_compile_definitions(relabsd PUBLIC RELABSD_REAL_FUZZ)
- message(STATUS "[OPTION] Fuzz is relative to the real device's events.")
-else ()
- message(STATUS "[OPTION] Fuzz is relative to the emulated device's events.")
-endif (RELABSD_REAL_FUZZ)
+set(
+ RELABSD_OPTION_MAX_SIZE
+ "64"
+ CACHE
+ INTEGER
+ "Maximum number of characters in an axis option (name + params)."
+)
+target_compile_definitions(
+ relabsd
+ PUBLIC
+ "-DRELABSD_OPTION_MAX_SIZE=${RELABSD_OPTION_MAX_SIZE}"
+)
+message(
+ STATUS
+ "[OPTION] Axis options can contain up to ${RELABSD_OPTION_MAX_SIZE}\
+ characters (name + params)."
+)
+
+set(
+ RELABSD_DEVICE_PREFIX
+ "relabsd:"
+ CACHE
+ STRING
+ "String prefixing the name of the virtual device."
+)
+target_compile_definitions(
+ relabsd
+ PUBLIC
+ "-DRELABSD_DEVICE_PREFIX=\"${RELABSD_DEVICE_PREFIX}\""
+)
+message(
+ STATUS
+ "[OPTION] Virtual devices' names are prefixed by '${RELABSD_DEVICE_PREFIX}'."
+)
diff --git a/conf/space_navigator.conf b/conf/space_navigator.conf
index 4936713..aa18480 100644
--- a/conf/space_navigator.conf
+++ b/conf/space_navigator.conf
@@ -1,8 +1,8 @@
# 3DConnexion SpaceNavigator
-# AXIS MIN MAX FUZZ FLAT RESOLUTION
-X -350 350 0 0 1
-Y -350 350 0 0 1
-Z -350 350 0 0 1
-RX -350 350 0 0 1
-RY -350 350 0 0 1
-RZ -350 350 0 0 1
+# AXIS MIN MAX FUZZ FLAT RESOLUTION OPTIONS
+X -350 350 0 0 1 direct,real_fuzz
+Y -350 350 0 0 1 direct,real_fuzz
+Z -350 350 0 0 1 direct,real_fuzz
+RX -350 350 0 0 1 direct,real_fuzz
+RY -350 350 0 0 1 direct,real_fuzz
+RZ -350 350 0 0 1 direct,real_fuzz
diff --git a/src/config.c b/src/config.c
index 59974b5..02460d0 100644
--- a/src/config.c
+++ b/src/config.c
@@ -2,12 +2,16 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#include "error.h"
#include "pervasive.h"
#include "axis.h"
#include "config.h"
+#ifndef RELABSD_OPTION_MAX_SIZE
+ #define RELABSD_OPTION_MAX_SIZE 64
+#endif
/*
* "errno is never set to zero by any system call or library function."
* This file makes use of this, by setting it to zero and checking if
@@ -19,7 +23,7 @@
*/
/*
- * Returns -1 on error,
+ * Returns -1 on (fatal) error,
* 0 on EOF,
* 1 on newline.
*/
@@ -32,15 +36,21 @@ static int reach_next_line_or_eof (FILE * const f)
errno = 0;
- c = getc(f);
+ c = (char) getc(f);
while ((c != '\n') && c != EOF)
{
- c = getc(f);
+ c = (char) getc(f);
}
if (errno != 0)
{
+ RELABSD_FATAL
+ (
+ "[CONFIG] Error while attempting to reach EOF or next line: %s.",
+ strerror(errno)
+ );
+
errno = prev_errno;
return -1;
@@ -57,6 +67,141 @@ static int reach_next_line_or_eof (FILE * const f)
}
/*
+ * Returns -1 if the option was discarded (an error has been reported),
+ * 0 if the option was successfully parsed.
+ *
+ * ('length' - 1) is the number of relevant characters in 'name'.
+ * 'name' must support 'length' characters.
+ * name[length] will be set to \0, so it does not need to be when calling
+ * this function.
+ */
+static int parse_option
+(
+ struct relabsd_config * const conf,
+ enum relabsd_axis const axis,
+ char * const name,
+ int const length
+)
+{
+ name[length] = '\0';
+
+ if (strcmp(name, "direct") == 0)
+ {
+ conf->axis[axis].option[RELABSD_DIRECT_OPTION] = 1;
+ }
+ else if (strcmp(name, "real_fuzz") == 0)
+ {
+ conf->axis[axis].option[RELABSD_REAL_FUZZ_OPTION] = 1;
+ }
+ else if (strcmp(name, "framed") == 0)
+ {
+ conf->axis[axis].option[RELABSD_FRAMED_OPTION] = 1;
+ }
+ else
+ {
+ RELABSD_ERROR
+ (
+ "[CONFIG] Unknown option '%s' for axis '%s'.",
+ name,
+ relabsd_axis_to_name(axis)
+ );
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Returns -1 on error,
+ * 0 on EOF,
+ * 1 on newline.
+ */
+static int read_axis_options
+(
+ struct relabsd_config * const conf,
+ FILE * const f,
+ enum relabsd_axis const axis
+)
+{
+ char option[(RELABSD_OPTION_MAX_SIZE + 1)];
+ int i, prev_errno;
+ char c;
+
+ option[RELABSD_OPTION_MAX_SIZE] = '\0';
+
+ prev_errno = errno;
+
+ errno = 0;
+
+ memset(conf->axis[axis].option, 0, RELABSD_OPTIONS_COUNT * sizeof(int));
+
+ i = 0;
+
+ while (i <= RELABSD_OPTION_MAX_SIZE)
+ {
+ c = (char) getc(f);
+
+ if ((errno != 0) && (c == EOF))
+ {
+ RELABSD_FATAL
+ (
+ "[CONFIG] Reading error while parsing option name (axis '%s'): %s.",
+ relabsd_axis_to_name(axis),
+ strerror(errno)
+ );
+
+ errno = prev_errno;
+
+ return -1;
+ }
+
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ break;
+
+ case ',':
+ /* We parsed a new option and there is a least another. */
+ parse_option(conf, axis, option, i);
+
+ i = 0;
+
+ break;
+
+ case '\n':
+ parse_option(conf, axis, option, i);
+ errno = prev_errno;
+
+ return 1;
+
+ case EOF:
+ parse_option(conf, axis, option, i);
+ errno = prev_errno;
+
+ return 0;
+
+ default:
+ option[i] = c;
+ i++;
+
+ break;
+ }
+ }
+
+ RELABSD_FATAL
+ (
+ "[CONFIG] Option name '%s[...]' (axis '%s') is too long (%d chars max).",
+ option,
+ relabsd_axis_to_name(axis),
+ RELABSD_OPTION_MAX_SIZE
+ );
+
+ return -1;
+}
+
+/*
* Returns -1 on (fatal) error,
* 0 on succes.
*/
@@ -140,7 +285,7 @@ static int parse_axis_configuration_line
conf->axis[axis].enabled = 1;
conf->axis[axis].previous_value = 0;
- return 0;
+ return read_axis_options(conf, f, axis);
}
/*
@@ -157,11 +302,7 @@ static int read_config_line
{
if (!RELABSD_IS_PREFIX("#", prefix))
{
- if (parse_axis_configuration_line(conf, f, prefix) < 0)
- {
- /* Fatal error. */
- return -1;
- }
+ return parse_axis_configuration_line(conf, f, prefix);
}
return reach_next_line_or_eof(f);
@@ -295,7 +436,7 @@ int relabsd_config_parse
if (argc == 3)
{
- conf->device_name = "relabsd device";
+ conf->device_name = NULL;
}
else
{
@@ -314,50 +455,128 @@ int relabsd_config_parse
return 0;
}
-int relabsd_config_filter
+static int direct_filter
(
- struct relabsd_config * const conf,
- enum relabsd_axis const axis,
+ struct relabsd_config_axis * const axis,
int * const value
)
{
- if ((axis == RELABSD_UNKNOWN) || !conf->axis[axis].enabled)
+ if (abs(*value - axis->previous_value) <= axis->fuzz)
{
- return 0;
+ if (axis->option[RELABSD_REAL_FUZZ_OPTION])
+ {
+ axis->previous_value = *value;
+ }
+
+ return -1;
}
- if (abs(*value - conf->axis[axis].previous_value) <= conf->axis[axis].fuzz)
+ if (*value < axis->min)
{
-#ifdef RELABSD_REAL_FUZZ
- conf->axis[axis].previous_value = *value;
-#endif
+ *value = axis->min;
+ }
+ else if (*value > axis->max)
+ {
+ *value = axis->max;
+ }
+ else if (abs(*value) <= axis->flat)
+ {
+ *value = 0;
+ }
+ if (*value == axis->previous_value)
+ {
return -1;
}
- if (*value < conf->axis[axis].min)
+ axis->previous_value = *value;
+
+ return 1;
+}
+
+static int rel_to_abs_filter
+(
+ struct relabsd_config_axis * const axis,
+ int * const value
+)
+{
+ long int guard;
+
+ guard = (((long int) axis->previous_value) + ((long int) *value));
+
+ if (guard < ((long int) INT_MIN))
{
- *value = conf->axis[axis].min;
+ guard = ((long int) INT_MIN);
}
- else if (*value > conf->axis[axis].max)
+ else if (guard > ((long int) INT_MAX))
{
- *value = conf->axis[axis].max;
+ guard = ((long int) INT_MAX);
}
- else if (abs(*value) <= conf->axis[axis].flat)
+
+ *value = (int) guard;
+
+ if (axis->option[RELABSD_FRAMED_OPTION])
{
- *value = 0;
+ if (*value < axis->min)
+ {
+ *value = axis->min;
+ }
+ else if (*value > axis->max)
+ {
+ *value = axis->max;
+ }
+
+ if (*value == axis->previous_value)
+ {
+ return 0;
+ }
+
+ axis->previous_value = *value;
- /*
- * As long as the 'fuzz' test is done prior the 'flat' one, moving around
- * in the 'flat' zone won't trigger useless '0' value events.
- */
+ return 1;
}
+ else
+ {
+ if (*value == axis->previous_value)
+ {
+ return 0;
+ }
- /* TODO: handle conf->axis[axis].resolution */
+ axis->previous_value = *value;
+
+ if ((*value < axis->min) || (*value > axis->max))
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+}
+
+int relabsd_config_filter
+(
+ struct relabsd_config * const conf,
+ enum relabsd_axis const axis,
+ int * const value
+)
+{
+ if ((axis == RELABSD_UNKNOWN) || !conf->axis[axis].enabled)
+ {
+ return 0;
+ }
- conf->axis[axis].previous_value = *value;
+ /* TODO: handle conf->axis[axis].resolution */
- return 1;
+ if (conf->axis[axis].option[RELABSD_DIRECT_OPTION])
+ {
+ return direct_filter((conf->axis + axis), value);
+ }
+ else
+ {
+ return rel_to_abs_filter((conf->axis + axis), value);
+ }
}
void relabsd_config_get_absinfo
diff --git a/src/config.h b/src/config.h
index c0c83a7..07fcdfb 100644
--- a/src/config.h
+++ b/src/config.h
@@ -5,10 +5,25 @@
#include "axis.h"
+/* Number of options that can be configured. */
+#define RELABSD_OPTIONS_COUNT 3
+
+enum relabsd_option
+{
+ RELABSD_DIRECT_OPTION,
+ RELABSD_REAL_FUZZ_OPTION,
+ RELABSD_FRAMED_OPTION
+};
+
+
struct relabsd_config_axis
{
+/* relabsd axis properties */
int enabled;
int previous_value;
+ int option[RELABSD_OPTIONS_COUNT];
+
+/* Absolute axis properties */
int min;
int max;
int fuzz;
diff --git a/src/relabsd_device.c b/src/relabsd_device.c
index 0ca6993..e807ec6 100644
--- a/src/relabsd_device.c
+++ b/src/relabsd_device.c
@@ -2,6 +2,8 @@
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <libevdev/libevdev-uinput.h>
@@ -49,6 +51,87 @@ static void replace_rel_axes
}
+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_device_create
(
struct relabsd_device * const dev,
@@ -85,7 +168,13 @@ int relabsd_device_create
return -1;
}
- libevdev_set_name(dev->dev, config->device_name);
+ if (rename_device(dev->dev, config) < 0)
+ {
+ libevdev_free(dev->dev);
+ close(fd);
+
+ return -1;
+ }
libevdev_enable_event_type(dev->dev, EV_ABS);
diff --git a/udev.rules b/udev.rules
new file mode 100644
index 0000000..7a9b4c6
--- /dev/null
+++ b/udev.rules
@@ -0,0 +1 @@
+SUBSYSTEM=="input", ATTRS{name}=="relabsd:*", ENV{ID_INPUT_JOYSTICK}="1", ENV{ID_CLASS}="joystick"