summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <t.j.smeding@uu.nl>2024-02-01 14:09:26 +0100
committerTom Smeding <t.j.smeding@uu.nl>2024-02-01 14:28:15 +0100
commit119b623640254f425a89a3f13ce5cbe633ead9c2 (patch)
tree348f17181e5afb6bebc8a68db34de9d214ffd431
parenta4f291dcfdbbb17f59679fbe0f010062a4cd49e5 (diff)
Support for keycode inputHEADmaster
-rw-r--r--main.cpp84
-rw-r--r--xutil.cpp5
-rw-r--r--xutil.h1
3 files changed, 58 insertions, 32 deletions
diff --git a/main.cpp b/main.cpp
index d597629..a3679ab 100644
--- a/main.cpp
+++ b/main.cpp
@@ -12,24 +12,31 @@ namespace {
void usage(const char *argv0) {
std::cerr
<< "Usage:\n"
+ << " " << argv0 << " --which\n"
<< " " << argv0 << " <key>\n"
- << " " << argv0 << " [<key> <output>]*\n"
+ << " " << argv0 << " [<key> <output> | s:<keysym> <output> | c:<keycode> <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"
+ << "Keys are specified with the X11 keysym name, its keysym ID (prefixed with 's:'),\n"
+ << "or its keycode (prefixed with 'c:'). The keycode is typically non-portable\n"
+ << "because it depends on the particular keyboard hardware.\n"
+ << "xev(1) prints the keysym name and the keysym ID (in hexadecimal).\n"
+ << "Keysym IDs and keycodes can be given in decimal and in hexadecimal (with 0x).\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"
+ << "- KP_1 and s:0xffb1 are valid key values for the '1' key on the numpad.\n"
+ << "- XF86Launch7 and s: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"
+ << "\n"
+ << "In --which mode, the program will grab the entire keyboard, wait until the first\n"
+ << "pressed key, and print its keycode for use with 'c:'.\n"
;
}
- std::vector<std::pair<x::Keysym, std::string>> parse_watchlist(int argc, char **argv) {
- std::vector<std::pair<x::Keysym, std::string>> watchlist;
+ std::vector<std::pair<x::Keycode, std::string>> parse_watchlist(Display *dpy, int argc, char **argv) {
+ std::vector<std::pair<x::Keycode, std::string>> watchlist;
if (argc <= 1) {
usage(argv[0]);
@@ -42,29 +49,40 @@ namespace {
exit(0);
}
- std::optional<x::Keysym> msym;
+ std::optional<x::Keycode> mcode;
- 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);
+ if ((argv[i][0] == 's' || argv[i][0] == 'c') && argv[i][1] == ':') {
+ unsigned number;
+ if (argv[i][2] == '0' && argv[i][3] == 'x') {
+ char *endp;
+ number = strtol(argv[i] + 2, &endp, 16);
+ if (argv[i][2] == '\0' || *endp != '\0') {
+ std::cerr << "Invalid hexadecimal number in '" << argv[i] << "'\n";
+ exit(1);
+ }
+ } else {
+ char *endp;
+ number = strtol(argv[i] + 2, &endp, 10);
+ if (argv[i][2] == '\0' || *endp != '\0') {
+ std::cerr << "Invalid decimal number in '" << argv[i] << "'\n";
+ exit(1);
+ }
}
- msym = x::Keysym{code};
+ if (argv[i][0] == 's') mcode = x::Keysym{number}.toCode(dpy);
+ else mcode = x::Keycode{number};
}
- if (!msym) {
+ if (!mcode) {
for (size_t j = 0; j < keysym_table.size(); j++) {
if (strcmp(argv[i], keysym_table[j].first) == 0) {
- msym = keysym_table[j].second;
+ mcode = keysym_table[j].second.toCode(dpy);
break;
}
}
}
- if (!msym) {
- std::cerr << "Unknown keysym '" << argv[i] << "'\n";
+ if (!mcode) {
+ std::cerr << "Unknown key name '" << argv[i] << "'\n";
exit(1);
}
@@ -72,14 +90,14 @@ namespace {
if (i == 1 && argc == 2) {
// empty output
} else if (i >= argc - 1) {
- std::cerr << "Missing output for keysym '" << argv[i] << "'\n";
+ std::cerr << "Missing output for key '" << argv[i] << "'\n";
exit(1);
} else {
output = argv[i+1];
i++; // skip output
}
- watchlist.emplace_back(*msym, std::move(output));
+ watchlist.emplace_back(*mcode, std::move(output));
}
return watchlist;
@@ -87,22 +105,26 @@ namespace {
}
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;
+ if (argc >= 2 && strcmp(argv[1], "--which") == 0) {
+ x::globalKeyboardGrab(dpy, [](const XKeyEvent &ev) -> bool {
+ std::cout << "c:" << ev.keycode << std::endl;
+ return true;
+ });
+ return 0;
+ }
+
+ std::vector<std::pair<x::Keycode, std::string>> watchlist = parse_watchlist(dpy, argc, argv);
+
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));
+ cleaners.push_back(x::XGrabKeyRAII(dpy, p.first, AnyModifier, root));
}
XSelectInput(dpy, root, KeyPressMask);
@@ -110,9 +132,9 @@ int main(int argc, char **argv) {
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;
+ for (const auto &p : watchlist) {
+ if (ev.xkey.keycode == (unsigned int)p.first) {
+ if (p.second.size() > 0) std::cout << p.second << std::endl;
return 0;
}
}
diff --git a/xutil.cpp b/xutil.cpp
index 7adceaa..2651dba 100644
--- a/xutil.cpp
+++ b/xutil.cpp
@@ -49,8 +49,11 @@ namespace x {
}
void globalKeyWatch(Display *dpy, Keysym keysym, std::function<bool(const XKeyEvent&)> callback) {
+ globalKeyWatch(dpy, keysym.toCode(dpy), callback);
+ }
+
+ void globalKeyWatch(Display *dpy, Keycode keycode, std::function<bool(const XKeyEvent&)> callback) {
const Window root = DefaultRootWindow(dpy);
- const Keycode keycode = keysym.toCode(dpy);
auto guard = XGrabKeyRAII(dpy, keycode, AnyModifier, root);
diff --git a/xutil.h b/xutil.h
index 609d20c..e067edd 100644
--- a/xutil.h
+++ b/xutil.h
@@ -72,6 +72,7 @@ namespace x {
// 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);
+ void globalKeyWatch(Display *dpy, Keycode keycode, 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.