1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#include <iostream>
#include <functional>
#include <X11/XKBlib.h>
#include "xutil.h"
namespace x {
Keycode::Keycode()
: code{0} {}
Keycode::Keycode(unsigned int code)
: code{code} {}
Keycode::operator unsigned int() const {
return code;
}
bool Keycode::operator==(Keycode other) const {
return code == other.code;
}
Keysym::Keysym()
: sym{0} {}
Keysym::Keysym(unsigned int sym)
: sym{sym} {}
Keysym::operator unsigned int() const {
return sym;
}
Keycode Keysym::toCode(Display *dpy) const {
return XKeysymToKeycode(dpy, sym);
}
bool Keysym::operator==(Keysym other) const {
return sym == other.sym;
}
void bel(Display *dpy) {
XkbBell(dpy, None, 100, None);
}
using UponExitF = UponExit<std::function<void()>>;
UponExitF XGrabKeyRAII(Display *dpy, Keycode code, int modifier, Window win) {
XGrabKey(dpy, (unsigned int)code, modifier, win, False, GrabModeAsync, GrabModeAsync);
return UponExitF{[dpy, code, modifier, win]() {
XUngrabKey(dpy, (unsigned int)code, modifier, win);
XSync(dpy, False);
}};
}
UponExitF XGrabKeyboardRAII(Display *dpy, Window win) {
int ret = XGrabKeyboard(dpy, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
if (ret == AlreadyGrabbed) {
XUngrabKeyboard(dpy, CurrentTime);
XSync(dpy, False);
throw std::runtime_error("Cannot grab keyboard: already grabbed");
}
return UponExitF{[dpy]() {
XUngrabKeyboard(dpy, CurrentTime);
XSync(dpy, False);
}};
}
std::pair<Display*, UponExitF> XOpenDisplayRAII(const char *name) {
Display *dpy = XOpenDisplay(name);
if (dpy == nullptr) {
std::cerr << "Cannot open X display" << std::endl;
exit(1);
}
return std::make_pair(dpy, UponExitF{[dpy]() {
XCloseDisplay(dpy);
}});
}
void globalKeyWatch(Display *dpy, Keysym keysym, std::function<bool(const XKeyEvent&)> callback) {
const Window root = DefaultRootWindow(dpy);
const Keycode keycode = keysym.toCode(dpy);
auto guard = XGrabKeyRAII(dpy, keycode, AnyModifier, root);
XSelectInput(dpy, root, KeyPressMask);
while (true) {
XEvent ev;
XNextEvent(dpy, &ev);
if (ev.type == KeyPress && ev.xkey.keycode == (unsigned int)keycode) {
if (callback(ev.xkey)) return;
}
}
}
void globalKeyboardGrab(Display *dpy, std::function<bool(const XKeyEvent&)> callback) {
const Window root = DefaultRootWindow(dpy);
try {
auto guard = XGrabKeyboardRAII(dpy, root);
while (true) {
XEvent ev;
XNextEvent(dpy, &ev);
if (ev.type == KeyPress) {
if (callback(ev.xkey)) return;
}
}
} catch (std::exception &e) {
std::cerr << e.what() << std::endl;
}
}
}
|