summaryrefslogtreecommitdiff
path: root/xutil.h
diff options
context:
space:
mode:
Diffstat (limited to 'xutil.h')
-rw-r--r--xutil.h95
1 files changed, 95 insertions, 0 deletions
diff --git a/xutil.h b/xutil.h
new file mode 100644
index 0000000..609d20c
--- /dev/null
+++ b/xutil.h
@@ -0,0 +1,95 @@
+#pragma once
+
+#include <functional>
+#include <optional>
+#include <X11/Xlib.h>
+
+
+namespace x {
+
+ // Typed wrapper for an X keycode
+ class Keycode {
+ public:
+ Keycode() = default;
+ inline Keycode(unsigned int code) : code{code} {};
+ inline explicit operator unsigned int() const { return code; };
+ inline bool operator==(Keycode other) const { return code == other.code; }
+ private:
+ unsigned int code = 0;
+ };
+
+ // Typed wrapper for an X keysym
+ class Keysym {
+ public:
+ Keysym() = default;
+ inline Keysym(unsigned int sym) : sym{sym} {};
+ inline explicit operator unsigned int() const { return sym; }
+ Keycode toCode(Display *dpy) const;
+ inline bool operator==(Keysym other) const { return sym == other.sym; }
+ private:
+ unsigned int sym = 0;
+ };
+
+ // Play the system bell
+ void bel(Display *dpy);
+
+ // Run a handler on scope exit
+ template <typename Cleanup>
+ class UponExit {
+ public:
+ UponExit(Cleanup cleanup) : cleanup{cleanup} {}
+ ~UponExit() {
+ if (cleanup) (*cleanup)();
+ }
+ UponExit(const UponExit&) = delete;
+ UponExit(UponExit &&other) : cleanup{move(other.cleanup)} {
+ other.cleanup.reset();
+ }
+ UponExit& operator=(const UponExit&) = delete;
+ UponExit& operator=(UponExit &&other) {
+ cleanup = move(other.cleanup);
+ other.cleanup.reset();
+ }
+
+ private:
+ std::optional<Cleanup> cleanup;
+ };
+
+ // Grab a single key (code + modifier) on the X server in the given window.
+ // Drop the UponExit to ungrab. For a global grab, use
+ // DefaultRootWindow(dpy) as the window.
+ UponExit<std::function<void()>> XGrabKeyRAII(Display *dpy, Keycode code, int modifier, Window win);
+
+ // Grab a the whole keyboard on the X server in the given window. Drop the
+ // UponExit to ungrab. For a global grab, use DefaultRootWindow(dpy) as the
+ // window.
+ UponExit<std::function<void()>> XGrabKeyboardRAII(Display *dpy, Window win);
+
+ // Open the specified display (pass nullptr to use $DISPLAY). Drop the UponExit to close.
+ std::pair<Display*, UponExit<std::function<void()>>> XOpenDisplayRAII(const char *name);
+
+ // Grab the specified key globally for any modifier combination, and run
+ // the callback on every hit of that key. Ungrabs and returns when the
+ // callback returns true.
+ void globalKeyWatch(Display *dpy, Keysym keysym, std::function<bool(const XKeyEvent&)> callback);
+
+ // Grab the whole keyboard globally, and run the callback on every keyboard
+ // key event. Ungrabs and returns when the callback returns true.
+ void globalKeyboardGrab(Display *dpy, std::function<bool(const XKeyEvent&)> callback);
+
+}
+
+template <>
+struct std::hash<x::Keycode> {
+ size_t operator()(x::Keycode code) const {
+ return std::hash<unsigned int>{}((unsigned int)code);
+ }
+};
+
+template <>
+struct std::hash<x::Keysym> {
+ size_t operator()(x::Keysym sym) const {
+ return std::hash<unsigned int>{}((unsigned int)sym);
+ }
+};
+