From bd0d20c622105c6797c0c7ac3631509c296194e5 Mon Sep 17 00:00:00 2001 From: houmain Date: Sun, 24 Jan 2021 10:26:37 +0100 Subject: [PATCH] Verbose output for linux/client --- CMakeLists.txt | 1 + README.md | 6 +-- src/linux/client/ConfigFile.cpp | 3 +- src/linux/client/Settings.cpp | 1 + src/linux/client/ipc.cpp | 8 +++- src/linux/client/main.cpp | 69 +++++++++++++++++++++++++++++---- src/linux/client/output.h | 4 ++ 7 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 src/linux/client/output.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 91bcf08e..7f7369c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ if(NOT WIN32) src/linux/client/Settings.h src/linux/client/ipc.cpp src/linux/client/ipc.h + src/linux/client/output.h src/linux/client/main.cpp ) diff --git a/README.md b/README.md index 32283f77..33c160cc 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ The command line argument ```-u``` causes the configuration to be automatically ### Key names -The keys are named after their scancodes and not affected by the present keyboard layout. -The names have been chosen to match on what the [web browsers](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code) have agreed upon, so this [handy website](http://keycode.info/) can be used to get a key's name. +The keys are named after their scancodes and are not affected by the present keyboard layout. +The names have been chosen to match on what the [web browsers](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values) have agreed upon, so this [handy website](http://keycode.info/) can be used to get a key's name. For convenience the letter and digits keys are also named ```A``` to ```Z``` and ```0``` to ```9```. The logical keys ```Shift```, ```Control``` and ```Meta``` are also defined (each matches the left and right modifier keys). There are also [virtual keys](#virtual-keys) for state switching and an [Any](#any-key) key. ### Input expressions @@ -159,7 +159,7 @@ systemctl enable keymapperd **Other Linux distributions:** -No packages are provided yet, please follow the instructions for [building manually](#Building). +No packages are provided yet, please follow the instructions for [building manually](#Building) or download a portable build from the [latest release](https://github.com/houmain/keymapper/releases/latest) page. To try it out, simply create a [configuration](#configuration) file and start it using: ``` diff --git a/src/linux/client/ConfigFile.cpp b/src/linux/client/ConfigFile.cpp index 716bcf0b..edbe36d6 100644 --- a/src/linux/client/ConfigFile.cpp +++ b/src/linux/client/ConfigFile.cpp @@ -1,6 +1,7 @@ #include "ConfigFile.h" #include "config/ParseConfig.h" +#include "output.h" #include #include #include @@ -38,7 +39,7 @@ bool ConfigFile::update() { m_config = parse(is); } catch (const std::exception& ex) { - std::fprintf(stderr, "%s\n", ex.what()); + error("%s", ex.what()); return false; } } diff --git a/src/linux/client/Settings.cpp b/src/linux/client/Settings.cpp index 4fa65c00..f4ca9acb 100644 --- a/src/linux/client/Settings.cpp +++ b/src/linux/client/Settings.cpp @@ -45,6 +45,7 @@ void print_help_message(const char* argv0) { " -c, --config configuration file.\n" " -u, --update reload configuration file when it changes.\n" " -v, --verbose enable verbose output.\n" + " -h, --help print this help.\n" "\n" "All Rights Reserved.\n" "This program comes with absolutely no warranty.\n" diff --git a/src/linux/client/ipc.cpp b/src/linux/client/ipc.cpp index a42452c9..0059fc33 100644 --- a/src/linux/client/ipc.cpp +++ b/src/linux/client/ipc.cpp @@ -42,7 +42,13 @@ int initialize_ipc(const char* fifo_filename) { ::signal(SIGPIPE, [](int) { g_pipe_broken = true; }); g_pipe_broken = false; - return ::open(fifo_filename, O_WRONLY); + for (;;) { + const auto fd = ::open(fifo_filename, O_WRONLY); + if (fd >= 0) + return fd; + + ::usleep(500 * 100); + } } void shutdown_ipc(int fd) { diff --git a/src/linux/client/main.cpp b/src/linux/client/main.cpp index fe7a5266..439ec51f 100644 --- a/src/linux/client/main.cpp +++ b/src/linux/client/main.cpp @@ -3,13 +3,36 @@ #include "FocusedWindow.h" #include "Settings.h" #include "ConfigFile.h" +#include "config/Config.h" +#include "output.h" #include +#include #include namespace { const auto ipc_fifo_filename = "/tmp/keymapper"; const auto config_filename = get_home_directory() + "/.config/keymapper.conf"; const auto update_interval_ms = 50; + bool g_verbose_output = false; +} + +void error(const char* format, ...) { + va_list args; + va_start(args, format); + std::vfprintf(stderr, format, args); + va_end(args); + std::fputc('\n', stderr); +} + +void verbose(const char* format, ...) { + if (g_verbose_output) { + va_list args; + va_start(args, format); + std::vfprintf(stdout, format, args); + va_end(args); + std::fputc('\n', stdout); + std::fflush(stdout); + } } int main(int argc, char* argv[]) { @@ -20,46 +43,78 @@ int main(int argc, char* argv[]) { print_help_message(argv[0]); return 1; } + g_verbose_output = settings.verbose; + // load initial configuration + verbose("loading configuration file '%s'", settings.config_file_path.c_str()); auto config_file = ConfigFile(settings.config_file_path); if (!config_file.update()) { - std::fprintf(stderr, "loading configuration failed\n"); + error("loading configuration failed"); return 1; } for (;;) { // initialize client/server IPC + verbose("connecting to keymapperd"); const auto ipc_fd = initialize_ipc(ipc_fifo_filename); - if (ipc_fd < 0) { - ::sleep(1); + if (ipc_fd < 0) continue; - } + // initialize focused window detection + verbose("initializing focused window detection"); auto focused_window = create_focused_window(); + if (!focused_window) { + error("initializing focused window detection failed"); + } // send configuration + verbose("sending configuration to keymapperd"); if (send_config(ipc_fd, config_file.config())) { + verbose("entering update loop"); + // main loop auto active_override_set = -1; for (;;) { // update configuration, reset on success if (settings.auto_update_config && - config_file.update()) + config_file.update()) { + verbose("configuration updated"); break; + } - if (is_pipe_broken((ipc_fd))) + if (is_pipe_broken((ipc_fd))) { + verbose("connection to keymapperd lost"); break; + } // update active override set if (focused_window && update_focused_window(*focused_window)) { + verbose("detected focused window changed:"); + verbose(" class = '%s'", get_class(*focused_window).c_str()); + verbose(" title = '%s'", get_title(*focused_window).c_str()); + const auto override_set = find_context( config_file.config(), get_class(*focused_window), get_title(*focused_window)); if (active_override_set != override_set) { + if (override_set >= 0) { + verbose("sending 'active context #%i' to keymapperd:", override_set + 1); + const auto& context = config_file.config().contexts[override_set]; + if (!context.window_class_filter.empty()) + verbose(" class filter = '%s'", context.window_class_filter.c_str()); + if (!context.window_title_filter.empty()) + verbose(" title filter = '%s'", context.window_title_filter.c_str()); + } + else { + verbose("sending 'no active context' to keymapperd"); + } + active_override_set = override_set; - if (!send_active_override_set(ipc_fd, active_override_set)) + if (!send_active_override_set(ipc_fd, active_override_set)) { + verbose("connection to keymapperd lost"); break; + } } } usleep(update_interval_ms * 1000); diff --git a/src/linux/client/output.h b/src/linux/client/output.h new file mode 100644 index 00000000..6b2ff0e9 --- /dev/null +++ b/src/linux/client/output.h @@ -0,0 +1,4 @@ +#pragma once + +void error(const char* format, ...); +void verbose(const char* format, ...);