| summaryrefslogtreecommitdiff |
diff options
| author | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2015-09-03 18:13:24 +0200 |
|---|---|---|
| committer | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2015-09-03 18:13:24 +0200 |
| commit | 385a3d17995dafde4f2b57f8d3a42d4d4782119d (patch) | |
| tree | 13422e28afbb7e8957ad061c662d159c28a930c4 | |
| parent | 480288ca001564fa8c9fbdd72be442bbe7ee3d97 (diff) | |
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.txt | 44 | ||||
| -rw-r--r-- | conf/space_navigator.conf | 14 | ||||
| -rw-r--r-- | src/config.c | 283 | ||||
| -rw-r--r-- | src/config.h | 15 | ||||
| -rw-r--r-- | src/relabsd_device.c | 91 | ||||
| -rw-r--r-- | udev.rules | 1 |
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" |


