You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
2.3 KiB
128 lines
2.3 KiB
#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; |
|
} |
|
|
|
|