#include "kbd.h"
#include "log.h"
+/* How many longs are needed to hold \n bits. */
+#define NLONGS(n) (((n) + LONG_BIT - 1) / LONG_BIT)
+
enum input_state {
INPUT_ASLEEP,
INPUT_AWAKE,
};
+/* See probe_device_features(). */
+enum device_feature {
+ FEATURE_HAS_KEYS = 0x01,
+};
+
struct kmscon_input_device {
size_t ref;
struct kmscon_input_device *next;
struct kmscon_input *input;
+ unsigned int features;
+
int rfd;
char *devnode;
struct kmscon_fd *fd;
return -errno;
}
- /* this rediscovers the keyboard state if sth changed during sleep */
- kmscon_kbd_reset(device->kbd, device->rfd);
+ if (device->features & FEATURE_HAS_KEYS) {
+ /* rediscover the keyboard state if sth changed during sleep */
+ kmscon_kbd_reset(device->kbd, device->rfd);
- ret = kmscon_eloop_new_fd(device->input->eloop, &device->fd,
- device->rfd, KMSCON_READABLE, device_data_arrived, device);
- if (ret) {
- close(device->rfd);
- device->rfd = -1;
- return ret;
+ ret = kmscon_eloop_new_fd(device->input->eloop, &device->fd,
+ device->rfd, KMSCON_READABLE,
+ device_data_arrived, device);
+ if (ret) {
+ close(device->rfd);
+ device->rfd = -1;
+ return ret;
+ }
}
return 0;
if (device->rfd < 0)
return;
- kmscon_eloop_rm_fd(device->fd);
+ if (device->features & FEATURE_HAS_KEYS)
+ kmscon_eloop_rm_fd(device->fd);
+
device->fd = NULL;
close(device->rfd);
device->rfd = -1;
}
static int kmscon_input_device_new(struct kmscon_input_device **out,
- struct kmscon_input *input, const char *devnode)
+ struct kmscon_input *input, const char *devnode,
+ unsigned int features)
{
int ret;
struct kmscon_input_device *device;
}
device->input = input;
+ device->features = features;
device->rfd = -1;
*out = device;
log_debug("input: destroying input object\n");
}
+/*
+ * See if the device has anything useful to offer.
+ * We go over the desired features and return a mask of enum device_feature's.
+ * */
+static unsigned int probe_device_features(const char *node)
+{
+ int i, fd;
+ unsigned int features = 0;
+ unsigned long evbits[NLONGS(EV_CNT)] = { 0 };
+ unsigned long keybits[NLONGS(KEY_CNT)] = { 0 };
+
+ fd = open(node, O_NONBLOCK | O_CLOEXEC);
+ if (fd < 0)
+ return 0;
+
+ /* Which types of input events the device supports. */
+ errno = 0;
+ ioctl(fd, EVIOCGBIT(0, sizeof(evbits)), evbits);
+ if (errno)
+ goto err_ioctl;
+
+ /* Device supports keys/buttons. */
+ if (kmscon_evdev_bit_is_set(evbits, EV_KEY)) {
+ errno = 0;
+ ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits);
+ if (errno)
+ goto err_ioctl;
+
+ /*
+ * If the device support any of the normal keyboard keys, we
+ * take it. Even if the keys are not ordinary they can be
+ * mapped to anything by the keyboard backend.
+ */
+ for (i = KEY_RESERVED; i <= KEY_MIN_INTERESTING; i++) {
+ if (kmscon_evdev_bit_is_set(keybits, i)) {
+ features |= FEATURE_HAS_KEYS;
+ break;
+ }
+ }
+ }
+
+ close(fd);
+ return features;
+
+err_ioctl:
+ if (errno != ENOTTY)
+ log_warn("input: cannot probe features of device (%s): %m\n",
+ node);
+ close(fd);
+ return 0;
+}
+
static void add_device(struct kmscon_input *input,
struct udev_device *udev_device)
{
int ret;
struct kmscon_input_device *device;
- const char *value, *node;
+ const char *node;
+ unsigned int features;
if (!input || !udev_device)
return;
- /*
- * TODO: Here should go a proper filtering of input devices we're
- * interested in. Currently, we add all kinds of devices. A simple
- * blacklist should be the easiest way.
- */
-
node = udev_device_get_devnode(udev_device);
if (!node)
return;
- value = udev_device_get_property_value(udev_device,
- "ID_INPUT_KEYBOARD");
- if (!value || strcmp(value, "1")) {
- log_debug("input: ignoring non-keyboard device %s\n", node);
+ features = probe_device_features(node);
+ if (!(features & FEATURE_HAS_KEYS)) {
+ log_debug("input: ignoring non-useful device %s\n", node);
return;
}
- ret = kmscon_input_device_new(&device, input, node);
+ ret = kmscon_input_device_new(&device, input, node, features);
if (ret) {
log_warn("input: cannot create input device for %s\n",
node);
device->next = input->devices;
input->devices = device;
- log_debug("input: added device %s\n", node);
+ log_debug("input: added device %s (features: %#x)\n", node, features);
}
static void remove_device(struct kmscon_input *input, const char *node)