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 /main.cpp |
Initial
Diffstat (limited to 'main.cpp')
-rw-r--r-- | main.cpp | 120 |
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; + } + } + } +} |