diff options
author | Tom Smeding <tom@tomsmeding.com> | 2024-01-31 15:42:17 +0100 |
---|---|---|
committer | Tom Smeding <tom@tomsmeding.com> | 2024-01-31 15:42:17 +0100 |
commit | 6060db32b949d62757b668f972648465f1e302c7 (patch) | |
tree | 53fcc624d250a7d42d15cfcae4909ed6c21dd3be /xutil.cpp |
Initial
Diffstat (limited to 'xutil.cpp')
-rw-r--r-- | xutil.cpp | 85 |
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; + } + } + +} |