The test-kbd helper simply attaches to the current session (or in case --all is passed to the system) and prints all keyboard events generated by attached keyboards.
It's meant to be used to debug sd_gfx_kbd/monitor issues regarding keymap/kbd setup. --- .gitignore | 1 + Makefile.am | 16 +++ src/libsystemd-gfx/test-kbd.c | 314 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 src/libsystemd-gfx/test-kbd.c diff --git a/.gitignore b/.gitignore index f8f6c8a..f4921f5 100644 --- a/.gitignore +++ b/.gitignore @@ -131,6 +131,7 @@ /test-journal-init /test-journal-syslog /test-journal-verify +/test-kbd /test-libudev /test-list /test-log diff --git a/Makefile.am b/Makefile.am index 189cc89..e8822b2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3878,6 +3878,22 @@ libsystemd_gfx_la_LIBADD = \ libudev-internal.la \ src/libsystemd-gfx/unifont.bin.lo +test_kbd_SOURCES = \ + src/libsystemd-gfx/test-kbd.c + +test_kbd_CFLAGS = \ + $(AM_CFLAGS) \ + $(GFX_CFLAGS) + +test_kbd_LDADD = \ + $(GFX_LIBS) \ + libsystemd-bus-internal.la \ + libsystemd-shared.la \ + libsystemd-gfx.la + +tests += \ + test-kbd + src/libsystemd-gfx/unifont.bin: make-unifont.py src/libsystemd-gfx/unifont.hex $(AM_V_GEN)cat $(top_srcdir)/src/libsystemd-gfx/unifont.hex | $(PYTHON) $< >$@ diff --git a/src/libsystemd-gfx/test-kbd.c b/src/libsystemd-gfx/test-kbd.c new file mode 100644 index 0000000..b902171 --- /dev/null +++ b/src/libsystemd-gfx/test-kbd.c @@ -0,0 +1,314 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 David Herrmann <dh.herrm...@gmail.com> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <inttypes.h> +#include <libevdev/libevdev.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include <xkbcommon/xkbcommon.h> + +#include "build.h" +#include "def.h" +#include "log.h" +#include "macro.h" +#include "missing.h" +#include "sd-bus.h" +#include "sd-daemon.h" +#include "sd-event.h" +#include "sd-gfx.h" +#include "util.h" + +typedef struct Test Test; + +struct Test { + sd_event *event; + sd_event_source *sigs[_NSIG]; + sd_gfx_monitor *mon; +}; + +static bool arg_all; +static const char *arg_gpus; +static const char *arg_keymap; + +static void test_kbd_fn(sd_gfx_kbd *kbd, void *fn_data, sd_gfx_kbd_event *ev) { + unsigned int i; + const char *t; + char s[128]; + uint32_t c; + + printf(" %5d", ev->keycode); + t = libevdev_event_code_get_name(EV_KEY, ev->keycode); + printf(" | %20s", t ? : "<unknown>"); + + printf(" | %s", (ev->mods & SD_GFX_SHIFT) ? "SHIFT" : " "); + printf(" | %s", (ev->mods & SD_GFX_CAPSL) ? "CAPSL" : " "); + printf(" | %s", (ev->mods & SD_GFX_CTRL) ? "CTRL" : " "); + printf(" | %s", (ev->mods & SD_GFX_ALT) ? "ALT" : " "); + printf(" | %s", (ev->mods & SD_GFX_LOGO) ? "LOGO" : " "); + + printf(" |"); + for (i = 0; i < ev->sym_count; ++i) { + xkb_keysym_get_name(ev->keysyms[i], s, sizeof(s)); + printf(" %20s", s); + } + + printf(" |"); + for (i = 0; i < ev->sym_count; ++i) { + c = ev->codepoints[i]; + if (c == 0xffffffff) + continue; + if (c < 0x1f) + continue; + if (c >= 0x7f && c <= 0x9f) + continue; + + /* Just a proof-of-concept hack. This works because glibc uses + * UCS-4 as the internal wchar_t encoding. */ + printf(" %lc", ev->codepoints[i]); + } + + printf("\n"); +} + +static void test_add(Test *t, sd_gfx_kbd *kbd) { + sd_gfx_kbd_set_event_fn(kbd, test_kbd_fn); +} + +static void test_remove(Test *t, sd_gfx_kbd *kbd) { + sd_gfx_kbd_set_event_fn(kbd, NULL); +} + +static void test_event_fn(sd_gfx_monitor *mon, void *fn_data, sd_gfx_monitor_event *ev) { + struct Test *t = fn_data; + + switch (ev->type) { + case SD_GFX_MONITOR_CREATE: + if (ev->devtype == SD_GFX_DEV_KBD) + test_add(t, ev->kbd); + else + log_notice("unknown device of type %d", ev->devtype); + break; + case SD_GFX_MONITOR_DESTROY: + if (ev->devtype == SD_GFX_DEV_KBD) + test_remove(t, ev->kbd); + break; + default: + log_warning("unhandled monitor event: %d", ev->type); + break; + } +} + +static int test_signal_fn(sd_event_source *s, const struct signalfd_siginfo *ssi, void *data) { + Test *t = data; + + log_notice("catched signal %d, exiting..", (int)ssi->ssi_signo); + sd_event_request_quit(t->event); + + return 0; +} + +static int test_new(Test **out) { + static const int sigs[] = { + SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGPIPE, 0 + }; + unsigned int flags; + sigset_t mask; + Test *t; + int r, i; + + t = calloc(1, sizeof(*t)); + if (!t) + return log_oom(); + + r = sd_event_default(&t->event); + if (r < 0) { + log_error("cannot get default event-loop: %d", r); + goto err_t; + } + + sigemptyset(&mask); + for (i = 0; sigs[i]; ++i) { + sigaddset(&mask, sigs[i]); + r = sd_event_add_signal(t->event, + sigs[i], + test_signal_fn, + t, + &t->sigs[i]); + if (r < 0) { + log_error("cannot block signal %d: %d", + sigs[i], r); + goto err_sigs; + } + } + sigprocmask(SIG_BLOCK, &mask, NULL); + + flags = SD_GFX_MONITOR_DEFAULT; + if (arg_all) + flags |= SD_GFX_MONITOR_IGNORE_SEATS; + + r = sd_gfx_monitor_new(&t->mon, + SD_GFX_DEV_EVDEV_MASK, + flags, + t->event); + if (r < 0) + goto err_sigs; + + sd_gfx_monitor_set_fn_data(t->mon, t); + sd_gfx_monitor_set_event_fn(t->mon, test_event_fn); + sd_gfx_monitor_parse_cmdline(t->mon); + if (arg_gpus) + sd_gfx_monitor_set_gpus(t->mon, arg_gpus); + if (arg_keymap) + sd_gfx_monitor_set_keymap(t->mon, arg_keymap); + + *out = t; + return 0; + +err_sigs: + for (i = 0; t->sigs[i]; ++i) + sd_event_source_unref(t->sigs[i]); + sd_event_unref(t->event); +err_t: + free(t); + return r; +} + +static void test_free(Test *t) { + int i; + + if (!t) + return; + + sd_gfx_monitor_free(t->mon); + for (i = 0; t->sigs[i]; ++i) + sd_event_source_unref(t->sigs[i]); + sd_event_unref(t->event); + free(t); +} + +static int test_run(Test *t) { + return sd_event_loop(t->event); +} + +static int help(void) { + printf("%s [OPTIONS...] ...\n\n" + "sd-gfx keyboard test.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --all Use all devices\n" + " --gpus=MATCH List of GPUs to use\n" + " --keymap=LMVO XKB keymap to use\n" + , program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + ARG_ALL, + ARG_GPUS, + ARG_KEYMAP, + }; + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "all", no_argument, NULL, ARG_ALL }, + { "gpus", required_argument, NULL, ARG_GPUS }, + { "keymap", required_argument, NULL, ARG_KEYMAP }, + {} + }; + int c; + + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + switch(c) { + case 'h': + return help(); + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + case ARG_ALL: + arg_all = true; + break; + case ARG_GPUS: + arg_gpus = optarg; + break; + case ARG_KEYMAP: + arg_keymap = optarg; + break; + case '?': + return -EINVAL; + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind < argc) { + log_error("This program does not take arguments."); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + Test *t = NULL; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + setlocale(LC_ALL, ""); + + r = parse_argv(argc, argv); + if (r < 0) + return EXIT_FAILURE; + if (r == 0) + return EXIT_SUCCESS; + + r = test_new(&t); + if (r < 0) + goto finish; + + system("stty -echo"); + r = test_run(t); + system("stty echo"); + +finish: + if (t) + test_free(t); + + log_debug("exiting.."); + return abs(r); +} -- 1.8.4.2 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel