summaryrefslogtreecommitdiff
path: root/main.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 /main.cpp
Initial
Diffstat (limited to 'main.cpp')
-rw-r--r--main.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..d597629
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,120 @@
+#include <iostream>
+#include <vector>
+#include <string>
+#include <optional>
+#include <utility>
+#include <cstring>
+#include "xutil.h"
+#include "keysym_table.h"
+
+
+namespace {
+ void usage(const char *argv0) {
+ std::cerr
+ << "Usage:\n"
+ << " " << argv0 << " <key>\n"
+ << " " << argv0 << " [<key> <output>]*\n"
+ << "\n"
+ << "Keys are specified with the X11 keysym name or ID (in hexadecimal with \"0x\").\n"
+ << "Both are given by xev(1).\n"
+ << "Examples:\n"
+ << "- KP_1 and 0xffb1 are valid key values for the '1' key on the numpad.\n"
+ << "- XF86Launch7 and 0x1008ff47 are valid key values for F16 on an Apple keyboard.\n"
+ << "The values can also be found in /usr/include/xkbcommon/xkbcommon-keysyms.h .\n"
+ << "\n"
+ << "If a single key is given, the program grabs that key and exits when the key is\n"
+ << "pressed. If multiple keys are given, the output string corresponding to the\n"
+ << "pressed key will be printed before exiting.\n"
+ ;
+ }
+
+ std::vector<std::pair<x::Keysym, std::string>> parse_watchlist(int argc, char **argv) {
+ std::vector<std::pair<x::Keysym, std::string>> watchlist;
+
+ if (argc <= 1) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
+ usage(argv[0]);
+ exit(0);
+ }
+
+ std::optional<x::Keysym> msym;
+
+ if (argv[i][0] == '0' && argv[i][1] == 'x') {
+ char *endp;
+ unsigned code = strtol(argv[i] + 2, &endp, 16);
+ if (argv[i][2] == '\0' || *endp != '\0') {
+ std::cerr << "Invalid hexadecimal number in '" << argv[i] << "'\n";
+ exit(1);
+ }
+ msym = x::Keysym{code};
+ }
+
+ if (!msym) {
+ for (size_t j = 0; j < keysym_table.size(); j++) {
+ if (strcmp(argv[i], keysym_table[j].first) == 0) {
+ msym = keysym_table[j].second;
+ break;
+ }
+ }
+ }
+
+ if (!msym) {
+ std::cerr << "Unknown keysym '" << argv[i] << "'\n";
+ exit(1);
+ }
+
+ std::string output;
+ if (i == 1 && argc == 2) {
+ // empty output
+ } else if (i >= argc - 1) {
+ std::cerr << "Missing output for keysym '" << argv[i] << "'\n";
+ exit(1);
+ } else {
+ output = argv[i+1];
+ i++; // skip output
+ }
+
+ watchlist.emplace_back(*msym, std::move(output));
+ }
+
+ return watchlist;
+ }
+}
+
+int main(int argc, char **argv) {
+ std::vector<std::pair<x::Keysym, std::string>> watchlist = parse_watchlist(argc, argv);
+
+ auto dpypair = x::XOpenDisplayRAII(nullptr);
+ Display *dpy = dpypair.first;
+
+ Window root = DefaultRootWindow(dpy);
+
+ std::vector<x::UponExit<std::function<void()>>> cleaners;
+ cleaners.reserve(watchlist.size());
+ std::vector<x::Keycode> keycodes;
+ keycodes.reserve(watchlist.size());
+
+ for (const auto &p : watchlist) {
+ x::Keycode code = p.first.toCode(dpy);
+ keycodes.push_back(code);
+ cleaners.push_back(x::XGrabKeyRAII(dpy, code, AnyModifier, root));
+ }
+
+ XSelectInput(dpy, root, KeyPressMask);
+ while (true) {
+ XEvent ev;
+ XNextEvent(dpy, &ev);
+ if (ev.type != KeyPress) continue;
+ for (size_t i = 0; i < watchlist.size(); i++) {
+ if (ev.xkey.keycode == (unsigned int)keycodes[i]) {
+ if (watchlist[i].second.size() > 0) std::cout << watchlist[i].second << std::endl;
+ return 0;
+ }
+ }
+ }
+}