#include #include #include #include #include #include #include #include #include #include "input_dev.h" #include #include static const char *input_path = "/dev/input/"; static struct libevdev* ev_matches(const char* sysfs_entry, const uinput_filters_t* const filters) { struct libevdev *dev = NULL; int fd = open(sysfs_entry, O_RDWR); if (fd < 0) { fprintf(stderr, "Cannot open %s, device skipped.\n", sysfs_entry); return NULL; } if (libevdev_new_from_fd(fd, &dev) != 0) { fprintf(stderr, "Cannot initialize libevdev from this device (%s): skipping.\n", sysfs_entry); close(fd); return NULL; } const char* name = libevdev_get_name(dev); if ((name != NULL) && (strcmp(name, filters->name) != 0)) { fprintf(stderr, "The device name (%s) for device %s does not matches the expected one %s.\n", name, sysfs_entry, filters->name); libevdev_free(dev); close(fd); return NULL; } const int grab_res = libevdev_grab(dev, LIBEVDEV_GRAB); if (grab_res != 0) { fprintf(stderr, "Unable to grab the device (%s): %d.\n", sysfs_entry, grab_res); //libevdev_free(dev); //close(fd); return dev; } return dev; } static pthread_mutex_t input_acquire_mutex = PTHREAD_MUTEX_INITIALIZER; static char* open_sysfs[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; void* input_read_thread_func(void* ptr) { struct libevdev* dev = (struct libevdev*)ptr; int rc = 1; do { struct input_event ev; rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_BLOCKING, &ev); if (rc == 0) { printf( "Device: %s, Event: %s %s %d\n", libevdev_get_name(dev), libevdev_event_type_get_name(ev.type), libevdev_event_code_get_name(ev.type, ev.code), ev.value ); } } while (rc == 1 || rc == 0 || rc == -EAGAIN); return NULL; } void *input_dev_thread_func(void *ptr) { input_dev_t *in_dev = (input_dev_t*)ptr; struct libevdev* dev = NULL; int open_sysfs_idx = -1; for (;;) { const uint32_t flags = in_dev->crtl_flags; if (flags & INPUT_DEV_CTRL_FLAG_EXIT) { in_dev->crtl_flags &= ~INPUT_DEV_CTRL_FLAG_EXIT; break; } // clean up from previous iteration if (dev != NULL) { libevdev_free(dev); dev = NULL; } const int input_acquire_lock_result = pthread_mutex_lock(&input_acquire_mutex); if (input_acquire_lock_result != 0) { fprintf(stderr, "Cannot lock input mutex: %d, will retry later...\n", input_acquire_lock_result); usleep(250000); continue; } // clean up leftover from previous opening if (open_sysfs_idx >= 0) { free(open_sysfs[open_sysfs_idx]); open_sysfs[open_sysfs_idx] = NULL; } char path[512] = "\0"; DIR *d; struct dirent *dir; d = opendir(input_path); if (d) { while ((dir = readdir(d)) != NULL) { if (dir->d_name[0] == '.') { continue; } else if (dir->d_name[0] == 'b') { // by-id continue; } else if (dir->d_name[0] == 'j') { // js-0 continue; } sprintf(path, "%s%s", input_path, dir->d_name); // check if that has been already opened // open_sysfs int skip = 0; for (int o = 0; o < (sizeof(open_sysfs) / sizeof(const char*)); ++o) { if ((open_sysfs[o] != NULL) && (strcmp(open_sysfs[o], path) == 0)) { skip = 1; break; } } if (skip) { continue; } // try to open the device dev = ev_matches(path, in_dev->ev_filters); if (dev != NULL) { open_sysfs_idx = 0; while (open_sysfs[open_sysfs_idx] != NULL) { ++open_sysfs_idx; } open_sysfs[open_sysfs_idx] = malloc(sizeof(path)); memcpy(open_sysfs[open_sysfs_idx], path, 512); if (libevdev_has_event_type(dev, EV_FF)) { printf("Opened device %s\n name: %s\n rumble: %s\n", path, libevdev_get_name(dev), libevdev_has_event_code(dev, EV_FF, FF_RUMBLE) ? "true" : "false" ); } else { printf("Opened device %s\n name: %s\n rumble: no EV_FF\n", path, libevdev_get_name(dev) ); } break; } } closedir(d); } pthread_mutex_unlock(&input_acquire_mutex); if (dev == NULL) { usleep(250000); continue; } pthread_t incoming_events_thread; const int incoming_events_thread_creation = pthread_create(&incoming_events_thread, NULL, input_read_thread_func, (void*)dev); if (incoming_events_thread_creation != 0) { fprintf(stderr, "Error creating the input thread for device %s: %d\n", libevdev_get_name(dev), incoming_events_thread_creation); } if (incoming_events_thread_creation == 0) { pthread_join(incoming_events_thread, NULL); } } return NULL; }