diff options
| -rw-r--r-- | TODO | 1 | ||||
| -rw-r--r-- | backends/evdev.c | 57 | ||||
| -rw-r--r-- | backends/evdev.h | 8 | ||||
| -rw-r--r-- | backends/evdev.md | 18 | ||||
| -rw-r--r-- | monster.cfg | 4 | 
5 files changed, 75 insertions, 13 deletions
| @@ -3,5 +3,4 @@ Note source in channel value struct  Optimize core channel search (store backend offset)  Printing backend / Verbose mode -evdev relative axis size  mm_managed_fd.impl is not freed currently 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 diff --git a/monster.cfg b/monster.cfg index 7db3ec3..2e6f76f 100644 --- a/monster.cfg +++ b/monster.cfg @@ -1,6 +1,8 @@  [backend artnet]  bind = 0.0.0.0 +[backend evdev] +  [artnet art]  universe = 0  dest = 255.255.255.255 @@ -11,6 +13,6 @@ input = TPPS  [loopback loop]  [map] +mouse.EV_REL.REL_X > loop.chan0  art.{3..4}{4..3} > loop.chan{4..3}{3..4}  art.{1..10} > loop.data{1..10} -art.{500..599} > loop.test{500..599} | 
