[systemd-devel] [RFC 09/12] gfx: add kbd test
David Herrmann
dh.herrmann at gmail.com
Wed Nov 27 10:48:44 PST 2013
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.herrmann at 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
More information about the systemd-devel
mailing list