diff options
| -rw-r--r-- | main.cpp | 84 | ||||
| -rw-r--r-- | xutil.cpp | 5 | ||||
| -rw-r--r-- | xutil.h | 1 | 
3 files changed, 58 insertions, 32 deletions
@@ -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;  			}  		} @@ -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); @@ -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.  | 
