Skip to content

Commit

Permalink
Use inotify for hotplug detection (eliminate udev)
Browse files Browse the repository at this point in the history
The end result should (hopefully) be a little more robust (and systemd independent).

I no longer remember what possessed me to switch away from the original
inotify implementation, but udev detection seems to have caused
enough grief to warrant switching back.

This will probably break FreeBSD support without some kind of
inotify glue and/or a kqueue implementation. If any FreeBSD
users see this feel free to open an issue or submit a PR :P.
  • Loading branch information
rvaiya committed Feb 3, 2022
1 parent cc84f3d commit cc4992a
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 171 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ CFLAGS+=-DVERSION=\"$(VERSION)\" \
all: vkbd-uinput
vkbd-%:
mkdir -p bin
$(CC) $(CFLAGS) -O3 src/*.c src/vkbd/$(@:vkbd-%=%).c -o bin/keyd -ludev
$(CC) $(CFLAGS) -O3 src/*.c src/vkbd/$(@:vkbd-%=%).c -o bin/keyd -lpthread
debug:
CFLAGS+="-pedantic -Wall -Wextra -g" $(MAKE)
man:
Expand Down
128 changes: 128 additions & 0 deletions src/evdev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include "keyd.h"
#include <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <dirent.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
#include <stdlib.h>
#include <unistd.h>

int evdev_is_keyboard(const char *devnode)
{
int fd = open(devnode, O_RDONLY);
if (fd < 0) {
perror("open");
exit(-1);
}

uint8_t keymask[(KEY_CNT+7)/8];

if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof keymask), keymask) < 0) {
perror("ioctl");
fprintf(stderr, "WARNING: Failed to retrieve key bit for %s\n", devnode);
return 0;
}

int has_a = keymask[KEY_A/8] & (0x01 << (KEY_A%8));
int has_d = keymask[KEY_D/8] & (0x01 << (KEY_D%8));

close(fd);

return has_a && has_d;
}


struct worker {
pthread_t tid;
char path[1024];
int result;
} workers[256];

static void *is_keyboard_worker(void *worker)
{
struct worker *w = (struct worker*) worker;
w->result = evdev_is_keyboard(w->path);
}

/*
* Note: the returned array is owned by the function and
* should not be freed by the caller. Successive invocations
* invalidate devs.
*/

int evdev_get_keyboard_nodes(char **devs, int *ndevs)
{
struct dirent *ent;
int nkbds = 0;
int n = 0;

DIR *dh = opendir("/dev/input/");
if (!dh) {
perror("opendir /dev/input");
exit(-1);
}

n = 0;

while((ent = readdir(dh))) {
char path[1024];
if (strstr(ent->d_name, "event") == ent->d_name) {
assert(n < sizeof(workers)/sizeof(workers[0]));
struct worker *w = &workers[n++];
snprintf(w->path, sizeof(w->path), "/dev/input/%s", ent->d_name);
pthread_create(&w->tid, NULL, is_keyboard_worker, w);
}
}

closedir(dh);

*ndevs = 0;
while(n--) {
pthread_join(workers[n].tid, NULL);

if(workers[n].result)
devs[(*ndevs)++] = workers[n].path;
}
}

const char *evdev_device_name(const char *devnode)
{
static char name[256];

int fd = open(devnode, O_RDONLY);
if (fd < 0) {
perror("open");
exit(-1);
}

if (ioctl(fd, EVIOCGNAME(sizeof(name)), &name) == -1)
return NULL;

close(fd);
return name;
}

uint32_t evdev_device_id(const char *devnode)
{
struct input_id info;

int fd = open(devnode, O_RDONLY);
if (fd < 0) {
perror("open");
exit(-1);
}

if (ioctl(fd, EVIOCGID, &info) == -1) {
perror("ioctl");
exit(-1);
}

close(fd);
return info.vendor << 16 | info.product;
}

Loading

0 comments on commit cc4992a

Please sign in to comment.