diff options
Diffstat (limited to 'xutil.cpp')
-rw-r--r-- | xutil.cpp | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/xutil.cpp b/xutil.cpp new file mode 100644 index 0000000..e5eb8c2 --- /dev/null +++ b/xutil.cpp @@ -0,0 +1,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; + } + } + +} |