For one: Tobias Stoeckmann already stated more yesterday, including that exit(3) in a signal handler is a bad thing. (It surely should have been _exit(2).)
Version 3 (1) doesn't trash errno no more, (2) is hopefully less messy and (3) does no longer introduce a new file, so also more easyness for cvs(1). It fixes a compiler warning in tab_by_name(). Beside that: :c Thank you very much. --steffen Index: src/sbin/wsconsctl/wsconsctl.8 =================================================================== RCS file: /cvs/src/sbin/wsconsctl/wsconsctl.8,v retrieving revision 1.23 diff -a -p -u -r1.23 wsconsctl.8 --- wsconsctl.8 4 Aug 2008 07:32:51 -0000 1.23 +++ wsconsctl.8 1 Feb 2012 14:41:11 -0000 @@ -49,6 +49,8 @@ .Op Fl n .Op Fl f Ar file .Ar name Ns += Ns Ar value ... +.Nm wsconsctl +.Fl r .Sh DESCRIPTION The .Nm @@ -81,6 +83,12 @@ symbol. See the .Sx EXAMPLES section for more details. +.It Fl r +Enters a raw interactive mode in which keypresses are displayed +as their keycodes. +This mode always operates on standard input +and does not work on pseudo terminals. +After five seconds of inactivity the program terminates. .El .Pp The Index: src/sbin/wsconsctl/wsconsctl.c =================================================================== RCS file: /cvs/src/sbin/wsconsctl/wsconsctl.c,v retrieving revision 1.26 diff -a -p -u -r1.26 wsconsctl.c --- wsconsctl.c 20 Aug 2010 00:20:55 -0000 1.26 +++ wsconsctl.c 1 Feb 2012 14:48:27 -0000 @@ -30,12 +30,18 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsksymdef.h> #include <fcntl.h> #include <err.h> #include <errno.h> +#include <signal.h> #include <string.h> #include <stdio.h> #include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <termios.h> #include <unistd.h> #include "wsconsctl.h" @@ -45,9 +51,7 @@ extern struct field keyboard_field_tab[] extern struct field mouse_field_tab[]; extern struct field display_field_tab[]; -void usage(void); - -struct vartypesw { +static struct vartypesw { const char *name; struct field *field_tab; void (*getval)(int); @@ -63,24 +67,15 @@ struct vartypesw { { NULL } }; -struct vartypesw *tab_by_name(const char *, int *); - -void -usage() -{ - fprintf(stderr, - "usage: %s [-an]\n" - " %s [-n] [-f file] name ...\n" - " %s [-n] [-f file] name=value ...\n" - " %s [-n] [-f file] name+=value ...\n", - __progname, __progname, __progname, __progname); - exit(1); -} +static void usage(void); +static struct vartypesw *tab_by_name(const char *, int *); +static int raw_mode(void); int main(int argc, char *argv[]) { - int i, ch, error = 0, aflag = 0, do_merge, putval, devidx, devfd; + int i, ch, error = 0, aflag = 0, rflag = 0, + do_merge, putval, devidx, devfd; struct vartypesw *sw = NULL; char *getsep = "=", *setsep = " -> ", *p; char *wdev = NULL; @@ -88,7 +83,7 @@ main(int argc, char *argv[]) struct field *f; char devname[20]; - while ((ch = getopt(argc, argv, "af:nw")) != -1) { + while ((ch = getopt(argc, argv, "af:nrw")) != -1) { switch(ch) { case 'a': aflag = 1; @@ -99,6 +94,9 @@ main(int argc, char *argv[]) case 'n': getsep = setsep = NULL; break; + case 'r': + rflag = 1; + break; case 'w': /* compat */ break; @@ -110,12 +108,17 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if (argc > 0 && aflag != 0) - errx(1, "excess arguments after -a"); - if (argc == 0) - aflag = 1; + if (argc > 0 && (aflag != 0 || rflag != 0)) + errx(1, "excess arguments after -%c", (aflag ? 'a' : 'r')); + if (rflag == 0) { + if (argc == 0) + aflag = 1; + } else if (aflag != 0 || wdev != NULL || getsep == NULL) + errx(1, "-r is mutual exclusive with other options"); - if (aflag != 0) { + if (rflag != 0) + error = raw_mode(); + else if (aflag != 0) { for (sw = typesw; sw->name; sw++) { for (devidx = 0;; devidx++) { device = (*sw->nextdev)(devidx); @@ -280,7 +283,20 @@ main(int argc, char *argv[]) exit(error); } -struct vartypesw * +static void +usage() +{ + fprintf(stderr, + "usage: %s [-an]\n" + " %s [-n] [-f file] name ...\n" + " %s [-n] [-f file] name=value ...\n" + " %s [-n] [-f file] name+=value ...\n" + " %s -r\n", + __progname, __progname, __progname, __progname, __progname); + exit(1); +} + +static struct vartypesw * tab_by_name(const char *var, int *idx) { struct vartypesw *sw; @@ -295,13 +311,13 @@ tab_by_name(const char *var, int *idx) if (!p) p = strchr(var, '\0'); + i = (int)(p - var); if (!sw->name) { - i = p - var; warnx("%*.*s: no such variable", i, i, var); return (NULL); } - if ((p - var) > strlen(sw->name)) { + if ((size_t)i > strlen(sw->name)) { c = (char *)var; c = c + strlen(sw->name); i = 0; @@ -324,3 +340,104 @@ tab_by_name(const char *var, int *idx) return (sw); } + +static int raw_caught_sig; +static struct termios raw_tios_orig, raw_tios_raw; + +static void raw_onsig(int sig); +static void raw_on(void), raw_off(void); + +int +raw_mode(void) +{ + ssize_t i, skip; + struct sigaction sa; + struct itimerval it; + unsigned char *cursor, buffer[64]; + + if (tcgetattr(STDIN_FILENO, &raw_tios_orig) < 0) + err(1, "Can't query terminal attributes"); + raw_tios_raw = raw_tios_orig; + (void)cfmakeraw(&raw_tios_raw); + + sa.sa_handler = &raw_onsig; + sa.sa_flags = 0; + (void)sigfillset(&sa.sa_mask); + for (i = 0; i++ < NSIG;) + if (sigaction((int)i, &sa, NULL) < 0 && i == SIGALRM) + err(1, "Can't install SIGALRM signal handler"); + + it.it_value.tv_sec = 5; + it.it_value.tv_usec = 0; + it.it_interval.tv_sec = it.it_interval.tv_usec = 0; + + raw_on(); + (void)printf("You may now use the keyboard.\r\n" + "After %d seconds of inactivity the program terminates\r\n", + (int)it.it_value.tv_sec); + for (i = skip = 0;;) { + if (setitimer(ITIMER_REAL, &it, NULL) < 0) { + raw_off(); + err(1, "Can't install wakeup timer"); + } + + i = read(STDIN_FILENO, buffer + skip, sizeof(buffer) - skip); + if (i <= 0) + break; + i += skip; + + for (cursor = buffer; --i >= 0;) { + unsigned int k = *cursor++; + if ((k & 0xF0) == 0xE0 || (k & 0xF8) == 0xF0) { + if (--i < 0) { + buffer[0] = (unsigned char)k; + skip = 1; + break; + } + k <<= 8; + k |= *cursor++; + k &= ((k & 0xF000) == 0xE000) ? 0x0FFF : 0x00FF; + } + (void)printf("keycode %3u %-7s\r\n", + (k & ~0x0080), (k & 0x0080) ? "release" : "press"); + skip = 0; + } + } + raw_off(); + + return (raw_caught_sig < 2); +} + +static void +raw_onsig(int sig) +{ + raw_caught_sig = 1 + (sig == SIGALRM); +} + +static void +raw_on(void) +{ + int arg = WSKBD_RAW; + + if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_tios_raw) < 0) + err(1, "Can't set terminal attributes"); + if (ioctl(STDIN_FILENO, WSKBDIO_SETMODE, &arg) < 0) { + arg = errno; + (void)tcsetattr(STDIN_FILENO, TCSANOW, &raw_tios_orig); + errx(1, ((arg == ENOTTY) + ? "This mode won't work on pseudo terminals" + : "Can't put keyboard in raw mode (the " + "WSDISPLAY_COMPAT_RAWKBD kernel option is required)")); + } + return; +} + +static void +raw_off(void) +{ + int arg = WSKBD_TRANSLATED; + + (void)ioctl(STDIN_FILENO, WSKBDIO_SETMODE, &arg); + (void)tcsetattr(STDIN_FILENO, TCSANOW, &raw_tios_orig); + return; +}