summaryrefslogtreecommitdiff
path: root/xutil.cpp
diff options
context:
space:
mode:
authorTom Smeding <tom@tomsmeding.com>2024-01-31 15:42:17 +0100
committerTom Smeding <tom@tomsmeding.com>2024-01-31 15:42:17 +0100
commit6060db32b949d62757b668f972648465f1e302c7 (patch)
tree53fcc624d250a7d42d15cfcae4909ed6c21dd3be /xutil.cpp
Initial
Diffstat (limited to 'xutil.cpp')
-rw-r--r--xutil.cpp85
1 files changed, 85 insertions, 0 deletions
diff --git a/xutil.cpp b/xutil.cpp
new file mode 100644
index 0000000..7adceaa
--- /dev/null
+++ b/xutil.cpp
@@ -0,0 +1,85 @@
+#include <iostream>
+#include <functional>
+#include <X11/XKBlib.h>
+#include "xutil.h"
+
+
+namespace x {
+
+ Keycode Keysym::toCode(Display *dpy) const {
+ return XKeysymToKeycode(dpy, 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;
+ }
+ }
+
+}