input: remove old input subsystem
We are no longer using the old subsystem, so remove it. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
parent
199f4cbfa8
commit
4f0defca3f
@ -48,7 +48,6 @@ libkmscon_core_la_SOURCES = \
|
||||
src/log.c src/log.h \
|
||||
src/eloop.c src/eloop.h \
|
||||
src/vt.c src/vt.h \
|
||||
src/input.c src/input.h \
|
||||
src/vte.c src/vte.h \
|
||||
src/terminal.c src/terminal.h \
|
||||
src/pty.c src/pty.h \
|
||||
@ -65,12 +64,10 @@ libkmscon_core_la_SOURCES = \
|
||||
|
||||
if USE_XKBCOMMON
|
||||
libkmscon_core_la_SOURCES += \
|
||||
src/kbd_xkb.c src/kbd.h \
|
||||
external/imKStoUCS.c external/imKStoUCS.h \
|
||||
src/uterm_input_xkb.c
|
||||
else
|
||||
libkmscon_core_la_SOURCES += \
|
||||
src/kbd_dumb.c src/kbd.h \
|
||||
external/imKStoUCS.c external/imKStoUCS.h \
|
||||
src/uterm_input_dumb.c
|
||||
endif
|
||||
|
699
src/input.c
699
src/input.c
@ -1,699 +0,0 @@
|
||||
/*
|
||||
* kmscon - udev input hotplug and evdev handling
|
||||
*
|
||||
* Copyright (c) 2011 Ran Benita <ran234@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The main object kmscon_input discovers and monitors input devices, and
|
||||
* adds/removes them accordingly from the devices linked list.
|
||||
*
|
||||
* The udev monitor keeps running even while the object is in INPUT_ASLEEP.
|
||||
* We do this because we'll either lose track of the devices, or otherwise
|
||||
* have to re-scan the devices at every wakeup.
|
||||
*
|
||||
* The kmscon_input_device objects hold the file descriptors for their device
|
||||
* nodes. All events go through the input-object callback; there is currently
|
||||
* no "routing" or any differentiation between them. When the input is put to
|
||||
* sleep, all fd's are closed. When woken up, they are opened. There should be
|
||||
* not spurious events delivered. The initial state depends on the
|
||||
* kmscon_input's state.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libudev.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "conf.h"
|
||||
#include "eloop.h"
|
||||
#include "input.h"
|
||||
#include "kbd.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "input"
|
||||
|
||||
/* 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,
|
||||
FEATURE_HAS_LEDS = 0x02,
|
||||
};
|
||||
|
||||
struct kmscon_input_device {
|
||||
struct kmscon_input_device *next;
|
||||
struct kmscon_input *input;
|
||||
|
||||
unsigned int features;
|
||||
|
||||
int rfd;
|
||||
char *devnode;
|
||||
struct ev_fd *fd;
|
||||
|
||||
struct kmscon_kbd *kbd;
|
||||
};
|
||||
|
||||
struct kmscon_input {
|
||||
size_t ref;
|
||||
enum input_state state;
|
||||
struct kmscon_input_device *devices;
|
||||
|
||||
struct ev_eloop *eloop;
|
||||
struct kmscon_hook *hook;
|
||||
|
||||
struct udev *udev;
|
||||
struct udev_monitor *monitor;
|
||||
struct ev_fd *monitor_fd;
|
||||
|
||||
struct kmscon_kbd_desc *desc;
|
||||
};
|
||||
|
||||
static void remove_device(struct kmscon_input *input, const char *node);
|
||||
|
||||
static void notify_key(struct kmscon_input_device *device,
|
||||
uint16_t type, uint16_t code, int32_t value)
|
||||
{
|
||||
int ret;
|
||||
struct kmscon_input_event ev;
|
||||
struct kmscon_input *input;
|
||||
|
||||
if (type != EV_KEY)
|
||||
return;
|
||||
|
||||
input = device->input;
|
||||
ret = kmscon_kbd_process_key(device->kbd, value, code, &ev);
|
||||
|
||||
if (ret && ret != -ENOKEY)
|
||||
return;
|
||||
|
||||
if (ret != -ENOKEY)
|
||||
kmscon_hook_call(input->hook, input, &ev);
|
||||
}
|
||||
|
||||
static void device_data_arrived(struct ev_fd *fd, int mask, void *data)
|
||||
{
|
||||
int i;
|
||||
ssize_t len, n;
|
||||
struct kmscon_input_device *device = data;
|
||||
struct kmscon_input *input = device->input;
|
||||
struct input_event ev[16];
|
||||
|
||||
len = sizeof(ev);
|
||||
while (len == sizeof(ev)) {
|
||||
len = read(device->rfd, &ev, sizeof(ev));
|
||||
if (len < 0) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
break;
|
||||
|
||||
log_warn("reading device %s failed %d",
|
||||
device->devnode, errno);
|
||||
remove_device(input, device->devnode);
|
||||
} else if (len == 0) {
|
||||
log_debug("EOF device %s", device->devnode);
|
||||
remove_device(input, device->devnode);
|
||||
} else if (len % sizeof(*ev)) {
|
||||
log_warn("read invalid input_event");
|
||||
} else {
|
||||
n = len / sizeof(*ev);
|
||||
for (i = 0; i < n; i++)
|
||||
notify_key(device, ev[i].type, ev[i].code,
|
||||
ev[i].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int kmscon_input_device_wake_up(struct kmscon_input_device *device)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ledbits[NLONGS(LED_CNT)] = { 0 };
|
||||
|
||||
if (!device || !device->input || !device->input->eloop)
|
||||
return -EINVAL;
|
||||
|
||||
if (device->rfd >= 0)
|
||||
return 0;
|
||||
|
||||
device->rfd = open(device->devnode, O_CLOEXEC | O_NONBLOCK | O_RDONLY);
|
||||
if (device->rfd < 0) {
|
||||
log_warn("cannot open input device %s: %d",
|
||||
device->devnode, errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (device->features & FEATURE_HAS_KEYS) {
|
||||
if (device->features & FEATURE_HAS_LEDS) {
|
||||
errno = 0;
|
||||
ioctl(device->rfd, EVIOCGLED(sizeof(ledbits)),
|
||||
&ledbits);
|
||||
if (errno)
|
||||
log_warn("cannot discover state of LEDs %s: %m",
|
||||
device->devnode);
|
||||
}
|
||||
|
||||
/* rediscover the keyboard state if sth changed during sleep */
|
||||
kmscon_kbd_reset(device->kbd, ledbits);
|
||||
|
||||
ret = ev_eloop_new_fd(device->input->eloop, &device->fd,
|
||||
device->rfd, EV_READABLE,
|
||||
device_data_arrived, device);
|
||||
if (ret) {
|
||||
close(device->rfd);
|
||||
device->rfd = -1;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kmscon_input_device_sleep(struct kmscon_input_device *device)
|
||||
{
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
if (device->rfd < 0)
|
||||
return;
|
||||
|
||||
ev_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,
|
||||
unsigned int features)
|
||||
{
|
||||
int ret;
|
||||
struct kmscon_input_device *device;
|
||||
|
||||
if (!out || !input)
|
||||
return -EINVAL;
|
||||
|
||||
device = malloc(sizeof(*device));
|
||||
if (!device)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(device, 0, sizeof(*device));
|
||||
|
||||
device->devnode = strdup(devnode);
|
||||
if (!device->devnode) {
|
||||
free(device);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = kmscon_kbd_new(&device->kbd, input->desc);
|
||||
if (ret) {
|
||||
free(device->devnode);
|
||||
free(device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
device->input = input;
|
||||
device->features = features;
|
||||
device->rfd = -1;
|
||||
|
||||
log_debug("new input device %s", devnode);
|
||||
*out = device;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kmscon_input_device_free(struct kmscon_input_device *device)
|
||||
{
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
log_debug("destroying input device %s", device->devnode);
|
||||
kmscon_input_device_sleep(device);
|
||||
kmscon_kbd_unref(device->kbd);
|
||||
free(device->devnode);
|
||||
free(device);
|
||||
}
|
||||
|
||||
int kmscon_input_new(struct kmscon_input **out)
|
||||
{
|
||||
int ret;
|
||||
struct kmscon_input *input;
|
||||
|
||||
if (!out)
|
||||
return -EINVAL;
|
||||
|
||||
input = malloc(sizeof(*input));
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(input, 0, sizeof(*input));
|
||||
input->ref = 1;
|
||||
input->state = INPUT_ASLEEP;
|
||||
|
||||
ret = kmscon_hook_new(&input->hook);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
ret = kmscon_kbd_desc_new(&input->desc,
|
||||
conf_global.xkb_layout,
|
||||
conf_global.xkb_variant,
|
||||
conf_global.xkb_options);
|
||||
if (ret) {
|
||||
log_warn("cannot create xkb description");
|
||||
goto err_hook;
|
||||
}
|
||||
|
||||
input->udev = udev_new();
|
||||
if (!input->udev) {
|
||||
log_warn("cannot create udev object");
|
||||
ret = -EFAULT;
|
||||
goto err_xkb;
|
||||
}
|
||||
|
||||
input->monitor = udev_monitor_new_from_netlink(input->udev, "udev");
|
||||
if (!input->monitor) {
|
||||
log_warn("cannot create udev monitor");
|
||||
ret = -EFAULT;
|
||||
goto err_udev;
|
||||
}
|
||||
|
||||
ret = udev_monitor_filter_add_match_subsystem_devtype(input->monitor,
|
||||
"input", NULL);
|
||||
if (ret) {
|
||||
log_warn("cannot add udev filter");
|
||||
ret = -EFAULT;
|
||||
goto err_monitor;
|
||||
}
|
||||
|
||||
ret = udev_monitor_enable_receiving(input->monitor);
|
||||
if (ret) {
|
||||
log_warn("cannot start udev monitor");
|
||||
ret = -EFAULT;
|
||||
goto err_monitor;
|
||||
}
|
||||
|
||||
log_debug("new input object");
|
||||
*out = input;
|
||||
return 0;
|
||||
|
||||
err_monitor:
|
||||
udev_monitor_unref(input->monitor);
|
||||
err_udev:
|
||||
udev_unref(input->udev);
|
||||
err_xkb:
|
||||
kmscon_kbd_desc_unref(input->desc);
|
||||
err_hook:
|
||||
kmscon_hook_free(input->hook);
|
||||
err_free:
|
||||
free(input);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kmscon_input_ref(struct kmscon_input *input)
|
||||
{
|
||||
if (!input)
|
||||
return;
|
||||
|
||||
++input->ref;
|
||||
}
|
||||
|
||||
void kmscon_input_unref(struct kmscon_input *input)
|
||||
{
|
||||
if (!input || !input->ref || --input->ref)
|
||||
return;
|
||||
|
||||
log_debug("free input object");
|
||||
kmscon_input_disconnect_eloop(input);
|
||||
udev_monitor_unref(input->monitor);
|
||||
udev_unref(input->udev);
|
||||
kmscon_kbd_desc_unref(input->desc);
|
||||
kmscon_hook_free(input->hook);
|
||||
free(input);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kmscon_evdev_bit_is_set(evbits, EV_LED))
|
||||
features |= FEATURE_HAS_LEDS;
|
||||
|
||||
close(fd);
|
||||
return features;
|
||||
|
||||
err_ioctl:
|
||||
if (errno != ENOTTY)
|
||||
log_warn("cannot probe features of device (%s): %m", 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 *node, *seat;
|
||||
unsigned int features;
|
||||
|
||||
if (!input || !udev_device)
|
||||
return;
|
||||
|
||||
node = udev_device_get_devnode(udev_device);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
seat = udev_device_get_property_value(udev_device, "ID_SEAT");
|
||||
if (!seat)
|
||||
seat = "seat0";
|
||||
if (strcmp(seat, conf_global.seat)) {
|
||||
log_debug("ignoring device %s (wrong seat)", node);
|
||||
return;
|
||||
}
|
||||
|
||||
features = probe_device_features(node);
|
||||
if (!(features & FEATURE_HAS_KEYS)) {
|
||||
log_debug("ignoring non-useful device %s", node);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = kmscon_input_device_new(&device, input, node, features);
|
||||
if (ret) {
|
||||
log_warn("cannot create input device for %s", node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (input->state == INPUT_AWAKE) {
|
||||
ret = kmscon_input_device_wake_up(device);
|
||||
if (ret) {
|
||||
log_warn("cannot wake up new device %s", node);
|
||||
kmscon_input_device_free(device);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
device->next = input->devices;
|
||||
input->devices = device;
|
||||
log_debug("added device %s (features: %#x)", node, features);
|
||||
}
|
||||
|
||||
static void remove_device(struct kmscon_input *input, const char *node)
|
||||
{
|
||||
struct kmscon_input_device *iter, *prev;
|
||||
|
||||
if (!input || !node || !input->devices)
|
||||
return;
|
||||
|
||||
iter = input->devices;
|
||||
prev = NULL;
|
||||
|
||||
while (iter) {
|
||||
if (!strcmp(iter->devnode, node)) {
|
||||
if (prev == NULL)
|
||||
input->devices = iter->next;
|
||||
else
|
||||
prev->next = iter->next;
|
||||
|
||||
kmscon_input_device_free(iter);
|
||||
log_debug("removed device %s", node);
|
||||
break;
|
||||
}
|
||||
|
||||
prev = iter;
|
||||
iter = iter->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_device_udev(struct kmscon_input *input,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
const char *node;
|
||||
|
||||
node = udev_device_get_devnode(udev_device);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
remove_device(input, node);
|
||||
}
|
||||
|
||||
static void device_changed(struct ev_fd *fd, int mask, void *data)
|
||||
{
|
||||
struct kmscon_input *input = data;
|
||||
struct udev_device *udev_device;
|
||||
const char *action;
|
||||
|
||||
udev_device = udev_monitor_receive_device(input->monitor);
|
||||
if (!udev_device)
|
||||
return;
|
||||
|
||||
action = udev_device_get_action(udev_device);
|
||||
if (!action) {
|
||||
log_warn("cannot get action field of new device");
|
||||
goto err_device;
|
||||
}
|
||||
|
||||
if (!strcmp(action, "add"))
|
||||
add_device(input, udev_device);
|
||||
else if (!strcmp(action, "remove"))
|
||||
remove_device_udev(input, udev_device);
|
||||
|
||||
err_device:
|
||||
udev_device_unref(udev_device);
|
||||
}
|
||||
|
||||
static void add_initial_devices(struct kmscon_input *input)
|
||||
{
|
||||
int ret;
|
||||
struct udev_enumerate *e;
|
||||
struct udev_list_entry *first;
|
||||
struct udev_list_entry *item;
|
||||
struct udev_device *udev_device;
|
||||
const char *syspath;
|
||||
|
||||
e = udev_enumerate_new(input->udev);
|
||||
if (!e) {
|
||||
log_warn("cannot create udev enumeration");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = udev_enumerate_add_match_subsystem(e, "input");
|
||||
if (ret) {
|
||||
log_warn("cannot add match to udev enumeration");
|
||||
goto err_enum;
|
||||
}
|
||||
|
||||
if (strcmp(conf_global.seat, "seat0")) {
|
||||
ret = udev_enumerate_add_match_tag(e, conf_global.seat);
|
||||
if (ret) {
|
||||
log_warn("cannot add match to udev enumeration");
|
||||
goto err_enum;
|
||||
}
|
||||
}
|
||||
|
||||
ret = udev_enumerate_scan_devices(e);
|
||||
if (ret) {
|
||||
log_warn("cannot scan udev enumeration");
|
||||
goto err_enum;
|
||||
}
|
||||
|
||||
first = udev_enumerate_get_list_entry(e);
|
||||
udev_list_entry_foreach(item, first) {
|
||||
syspath = udev_list_entry_get_name(item);
|
||||
if (!syspath)
|
||||
continue;
|
||||
|
||||
udev_device = udev_device_new_from_syspath(input->udev, syspath);
|
||||
if (!udev_device)
|
||||
continue;
|
||||
|
||||
add_device(input, udev_device);
|
||||
udev_device_unref(udev_device);
|
||||
}
|
||||
|
||||
err_enum:
|
||||
udev_enumerate_unref(e);
|
||||
}
|
||||
|
||||
int kmscon_input_connect_eloop(struct kmscon_input *input,
|
||||
struct ev_eloop *eloop)
|
||||
{
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
if (!input || !eloop)
|
||||
return -EINVAL;
|
||||
|
||||
if (input->eloop)
|
||||
return -EALREADY;
|
||||
|
||||
fd = udev_monitor_get_fd(input->monitor);
|
||||
ret = ev_eloop_new_fd(eloop, &input->monitor_fd, fd,
|
||||
EV_READABLE, device_changed, input);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ev_eloop_ref(eloop);
|
||||
input->eloop = eloop;
|
||||
|
||||
add_initial_devices(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kmscon_input_disconnect_eloop(struct kmscon_input *input)
|
||||
{
|
||||
struct kmscon_input_device *tmp;
|
||||
|
||||
if (!input || !input->eloop)
|
||||
return;
|
||||
|
||||
while (input->devices) {
|
||||
tmp = input->devices;
|
||||
input->devices = tmp->next;
|
||||
kmscon_input_device_free(tmp);
|
||||
}
|
||||
|
||||
ev_eloop_rm_fd(input->monitor_fd);
|
||||
input->monitor_fd = NULL;
|
||||
ev_eloop_unref(input->eloop);
|
||||
input->eloop = NULL;
|
||||
}
|
||||
|
||||
int kmscon_input_register_cb(struct kmscon_input *input, kmscon_input_cb cb,
|
||||
void *data)
|
||||
{
|
||||
if (!input || !cb)
|
||||
return -EINVAL;
|
||||
|
||||
return kmscon_hook_add_cast(input->hook, cb, data);
|
||||
}
|
||||
|
||||
void kmscon_input_unregister_cb(struct kmscon_input *input, kmscon_input_cb cb,
|
||||
void *data)
|
||||
{
|
||||
if (!input || !cb)
|
||||
return;
|
||||
|
||||
kmscon_hook_rm_cast(input->hook, cb, data);
|
||||
}
|
||||
|
||||
void kmscon_input_sleep(struct kmscon_input *input)
|
||||
{
|
||||
struct kmscon_input_device *iter;
|
||||
|
||||
if (!input || input->state == INPUT_ASLEEP)
|
||||
return;
|
||||
|
||||
log_debug("going asleep");
|
||||
|
||||
for (iter = input->devices; iter; iter = iter->next)
|
||||
kmscon_input_device_sleep(iter);
|
||||
|
||||
input->state = INPUT_ASLEEP;
|
||||
}
|
||||
|
||||
void kmscon_input_wake_up(struct kmscon_input *input)
|
||||
{
|
||||
struct kmscon_input_device *iter, *prev, *tmp;
|
||||
int ret;
|
||||
|
||||
if (!input || input->state == INPUT_AWAKE)
|
||||
return;
|
||||
|
||||
log_debug("waking up");
|
||||
prev = NULL;
|
||||
iter = input->devices;
|
||||
|
||||
while (iter) {
|
||||
ret = kmscon_input_device_wake_up(iter);
|
||||
if (ret) {
|
||||
if (!prev)
|
||||
input->devices = iter->next;
|
||||
else
|
||||
prev->next = iter->next;
|
||||
|
||||
tmp = iter;
|
||||
iter = iter->next;
|
||||
|
||||
log_warn("device %s does not wake up, removing device",
|
||||
tmp->devnode);
|
||||
kmscon_input_device_free(tmp);
|
||||
} else {
|
||||
prev = iter;
|
||||
iter = iter->next;
|
||||
}
|
||||
}
|
||||
|
||||
input->state = INPUT_AWAKE;
|
||||
}
|
||||
|
||||
bool kmscon_input_is_asleep(struct kmscon_input *input)
|
||||
{
|
||||
if (!input)
|
||||
return false;
|
||||
|
||||
return input->state == INPUT_ASLEEP;
|
||||
}
|
103
src/input.h
103
src/input.h
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* kmscon - udev input hotplug and evdev handling
|
||||
*
|
||||
* Copyright (c) 2011 Ran Benita <ran234@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This module provides an input object which can deliver all useful input
|
||||
* events to the program.
|
||||
*
|
||||
* Its use should be as simple as the following (but also see below):
|
||||
* - Create a new input object.
|
||||
* - Provide a callback function to receive the events.
|
||||
* - Connect the input object to a ev_eloop.
|
||||
* - Wake up the input object to begin receiving input events through the
|
||||
* event loop.
|
||||
*
|
||||
* A few things to note:
|
||||
* - This module uses evdev for input, and reads from input devices directly.
|
||||
* This requires root privileges; waking up the input object will fail
|
||||
* without them.
|
||||
* - evdev has no inhert notion of "focus" like tty input. In other words,
|
||||
* it will deliver input events whether they are intended for the program
|
||||
* or not. This may also pose a security risk. Therefore, make sure to put
|
||||
* the object to sleep when the program is not active, for example by
|
||||
* reacting to VT changes.
|
||||
*/
|
||||
|
||||
#ifndef KMSCON_INPUT_H
|
||||
#define KMSCON_INPUT_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include "eloop.h"
|
||||
|
||||
struct kmscon_input;
|
||||
|
||||
enum kmscon_modifier {
|
||||
KMSCON_SHIFT_MASK = (1 << 0),
|
||||
KMSCON_LOCK_MASK = (1 << 1),
|
||||
KMSCON_CONTROL_MASK = (1 << 2),
|
||||
KMSCON_MOD1_MASK = (1 << 3),
|
||||
KMSCON_MOD2_MASK = (1 << 4),
|
||||
KMSCON_MOD3_MASK = (1 << 5),
|
||||
KMSCON_MOD4_MASK = (1 << 6),
|
||||
KMSCON_MOD5_MASK = (1 << 7),
|
||||
};
|
||||
|
||||
#define KMSCON_INPUT_INVALID 0xffffffff
|
||||
|
||||
struct kmscon_input_event {
|
||||
uint16_t keycode; /* linux keycode - KEY_* - linux/input.h */
|
||||
uint32_t keysym; /* X keysym - XK_* - X11/keysym.h */
|
||||
unsigned int mods; /* active modifiers - kmscon_modifier mask */
|
||||
uint32_t unicode; /* UCS-4 unicode value or KMSCON_INPUT_INVALID */
|
||||
};
|
||||
|
||||
typedef void (*kmscon_input_cb) (struct kmscon_input *input,
|
||||
struct kmscon_input_event *ev, void *data);
|
||||
|
||||
int kmscon_input_new(struct kmscon_input **out);
|
||||
void kmscon_input_ref(struct kmscon_input *input);
|
||||
void kmscon_input_unref(struct kmscon_input *input);
|
||||
|
||||
int kmscon_input_connect_eloop(struct kmscon_input *input,
|
||||
struct ev_eloop *eloop);
|
||||
void kmscon_input_disconnect_eloop(struct kmscon_input *input);
|
||||
int kmscon_input_register_cb(struct kmscon_input *input, kmscon_input_cb cb,
|
||||
void *data);
|
||||
void kmscon_input_unregister_cb(struct kmscon_input *input, kmscon_input_cb cb,
|
||||
void *data);
|
||||
|
||||
void kmscon_input_sleep(struct kmscon_input *input);
|
||||
void kmscon_input_wake_up(struct kmscon_input *input);
|
||||
bool kmscon_input_is_asleep(struct kmscon_input *input);
|
||||
|
||||
/* Querying the results of evdev ioctl's. Also used by kbd backends. */
|
||||
static inline bool kmscon_evdev_bit_is_set(const unsigned long *array, int bit)
|
||||
{
|
||||
return !!(array[bit / LONG_BIT] & (1LL << (bit % LONG_BIT)));
|
||||
}
|
||||
|
||||
#endif /* KMSCON_INPUT_H */
|
88
src/kbd.h
88
src/kbd.h
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* kmscon - translating key presses to input events
|
||||
*
|
||||
* Copyright (c) 2012 Ran Benita <ran234@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This defines the API the keyboard backends need to implement. The main
|
||||
* function of a keyboard backend is to translate a kernel input event into a
|
||||
* kmscon_input_event (see kmscon_kbd_process_key function).
|
||||
*
|
||||
* The two exported object are a "keyboard" object and a "keyboard
|
||||
* description" object. The keyboard object holds all the device specific
|
||||
* private state (e.g. active groups, modifiers). The description object
|
||||
* holds all the global information (e.g. layouts, mapping tables).
|
||||
*/
|
||||
|
||||
#ifndef KMSCON_KBD_H
|
||||
#define KMSCON_KBD_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "input.h"
|
||||
|
||||
struct kmscon_kbd_desc;
|
||||
struct kmscon_kbd;
|
||||
|
||||
/*
|
||||
* These are the values sent by the kernel in the /value/ field of the
|
||||
* /input_event/ struct.
|
||||
* See Documentation/input/event-codes.txt in the kernel tree.
|
||||
*/
|
||||
enum kmscon_key_state {
|
||||
KMSCON_KEY_RELEASED = 0,
|
||||
KMSCON_KEY_PRESSED = 1,
|
||||
KMSCON_KEY_REPEATED = 2,
|
||||
};
|
||||
|
||||
int kmscon_kbd_desc_new(struct kmscon_kbd_desc **out, const char *layout,
|
||||
const char *variant, const char *options);
|
||||
void kmscon_kbd_desc_ref(struct kmscon_kbd_desc *desc);
|
||||
void kmscon_kbd_desc_unref(struct kmscon_kbd_desc *desc);
|
||||
|
||||
int kmscon_kbd_new(struct kmscon_kbd **out, struct kmscon_kbd_desc *desc);
|
||||
void kmscon_kbd_ref(struct kmscon_kbd *state);
|
||||
void kmscon_kbd_unref(struct kmscon_kbd *state);
|
||||
|
||||
/*
|
||||
* This resets the keyboard state in case it got out of sync. It's mainly used
|
||||
* to sync our notion of the keyboard state with what the keyboard LEDs show.
|
||||
*/
|
||||
void kmscon_kbd_reset(struct kmscon_kbd *kbd, const unsigned long *ledbits);
|
||||
|
||||
/*
|
||||
* This is the entry point to the keyboard processing.
|
||||
* We get an evdev scancode and the keyboard state, and should put out a
|
||||
* proper input event.
|
||||
* Some evdev input events shouldn't result in us sending an input event
|
||||
* (e.g. a key release):
|
||||
* - If the event was filled out, 0 is returned.
|
||||
* - Otherwise, if there was no error, -ENOKEY is returned.
|
||||
*/
|
||||
int kmscon_kbd_process_key(struct kmscon_kbd *kbd,
|
||||
enum kmscon_key_state key_state,
|
||||
uint16_t code,
|
||||
struct kmscon_input_event *out);
|
||||
|
||||
void kmscon_kbd_keysym_to_string(uint32_t keysym, char *str, size_t size);
|
||||
|
||||
#endif /* KMSCON_KBD_H */
|
453
src/kbd_dumb.c
453
src/kbd_dumb.c
@ -1,453 +0,0 @@
|
||||
/*
|
||||
* kmscon - translating key presses to input events using keycodes
|
||||
*
|
||||
* Copyright (c) 2012 Ran Benita <ran234@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <linux/input.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "kbd.h"
|
||||
#include "log.h"
|
||||
#include "imKStoUCS.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "kbd_dumb"
|
||||
|
||||
/*
|
||||
* This is a very "dumb" and simple fallback backend for keycodes
|
||||
* interpretation. It uses direct mapping from kernel keycodes to X keysyms
|
||||
* according to a basic US PC keyboard. It is not configurable and does not
|
||||
* support unicode or other languages.
|
||||
*
|
||||
* The key interpretation is affected by the following modifiers: Numlock,
|
||||
* Shift, Capslock, and "Normal" (no mofifiers) in that order. If a keycode is
|
||||
* not affected by one of these depressed modifiers, the next matching one is
|
||||
* attempted.
|
||||
*/
|
||||
|
||||
struct kmscon_kbd_desc {
|
||||
unsigned long ref;
|
||||
|
||||
/*
|
||||
* There is no need for this structure here currently. It can contain
|
||||
* pointers to alternative keytabs and modmaps, if we ever want this
|
||||
* backend to support different languages, etc.
|
||||
*/
|
||||
};
|
||||
|
||||
struct kmscon_kbd {
|
||||
unsigned long ref;
|
||||
struct kmscon_kbd_desc *desc;
|
||||
|
||||
unsigned int mods;
|
||||
};
|
||||
|
||||
/*
|
||||
* These tables do not contain all possible keys from linux/input.h.
|
||||
* If a keycode does not appear, it is mapped to keysym 0 and regarded as not
|
||||
* found.
|
||||
*/
|
||||
|
||||
static const uint32_t keytab_normal[] = {
|
||||
[KEY_ESC] = XK_Escape,
|
||||
[KEY_1] = XK_1,
|
||||
[KEY_2] = XK_2,
|
||||
[KEY_3] = XK_3,
|
||||
[KEY_4] = XK_4,
|
||||
[KEY_5] = XK_5,
|
||||
[KEY_6] = XK_6,
|
||||
[KEY_7] = XK_7,
|
||||
[KEY_8] = XK_8,
|
||||
[KEY_9] = XK_9,
|
||||
[KEY_0] = XK_0,
|
||||
[KEY_MINUS] = XK_minus,
|
||||
[KEY_EQUAL] = XK_equal,
|
||||
[KEY_BACKSPACE] = XK_BackSpace,
|
||||
[KEY_TAB] = XK_Tab,
|
||||
[KEY_Q] = XK_q,
|
||||
[KEY_W] = XK_w,
|
||||
[KEY_E] = XK_e,
|
||||
[KEY_R] = XK_r,
|
||||
[KEY_T] = XK_t,
|
||||
[KEY_Y] = XK_y,
|
||||
[KEY_U] = XK_u,
|
||||
[KEY_I] = XK_i,
|
||||
[KEY_O] = XK_o,
|
||||
[KEY_P] = XK_p,
|
||||
[KEY_LEFTBRACE] = XK_bracketleft,
|
||||
[KEY_RIGHTBRACE] = XK_bracketright,
|
||||
[KEY_ENTER] = XK_Return,
|
||||
[KEY_LEFTCTRL] = XK_Control_L,
|
||||
[KEY_A] = XK_a,
|
||||
[KEY_S] = XK_s,
|
||||
[KEY_D] = XK_d,
|
||||
[KEY_F] = XK_f,
|
||||
[KEY_G] = XK_g,
|
||||
[KEY_H] = XK_h,
|
||||
[KEY_J] = XK_j,
|
||||
[KEY_K] = XK_k,
|
||||
[KEY_L] = XK_l,
|
||||
[KEY_SEMICOLON] = XK_semicolon,
|
||||
[KEY_APOSTROPHE] = XK_apostrophe,
|
||||
[KEY_GRAVE] = XK_grave,
|
||||
[KEY_LEFTSHIFT] = XK_Shift_L,
|
||||
[KEY_BACKSLASH] = XK_backslash,
|
||||
[KEY_Z] = XK_z,
|
||||
[KEY_X] = XK_x,
|
||||
[KEY_C] = XK_c,
|
||||
[KEY_V] = XK_v,
|
||||
[KEY_B] = XK_b,
|
||||
[KEY_N] = XK_n,
|
||||
[KEY_M] = XK_m,
|
||||
[KEY_COMMA] = XK_comma,
|
||||
[KEY_DOT] = XK_period,
|
||||
[KEY_SLASH] = XK_slash,
|
||||
[KEY_RIGHTSHIFT] = XK_Shift_R,
|
||||
[KEY_KPASTERISK] = XK_KP_Multiply,
|
||||
[KEY_LEFTALT] = XK_Alt_L,
|
||||
[KEY_SPACE] = XK_space,
|
||||
[KEY_CAPSLOCK] = XK_Caps_Lock,
|
||||
[KEY_F1] = XK_F1,
|
||||
[KEY_F2] = XK_F2,
|
||||
[KEY_F3] = XK_F3,
|
||||
[KEY_F4] = XK_F4,
|
||||
[KEY_F5] = XK_F5,
|
||||
[KEY_F6] = XK_F6,
|
||||
[KEY_F7] = XK_F7,
|
||||
[KEY_F8] = XK_F8,
|
||||
[KEY_F9] = XK_F9,
|
||||
[KEY_F10] = XK_F10,
|
||||
[KEY_NUMLOCK] = XK_Num_Lock,
|
||||
[KEY_SCROLLLOCK] = XK_Scroll_Lock,
|
||||
[KEY_KP7] = XK_KP_Home,
|
||||
[KEY_KP8] = XK_KP_Up,
|
||||
[KEY_KP9] = XK_KP_Page_Up,
|
||||
[KEY_KPMINUS] = XK_KP_Subtract,
|
||||
[KEY_KP4] = XK_KP_Left,
|
||||
[KEY_KP5] = XK_KP_Begin,
|
||||
[KEY_KP6] = XK_KP_Right,
|
||||
[KEY_KPPLUS] = XK_KP_Add,
|
||||
[KEY_KP1] = XK_KP_End,
|
||||
[KEY_KP2] = XK_KP_Down,
|
||||
[KEY_KP3] = XK_KP_Page_Down,
|
||||
[KEY_KP0] = XK_KP_Insert,
|
||||
[KEY_KPDOT] = XK_KP_Delete,
|
||||
[KEY_F11] = XK_F11,
|
||||
[KEY_F12] = XK_F12,
|
||||
[KEY_KPENTER] = XK_KP_Enter,
|
||||
[KEY_RIGHTCTRL] = XK_Control_R,
|
||||
[KEY_KPSLASH] = XK_KP_Divide,
|
||||
[KEY_RIGHTALT] = XK_Alt_R,
|
||||
[KEY_LINEFEED] = XK_Linefeed,
|
||||
[KEY_HOME] = XK_Home,
|
||||
[KEY_UP] = XK_Up,
|
||||
[KEY_PAGEUP] = XK_Page_Up,
|
||||
[KEY_LEFT] = XK_Left,
|
||||
[KEY_RIGHT] = XK_Right,
|
||||
[KEY_END] = XK_End,
|
||||
[KEY_DOWN] = XK_Down,
|
||||
[KEY_PAGEDOWN] = XK_Page_Down,
|
||||
[KEY_INSERT] = XK_Insert,
|
||||
[KEY_DELETE] = XK_Delete,
|
||||
[KEY_KPEQUAL] = XK_KP_Equal,
|
||||
[KEY_LEFTMETA] = XK_Meta_L,
|
||||
[KEY_RIGHTMETA] = XK_Meta_R,
|
||||
};
|
||||
#define KEYTAB_SIZE (KEY_RIGHTMETA + 1)
|
||||
_Static_assert(
|
||||
(KEYTAB_SIZE == sizeof(keytab_normal) / sizeof(*keytab_normal)),
|
||||
"The KEYTAB_SIZE #define is incorrect!"
|
||||
);
|
||||
|
||||
static const uint32_t keytab_numlock[KEYTAB_SIZE] = {
|
||||
[KEY_KP7] = XK_KP_7,
|
||||
[KEY_KP8] = XK_KP_8,
|
||||
[KEY_KP9] = XK_KP_9,
|
||||
[KEY_KP4] = XK_KP_4,
|
||||
[KEY_KP5] = XK_KP_5,
|
||||
[KEY_KP6] = XK_KP_6,
|
||||
[KEY_KP1] = XK_KP_1,
|
||||
[KEY_KP2] = XK_KP_2,
|
||||
[KEY_KP3] = XK_KP_3,
|
||||
[KEY_KP0] = XK_KP_0,
|
||||
};
|
||||
|
||||
static const uint32_t keytab_shift[KEYTAB_SIZE] = {
|
||||
[KEY_1] = XK_exclam,
|
||||
[KEY_2] = XK_at,
|
||||
[KEY_3] = XK_numbersign,
|
||||
[KEY_4] = XK_dollar,
|
||||
[KEY_5] = XK_percent,
|
||||
[KEY_6] = XK_asciicircum,
|
||||
[KEY_7] = XK_ampersand,
|
||||
[KEY_8] = XK_asterisk,
|
||||
[KEY_9] = XK_parenleft,
|
||||
[KEY_0] = XK_parenright,
|
||||
[KEY_MINUS] = XK_underscore,
|
||||
[KEY_EQUAL] = XK_plus,
|
||||
[KEY_Q] = XK_Q,
|
||||
[KEY_W] = XK_W,
|
||||
[KEY_E] = XK_E,
|
||||
[KEY_R] = XK_R,
|
||||
[KEY_T] = XK_T,
|
||||
[KEY_Y] = XK_Y,
|
||||
[KEY_U] = XK_U,
|
||||
[KEY_I] = XK_I,
|
||||
[KEY_O] = XK_O,
|
||||
[KEY_P] = XK_P,
|
||||
[KEY_LEFTBRACE] = XK_braceleft,
|
||||
[KEY_RIGHTBRACE] = XK_braceright,
|
||||
[KEY_A] = XK_A,
|
||||
[KEY_S] = XK_S,
|
||||
[KEY_D] = XK_D,
|
||||
[KEY_F] = XK_F,
|
||||
[KEY_G] = XK_G,
|
||||
[KEY_H] = XK_H,
|
||||
[KEY_J] = XK_J,
|
||||
[KEY_K] = XK_K,
|
||||
[KEY_L] = XK_L,
|
||||
[KEY_SEMICOLON] = XK_colon,
|
||||
[KEY_APOSTROPHE] = XK_quotedbl,
|
||||
[KEY_GRAVE] = XK_asciitilde,
|
||||
[KEY_BACKSLASH] = XK_bar,
|
||||
[KEY_Z] = XK_Z,
|
||||
[KEY_X] = XK_X,
|
||||
[KEY_C] = XK_C,
|
||||
[KEY_V] = XK_V,
|
||||
[KEY_B] = XK_B,
|
||||
[KEY_N] = XK_N,
|
||||
[KEY_M] = XK_M,
|
||||
[KEY_COMMA] = XK_less,
|
||||
[KEY_DOT] = XK_greater,
|
||||
[KEY_SLASH] = XK_question,
|
||||
};
|
||||
|
||||
static const uint32_t keytab_capslock[KEYTAB_SIZE] = {
|
||||
[KEY_Q] = XK_Q,
|
||||
[KEY_W] = XK_W,
|
||||
[KEY_E] = XK_E,
|
||||
[KEY_R] = XK_R,
|
||||
[KEY_T] = XK_T,
|
||||
[KEY_Y] = XK_Y,
|
||||
[KEY_U] = XK_U,
|
||||
[KEY_I] = XK_I,
|
||||
[KEY_O] = XK_O,
|
||||
[KEY_P] = XK_P,
|
||||
[KEY_A] = XK_A,
|
||||
[KEY_S] = XK_S,
|
||||
[KEY_D] = XK_D,
|
||||
[KEY_F] = XK_F,
|
||||
[KEY_G] = XK_G,
|
||||
[KEY_H] = XK_H,
|
||||
[KEY_J] = XK_J,
|
||||
[KEY_K] = XK_K,
|
||||
[KEY_L] = XK_L,
|
||||
[KEY_Z] = XK_Z,
|
||||
[KEY_X] = XK_X,
|
||||
[KEY_C] = XK_C,
|
||||
[KEY_V] = XK_V,
|
||||
[KEY_B] = XK_B,
|
||||
[KEY_N] = XK_N,
|
||||
[KEY_M] = XK_M,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
enum kmscon_modifier mod;
|
||||
enum {
|
||||
MOD_NORMAL = 1,
|
||||
MOD_LOCK,
|
||||
} type;
|
||||
} modmap[KEYTAB_SIZE] = {
|
||||
[KEY_LEFTCTRL] = { KMSCON_CONTROL_MASK, MOD_NORMAL },
|
||||
[KEY_LEFTSHIFT] = { KMSCON_SHIFT_MASK, MOD_NORMAL },
|
||||
[KEY_RIGHTSHIFT] = { KMSCON_SHIFT_MASK, MOD_NORMAL },
|
||||
[KEY_LEFTALT] = { KMSCON_MOD1_MASK, MOD_NORMAL },
|
||||
[KEY_CAPSLOCK] = { KMSCON_LOCK_MASK, MOD_LOCK },
|
||||
[KEY_NUMLOCK] = { KMSCON_MOD2_MASK, MOD_LOCK },
|
||||
[KEY_RIGHTCTRL] = { KMSCON_CONTROL_MASK, MOD_NORMAL },
|
||||
[KEY_RIGHTALT] = { KMSCON_MOD1_MASK, MOD_NORMAL },
|
||||
[KEY_LEFTMETA] = { KMSCON_MOD4_MASK, MOD_NORMAL },
|
||||
[KEY_RIGHTMETA] = { KMSCON_MOD4_MASK, MOD_NORMAL },
|
||||
};
|
||||
|
||||
int kmscon_kbd_new(struct kmscon_kbd **out, struct kmscon_kbd_desc *desc)
|
||||
{
|
||||
struct kmscon_kbd *kbd;
|
||||
|
||||
kbd = malloc(sizeof(*kbd));
|
||||
if (!kbd)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(kbd, 0, sizeof(*kbd));
|
||||
kbd->ref = 1;
|
||||
|
||||
kbd->desc = desc;
|
||||
kmscon_kbd_desc_ref(desc);
|
||||
|
||||
*out = kbd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kmscon_kbd_ref(struct kmscon_kbd *kbd)
|
||||
{
|
||||
if (!kbd)
|
||||
return;
|
||||
|
||||
++kbd->ref;
|
||||
}
|
||||
|
||||
void kmscon_kbd_unref(struct kmscon_kbd *kbd)
|
||||
{
|
||||
if (!kbd || !kbd->ref)
|
||||
return;
|
||||
|
||||
if (--kbd->ref)
|
||||
return;
|
||||
|
||||
kmscon_kbd_desc_unref(kbd->desc);
|
||||
free(kbd);
|
||||
}
|
||||
|
||||
void kmscon_kbd_reset(struct kmscon_kbd *kbd, const unsigned long *ledbits)
|
||||
{
|
||||
if (!kbd)
|
||||
return;
|
||||
|
||||
kbd->mods = 0;
|
||||
|
||||
if (kmscon_evdev_bit_is_set(ledbits, LED_NUML))
|
||||
kbd->mods |= KMSCON_MOD2_MASK;
|
||||
if (kmscon_evdev_bit_is_set(ledbits, LED_CAPSL))
|
||||
kbd->mods |= KMSCON_LOCK_MASK;
|
||||
}
|
||||
|
||||
int kmscon_kbd_process_key(struct kmscon_kbd *kbd,
|
||||
enum kmscon_key_state key_state,
|
||||
uint16_t code,
|
||||
struct kmscon_input_event *out)
|
||||
{
|
||||
uint32_t keysym;
|
||||
enum kmscon_modifier mod;
|
||||
int mod_type;
|
||||
|
||||
/* Ignore unknown keycodes. */
|
||||
if (code >= KEYTAB_SIZE)
|
||||
return -ENOKEY;
|
||||
|
||||
if (modmap[code].mod) {
|
||||
mod = modmap[code].mod;
|
||||
mod_type = modmap[code].type;
|
||||
|
||||
/*
|
||||
* We release locked modifiers on key press, like the kernel,
|
||||
* but unlike XKB.
|
||||
*/
|
||||
if (key_state == KMSCON_KEY_PRESSED) {
|
||||
if (mod_type == MOD_NORMAL)
|
||||
kbd->mods |= mod;
|
||||
else if (mod_type == MOD_LOCK)
|
||||
kbd->mods ^= mod;
|
||||
} else if (key_state == KMSCON_KEY_RELEASED) {
|
||||
if (mod_type == MOD_NORMAL)
|
||||
kbd->mods &= ~mod;
|
||||
}
|
||||
|
||||
/* Don't deliver events purely for modifiers. */
|
||||
return -ENOKEY;
|
||||
}
|
||||
|
||||
if (key_state == KMSCON_KEY_RELEASED)
|
||||
return -ENOKEY;
|
||||
|
||||
keysym = 0;
|
||||
|
||||
if (!keysym && kbd->mods & KMSCON_MOD2_MASK)
|
||||
keysym = keytab_numlock[code];
|
||||
if (!keysym && kbd->mods & KMSCON_SHIFT_MASK)
|
||||
keysym = keytab_shift[code];
|
||||
if (!keysym && kbd->mods & KMSCON_LOCK_MASK)
|
||||
keysym = keytab_capslock[code];
|
||||
if (!keysym)
|
||||
keysym = keytab_normal[code];
|
||||
|
||||
if (!keysym)
|
||||
return -ENOKEY;
|
||||
|
||||
out->keycode = code;
|
||||
out->keysym = keysym;
|
||||
out->unicode = KeysymToUcs4(keysym) ?: KMSCON_INPUT_INVALID;
|
||||
out->mods = kbd->mods;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kmscon_kbd_desc_new(struct kmscon_kbd_desc **out, const char *layout,
|
||||
const char *variant, const char *options)
|
||||
{
|
||||
struct kmscon_kbd_desc *desc;
|
||||
|
||||
if (!out)
|
||||
return -EINVAL;
|
||||
|
||||
desc = malloc(sizeof(*desc));
|
||||
if (!desc)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
desc->ref = 1;
|
||||
|
||||
log_debug("new keyboard description (%s, %s, %s)",
|
||||
layout, variant, options);
|
||||
*out = desc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kmscon_kbd_desc_ref(struct kmscon_kbd_desc *desc)
|
||||
{
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
++desc->ref;
|
||||
}
|
||||
|
||||
void kmscon_kbd_desc_unref(struct kmscon_kbd_desc *desc)
|
||||
{
|
||||
if (!desc || !desc->ref)
|
||||
return;
|
||||
|
||||
if (--desc->ref)
|
||||
return;
|
||||
|
||||
log_debug("destroying keyboard description");
|
||||
|
||||
free(desc);
|
||||
}
|
||||
|
||||
void kmscon_kbd_keysym_to_string(uint32_t keysym, char *str, size_t size)
|
||||
{
|
||||
snprintf(str, size, "%#x", keysym);
|
||||
}
|
1012
src/kbd_xkb.c
1012
src/kbd_xkb.c
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,6 @@
|
||||
#include <sys/signalfd.h>
|
||||
#include "conf.h"
|
||||
#include "eloop.h"
|
||||
#include "input.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
#include "ui.h"
|
||||
|
Loading…
x
Reference in New Issue
Block a user