aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md16
-rw-r--r--backends/evdev.c110
-rw-r--r--backends/evdev.h6
-rw-r--r--configs/evdev.conf2
-rw-r--r--monster.cfg8
5 files changed, 110 insertions, 32 deletions
diff --git a/README.md b/README.md
index 1f1979d..45f2267 100644
--- a/README.md
+++ b/README.md
@@ -259,11 +259,12 @@ This backend does not take any global configuration.
#### Instance configuration
-| Option | Example value | Default value | Description |
-|---------------|-----------------------|---------------|-----------------------------------------------|
-| `input` | `/dev/input/event1` | none | `evdev` device to use as input device |
-| `exclusive` | `1` | `0` | Prevent other processes from using the device |
-| `name` | `My Input Device` | none | Output device presentation name. Setting this option enables the instance for output |
+| Option | Example value | Default value | Description |
+|---------------|-----------------------|---------------|-------------------------------------------------------|
+| `device` | `/dev/input/event1` | none | `evdev` device to use as input device |
+| `input` | `Xbox Wireless` | none | Presentation name of evdev device to use as input (prefix-matched) |
+| `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.
@@ -288,7 +289,7 @@ see the [kernel documentation](https://www.kernel.org/doc/html/v4.12/input/event
* `EV_ABS` for absolute axes (such as Joysticks)
* `EV_REL` for relative axes (such as Mouses)
-The `evtest` tool is useful to gather information on devices active on the local system, including types, codes
+The `evtest` tool is useful to gather information on devices active on the local system, including names, types, codes
and configuration supported by these devices.
Example mapping:
@@ -318,9 +319,6 @@ than `0`, respectively. As for output, only the values `-1`, `0` and `1` are gen
Extended event type values such as `EV_LED`, `EV_SND`, etc are recognized in the MIDIMonster configuration file
but may or may not work with the internal channel mapping and normalization code.
-Input devices can currently only be specified by device node directly. There may be a facility to open input
-devices by presentation name in the future.
-
### The `loopback` backend
This backend allows the user to create logical mapping channels, for example to exchange triggering
diff --git a/backends/evdev.c b/backends/evdev.c
index ac63850..e26eb76 100644
--- a/backends/evdev.c
+++ b/backends/evdev.c
@@ -5,6 +5,10 @@
#include <unistd.h>
#include <sys/ioctl.h>
#include <libevdev/libevdev.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <linux/input.h>
#ifndef EVDEV_NO_UINPUT
#include <libevdev/libevdev-uinput.h>
#endif
@@ -75,37 +79,103 @@ static instance* evdev_instance(){
return inst;
}
+static int evdev_attach(instance* inst, evdev_instance_data* data, char* node){
+ if(data->input_fd >= 0){
+ fprintf(stderr, "Instance %s already was assigned an input device\n", inst->name);
+ return 1;
+ }
+
+ data->input_fd = open(node, O_RDONLY | O_NONBLOCK);
+ if(data->input_fd < 0){
+ fprintf(stderr, "Failed to open evdev input device node %s: %s\n", node, strerror(errno));
+ return 1;
+ }
+
+ if(libevdev_new_from_fd(data->input_fd, &data->input_ev)){
+ fprintf(stderr, "Failed to initialize libevdev for %s\n", node);
+ close(data->input_fd);
+ data->input_fd = -1;
+ return 1;
+ }
+
+ if(data->exclusive && libevdev_grab(data->input_ev, LIBEVDEV_GRAB)){
+ fprintf(stderr, "Failed to obtain exclusive device access on %s\n", node);
+ }
+
+ return 0;
+}
+
+static char* evdev_find(char* name){
+ int fd = -1;
+ struct dirent* file = NULL;
+ char file_path[PATH_MAX * 2];
+ DIR* nodes = opendir(INPUT_NODES);
+ char device_name[UINPUT_MAX_NAME_SIZE], *result = NULL;
+
+ if(!nodes){
+ fprintf(stderr, "Failed to query input device nodes in %s: %s", INPUT_NODES, strerror(errno));
+ return NULL;
+ }
+
+ for(file = readdir(nodes); file; file = readdir(nodes)){
+ if(!strncmp(file->d_name, INPUT_PREFIX, strlen(INPUT_PREFIX)) && file->d_type == DT_CHR){
+ snprintf(file_path, sizeof(file_path), "%s/%s", INPUT_NODES, file->d_name);
+
+ fd = open(file_path, O_RDONLY);
+ if(fd < 0){
+ fprintf(stderr, "Failed to access %s: %s\n", file_path, strerror(errno));
+ continue;
+ }
+
+ if(ioctl(fd, EVIOCGNAME(sizeof(device_name)), device_name) < 0){
+ fprintf(stderr, "Failed to read name for %s: %s\n", file_path, strerror(errno));
+ close(fd);
+ continue;
+ }
+
+ close(fd);
+
+ if(!strncmp(device_name, name, strlen(name))){
+ fprintf(stderr, "Matched name %s for %s: %s\n", device_name, name, file_path);
+ break;
+ }
+ }
+ }
+
+ if(file){
+ result = calloc(strlen(file_path) + 1, sizeof(char));
+ if(result){
+ strncpy(result, file_path, strlen(file_path));
+ }
+ }
+
+ closedir(nodes);
+ return result;
+}
+
static int evdev_configure_instance(instance* inst, char* option, char* value) {
evdev_instance_data* data = (evdev_instance_data*) inst->impl;
-#ifndef EVDEV_NO_UINPUT
char* next_token = NULL;
+#ifndef EVDEV_NO_UINPUT
struct input_absinfo abs_info = {
0
};
#endif
- if(!strcmp(option, "input")){
- if(data->input_fd >= 0){
- fprintf(stderr, "Instance %s already was assigned an input device\n", inst->name);
- return 1;
- }
-
- data->input_fd = open(value, O_RDONLY | O_NONBLOCK);
- if(data->input_fd < 0){
- fprintf(stderr, "Failed to open evdev input device node %s: %s\n", value, strerror(errno));
+ if(!strcmp(option, "device")){
+ return evdev_attach(inst, data, value);
+ }
+ else if(!strcmp(option, "input")){
+ next_token = evdev_find(value);
+ if(!next_token){
+ fprintf(stderr, "Failed to find evdev input device with name %s for instance %s\n", value, inst->name);
return 1;
}
-
- if(libevdev_new_from_fd(data->input_fd, &data->input_ev)){
- fprintf(stderr, "Failed to initialize libevdev for %s\n", value);
- close(data->input_fd);
- data->input_fd = -1;
+ if(evdev_attach(inst, data, next_token)){
+ free(next_token);
return 1;
}
-
- if(data->exclusive && libevdev_grab(data->input_ev, LIBEVDEV_GRAB)){
- fprintf(stderr, "Failed to obtain exclusive device access on %s\n", value);
- }
+ free(next_token);
}
else if(!strcmp(option, "exclusive")){
if(data->input_fd >= 0 && libevdev_grab(data->input_ev, LIBEVDEV_GRAB)){
@@ -114,7 +184,7 @@ static int evdev_configure_instance(instance* inst, char* option, char* value) {
data->exclusive = 1;
}
#ifndef EVDEV_NO_UINPUT
- else if(!strcmp(option, "name")){
+ else if(!strcmp(option, "output")){
data->output_enabled = 1;
libevdev_set_name(data->output_proto, value);
}
diff --git a/backends/evdev.h b/backends/evdev.h
index 89a08ae..c6e3a25 100644
--- a/backends/evdev.h
+++ b/backends/evdev.h
@@ -18,6 +18,12 @@ static int evdev_handle(size_t num, managed_fd* fds);
static int evdev_start();
static int evdev_shutdown();
+#define INPUT_NODES "/dev/input"
+#define INPUT_PREFIX "event"
+#ifndef UINPUT_MAX_NAME_SIZE
+ #define UINPUT_MAX_NAME_SIZE 512
+#endif
+
typedef struct /*_evdev_instance_model*/ {
int input_fd;
struct libevdev* input_ev;
diff --git a/configs/evdev.conf b/configs/evdev.conf
index 3a0fa4f..386e154 100644
--- a/configs/evdev.conf
+++ b/configs/evdev.conf
@@ -3,7 +3,7 @@ bind = * 6454
net = 0
[evdev xbox]
-input = /dev/input/event14
+device = /dev/input/event14
axis.ABS_X = 34300 0 65535 255 4095
axis.ABS_RZ = 34300 0 65535 255 4095
axis.ABS_Y = 34300 0 65535 255 4095
diff --git a/monster.cfg b/monster.cfg
index 8412e8c..34acbce 100644
--- a/monster.cfg
+++ b/monster.cfg
@@ -10,10 +10,10 @@ bind = 0.0.0.0
[artnet art]
universe = 1
-dest = 10.2.2.255
+dest = 129.13.215.0
[evdev in]
-input = /dev/input/event14
+input = Xbox Wireless Controller
[midi midi]
@@ -28,3 +28,7 @@ in.EV_ABS.ABS_X > sacn.1+2
in.EV_ABS.ABS_Y > sacn.3
in.EV_ABS.ABS_X > art.1+2
in.EV_ABS.ABS_Y > art.3
+in.EV_KEY.BTN_THUMBL > sacn.4
+in.EV_KEY.BTN_THUMBR > sacn.5
+in.EV_ABS.ABS_GAS > sacn.6+7
+in.EV_ABS.ABS_BRAKE > sacn.8