From 4e604b493e0dc855b6ea6978e5cf8e2de5d2b8d5 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sun, 28 Jul 2019 23:40:40 +0200 Subject: Fix evdev relative axes, add detect option --- backends/evdev.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++----- backends/evdev.h | 8 ++++++++ backends/evdev.md | 18 ++++++++++++------ 3 files changed, 72 insertions(+), 11 deletions(-) (limited to 'backends') diff --git a/backends/evdev.c b/backends/evdev.c index ca8469a..565eb17 100644 --- a/backends/evdev.c +++ b/backends/evdev.c @@ -27,6 +27,12 @@ typedef union { uint64_t label; } evdev_channel_ident; +static struct { + uint8_t detect; +} evdev_config = { + .detect = 0 +}; + int init(){ backend evdev = { .name = BACKEND_NAME, @@ -49,7 +55,15 @@ int init(){ } static int evdev_configure(char* option, char* value) { - fprintf(stderr, "The evdev backend does not take any global configuration\n"); + if(!strcmp(option, "detect")){ + evdev_config.detect = 1; + if(!strcmp(value, "off")){ + evdev_config.detect = 0; + } + return 0; + } + + fprintf(stderr, "Unknown configuration option %s for evdev backend\n", option); return 1; } @@ -185,6 +199,22 @@ static int evdev_configure_instance(instance* inst, char* option, char* value) { data->exclusive = 1; return 0; } + else if(!strncmp(option, "relaxis.", 8)){ + data->relative_axis = realloc(data->relative_axis, (data->relative_axes + 1) * sizeof(evdev_relaxis_config)); + if(!data->relative_axis){ + fprintf(stderr, "Failed to allocate memory\n"); + return 1; + } + data->relative_axis[data->relative_axes].code = libevdev_event_code_from_name(EV_REL, option + 8); + data->relative_axis[data->relative_axes].max = strtoul(value, &next_token, 0); + data->relative_axis[data->relative_axes].current = strtoul(next_token, NULL, 0); + if(data->relative_axis[data->relative_axes].code < 0){ + fprintf(stderr, "Failed to configure relative axis extents for %s.%s\n", inst->name, option + 8); + return 1; + } + data->relative_axes++; + return 0; + } #ifndef EVDEV_NO_UINPUT else if(!strcmp(option, "output")){ data->output_enabled = 1; @@ -214,7 +244,7 @@ static int evdev_configure_instance(instance* inst, char* option, char* value) { return 0; } #endif - fprintf(stderr, "Unknown configuration parameter %s for evdev backend\n", option); + fprintf(stderr, "Unknown instance configuration parameter %s for evdev instance %s\n", option, inst->name); return 1; } @@ -275,21 +305,32 @@ static int evdev_push_event(instance* inst, evdev_instance_data* data, struct in .fields.code = event.code }; channel* chan = mm_channel(inst, ident.label, 0); + size_t axis; if(chan){ val.raw.u64 = event.value; switch(event.type){ case EV_REL: - val.normalised = 0.5 + ((event.value < 0) ? 0.5 : -0.5); + for(axis = 0; axis < data->relative_axes; axis++){ + if(data->relative_axis[axis].code == event.code){ + data->relative_axis[axis].current = clamp(data->relative_axis[axis].current + event.value, data->relative_axis[axis].max, 0); + val.normalised = (double) data->relative_axis[axis].current / (double) data->relative_axis[axis].max; + break; + } + } + if(axis == data->relative_axes){ + val.normalised = 0.5 + ((event.value < 0) ? 0.5 : -0.5); + break; + } break; case EV_ABS: range = libevdev_get_abs_maximum(data->input_ev, event.code) - libevdev_get_abs_minimum(data->input_ev, event.code); - val.normalised = (event.value - libevdev_get_abs_minimum(data->input_ev, event.code)) / (double) range; + val.normalised = clamp((event.value - libevdev_get_abs_minimum(data->input_ev, event.code)) / (double) range, 1.0, 0.0); break; case EV_KEY: case EV_SW: default: - val.normalised = 1.0 * event.value; + val.normalised = clamp(1.0 * event.value, 1.0, 0.0); break; } @@ -299,6 +340,10 @@ static int evdev_push_event(instance* inst, evdev_instance_data* data, struct in } } + if(evdev_config.detect){ + fprintf(stderr, "Incoming evdev data for channel %s.%s.%s\n", inst->name, libevdev_event_type_get_name(event.type), libevdev_event_code_get_name(event.type, event.code)); + } + return 0; } @@ -470,6 +515,8 @@ static int evdev_shutdown(){ libevdev_free(data->output_proto); #endif + data->relative_axes = 0; + free(data->relative_axis); free(data); } diff --git a/backends/evdev.h b/backends/evdev.h index c6e3a25..d719631 100644 --- a/backends/evdev.h +++ b/backends/evdev.h @@ -24,10 +24,18 @@ static int evdev_shutdown(); #define UINPUT_MAX_NAME_SIZE 512 #endif +typedef struct /*_evdev_relative_axis_config*/ { + int code; + int64_t max; + int64_t current; +} evdev_relaxis_config; + typedef struct /*_evdev_instance_model*/ { int input_fd; struct libevdev* input_ev; int exclusive; + size_t relative_axes; + evdev_relaxis_config* relative_axis; int output_enabled; #ifndef EVDEV_NO_UINPUT diff --git a/backends/evdev.md b/backends/evdev.md index d750f1e..995b44c 100644 --- a/backends/evdev.md +++ b/backends/evdev.md @@ -7,7 +7,9 @@ This functionality may require elevated privileges (such as special group member #### Global configuration -This backend does not take any global configuration. +| Option | Example value | Default value | Description | +|---------------|-----------------------|-----------------------|-----------------------| +| `detect` | `on` | `off` | Output the channel specification for all events coming in on configured instances to help with configuration. | #### Instance configuration @@ -18,7 +20,8 @@ This backend does not take any global configuration. | `output` | `My Input Device` | none | Output device presentation name. Setting this option enables the instance for output | | `exclusive` | `1` | `0` | Prevent other processes from using the device | | `id` | `0x1 0x2 0x3` | none | Set output device bus identification (Vendor, Product and Version), optional | -| `axis.AXISNAME`| `34300 0 65536 255 4095` | none | Specify absolute axis details (see below) for output. This is required for any absolute axis to be output. +| `axis.AXISNAME`| `34300 0 65536 255 4095` | none | Specify absolute axis details (see below) for output. This is required for any absolute axis to be output. | +| `relaxis.AXISNAME`| `65534 32767` | none | Specify relative axis details (extent and optional initial value) for output and input (see below). | The absolute axis details configuration (e.g. `axis.ABS_X`) is required for any absolute axis on output-enabled instances. The configuration value contains, space-separated, the following values: @@ -34,6 +37,13 @@ If an axis is not used for output, this configuration can be omitted. For real devices, all of these parameters for every axis can be found by running `evtest` on the device. +To use the input from relative axes in absolute-value based protocols, the backend needs a reference frame to +convert the relative movements to absolute values. + +If relative axes are used without specifying their extents, the channel will generate normalized values +of `0`, `0.5` and `1` for any input less than, equal to and greater than `0`, respectively. As for output, only +the values `-1`, `0` and `1` are generated for the same interval. + #### Channel specification A channel is specified by its event type and event code, separated by `.`. For a complete list of event types and codes @@ -64,10 +74,6 @@ Input devices may synchronize logically connected event types (for example, X an events. The MIDIMonster also generates these events after processing channel events, but may not keep the original event grouping. -Relative axes (`EV_REL`-type events), such as generated by mouses, are currently handled in a very basic fashion, -generating only the normalized channel values of `0`, `0.5` and `1` for any input less than, equal to and greater -than `0`, respectively. As for output, only the values `-1`, `0` and `1` are generated for the same interval. - `EV_KEY` key-down events are sent for normalized channel values over `0.9`. Extended event type values such as `EV_LED`, `EV_SND`, etc are recognized in the MIDIMonster configuration file -- cgit v1.2.3