ric*_*mer 5 keyboard-shortcuts wayland
这里有很多问题询问如何在 Wayland 环境中创建全局键盘绑定。一般来说,答案是“使用你的桌面环境”——这个答案对于大多数提出问题的人来说几乎毫无用处。
那么,为了得出一个更有用的答案,我想问一下如何创建一个最小的可以绑定快捷键的Wayland桌面环境?
我已经让 Mutter 作为我的 WM 运行,并使用 GNOME Do 作为启动器。这几乎正是我想要的桌面环境,只是我无法绑定热键。
我不在乎是否必须编写一个 10k 行的 C 应用程序才能完成这项工作。我只是想知道如何继续。GNOME 如何在 Wayland 中绑定键盘快捷键?代码在哪里?Wayland/Mutter 的适当文档在哪里?
经过大量研究和实验,它看起来libevdev可能是正确的工具。Alt+X我开发了下面的程序作为绑定到 launch 的概念验证xterm。
不幸的是,它必须以 root 身份运行,所以我想我需要以某种方式将其绑定到本地桌面会话中。setuid就我的目的而言,仅使用root用户并结束可能就足够了。
我也不相信我的键盘检测启发式非常好。我本质上是在寻找任何具有按键和重复率的设备,在我的系统上仅与我的键盘匹配。
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <libevdev/libevdev.h>
#define DEVROOT "/dev/input/"
#define DEVROOT_LEN 12
#define PATH_LEN (DEVROOT_LEN + NAME_MAX)
int outerr(int, const char*);
struct libevdev* open_device(int);
bool kblike(struct libevdev*);
int main(int argc, char* argv[]) {
DIR* dir;
struct dirent* entry;
char path[PATH_LEN];
int fd, err;
struct libevdev* dev = NULL;
struct input_event ev;
bool key, rep, alt;
if (!(dir = opendir("/dev/input"))) {
return outerr(errno, "cannot enumerate devices");
}
// look for keyboard device
while (entry = readdir(dir)) {
if (DT_CHR == entry->d_type) {
sprintf(path, "/dev/input/%s", entry->d_name);
if (-1 == (fd = open(path, O_RDONLY|O_NONBLOCK))) {
return outerr(errno, "cannot read device");
}
if (dev = open_device(fd)) {
if (kblike(dev)) break;
libevdev_free(dev);
dev = NULL;
}
}
}
closedir(dir);
// check if keyboard was found
if (dev == NULL) {
return outerr(ENODEV, "could not detect keyboard");
} else do {
err = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
if (err == 0 && ev.type == EV_KEY) switch (ev.code) {
case KEY_LEFTALT:
alt = ev.value == 1;
break;
case KEY_X:
if (ev.value == 1 && alt) system("xterm");
break;
}
} while (err == 1 || err == 0 || err == -EAGAIN);
return 0;
}
int outerr(int errnum, const char* msg) {
fprintf(stderr, "%s (%s)\n", msg, strerror(errnum));
return errnum;
}
bool kblike(struct libevdev* dev) {
return libevdev_has_event_type(dev, EV_KEY)
&& libevdev_has_event_type(dev, EV_REP);
}
struct libevdev* open_device(int fd) {
struct libevdev* dev = libevdev_new();
int err;
if (dev == NULL) {
errno = ENOMEM;
} else if (0 > (err = libevdev_set_fd(dev, fd))) {
libevdev_free(dev);
dev = NULL;
errno = -err;
}
return dev;
}
Run Code Online (Sandbox Code Playgroud)