Hi, just want to post a corrected and better version which prints the (correct) keycode on the left and the current assignments on the right (if any). The entire code is conditionalized on !SMALL. Plain I/O tested a lot outside of wsconsctl(8).
wsconsctl(8) supports -f with default/-a, so i've also updated that in respect to manual and usage. May have been left off deliberately though. --steffen Forza Figa! Index: util.c =================================================================== RCS file: /Users/steffen/arena/code.openbsd/src/sbin/wsconsctl/util.c,v retrieving revision 1.55 diff -a -p -u -r1.55 util.c --- util.c 20 Sep 2011 17:00:24 -0000 1.55 +++ util.c 28 Mar 2012 17:38:28 -0000 @@ -457,35 +457,41 @@ rd_field(struct field *f, char *val, int void print_kmap(struct wskbd_map_data *map) { - struct wscons_keymap *mp; int i; - for (i = 0; i < map->maplen; i++) { - mp = map->map + i; + for (i = 0; i < (int)map->maplen; i++) + print_kmap_entry(map->map + i, i); + ksymenc(0); +} - if (mp->command == KS_voidSymbol && - mp->group1[0] == KS_voidSymbol && - mp->group1[1] == KS_voidSymbol && - mp->group2[0] == KS_voidSymbol && - mp->group2[1] == KS_voidSymbol) - continue; - printf("\n"); - printf("keycode %u =", i); - if (mp->command != KS_voidSymbol) - printf(" %s", ksym2name(mp->command)); - printf(" %s", ksym2name(mp->group1[0])); - if (mp->group1[0] != mp->group1[1] || - mp->group1[0] != mp->group2[0] || - mp->group1[0] != mp->group2[1]) { - printf(" %s", ksym2name(mp->group1[1])); - if (mp->group1[0] != mp->group2[0] || - mp->group1[1] != mp->group2[1]) { - printf(" %s", ksym2name(mp->group2[0])); - printf(" %s", ksym2name(mp->group2[1])); - } +void +print_kmap_entry(struct wscons_keymap *mp, int keycode) +{ + if (mp->command == KS_voidSymbol && + mp->group1[0] == KS_voidSymbol && + mp->group1[1] == KS_voidSymbol && + mp->group2[0] == KS_voidSymbol && + mp->group2[1] == KS_voidSymbol) + return; + + if (keycode >= 0) + printf("\nkeycode %u ", keycode); + putchar('='); + + if (mp->command != KS_voidSymbol) + printf(" %s", ksym2name(mp->command)); + printf(" %s", ksym2name(mp->group1[0])); + if (mp->group1[0] != mp->group1[1] || + mp->group1[0] != mp->group2[0] || + mp->group1[0] != mp->group2[1]) { + printf(" %s", ksym2name(mp->group1[1])); + if (mp->group1[0] != mp->group2[0] || + mp->group1[1] != mp->group2[1]) { + printf(" %s", ksym2name(mp->group2[0])); + printf(" %s", ksym2name(mp->group2[1])); } } - ksymenc(0); + return; } void Index: wsconsctl.8 =================================================================== RCS file: /Users/steffen/arena/code.openbsd/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 28 Mar 2012 18:03:32 -0000 @@ -37,6 +37,7 @@ .Sh SYNOPSIS .Nm wsconsctl .Op Fl an +.Op Fl f Ar file .Nm wsconsctl .Op Fl n .Op Fl f Ar file @@ -49,6 +50,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 +84,13 @@ symbol. See the .Sx EXAMPLES section for more details. +.It Fl r +Enters an interactive mode in which keypresses are displayed +as their raw keyboard scancodes. +This mode always operates on standard input +and does not work on pseudo terminals. +It is not available in SMALL environments. +After five seconds of inactivity the program terminates. .El .Pp The Index: wsconsctl.c =================================================================== RCS file: /Users/steffen/arena/code.openbsd/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 28 Mar 2012 17:46:06 -0000 @@ -37,8 +37,23 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> + +#ifndef SMALL +# include <signal.h> +# include <sys/ioctl.h> +# include <sys/time.h> +# include <termios.h> +# include <dev/wscons/wsconsio.h> +# include <dev/wscons/wsksymdef.h> +#endif + #include "wsconsctl.h" +#ifndef SMALL +/* How many seconds of inactivity before termination in -r mode */ +# define ALARM_DELAY 5 +#endif + extern const char *__progname; /* from crt0.o */ extern struct field keyboard_field_tab[]; @@ -64,6 +79,9 @@ struct vartypesw { }; struct vartypesw *tab_by_name(const char *, int *); +#ifndef SMALL +static int raw_mode(void); +#endif void usage() @@ -72,15 +90,20 @@ usage() "usage: %s [-an] [-f file]\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); + " %s [-n] [-f file] name+=value ...\n" +#ifndef SMALL + " %s -r\n", + __progname +#endif + , __progname, __progname, __progname, __progname); exit(1); } 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 +111,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; @@ -102,6 +125,11 @@ main(int argc, char *argv[]) case 'w': /* compat */ break; + case 'r': + rflag = 1; +#ifndef SMALL + break; +#endif default: usage(); } @@ -110,11 +138,19 @@ 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"); +#ifndef SMALL + if (rflag != 0) { + error = raw_mode(); + } else +#endif if (aflag != 0) { for (sw = typesw; sw->name; sw++) { for (devidx = 0;; devidx++) { @@ -295,13 +331,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 +360,134 @@ tab_by_name(const char *var, int *idx) return (sw); } + +#ifndef SMALL + +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) +{ + struct vartypesw *sw; + struct field *f; + struct wskbd_map_data *map; + int devidx; + ssize_t len, skip; + unsigned char *cursor, buffer[64]; + struct sigaction sa; + struct itimerval it; + + sw = tab_by_name("keyboard", &devidx); + if (sw == NULL) + errx(1, "Cannot query key assignments"); + f = field_by_name(sw->field_tab, "keyboard.map"); + f->flags |= FLG_GET; + (*sw->getval)(STDIN_FILENO); + map = (struct wskbd_map_data*)f->valp; + + 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 (len = 0; len++ < NSIG;) + if (sigaction((int)len, &sa, NULL) < 0 && len == SIGALRM) + err(1, "Can't install SIGALRM signal handler"); + + it.it_value.tv_sec = ALARM_DELAY; + 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", + ALARM_DELAY); + + for (skip = 0;;) { + if (setitimer(ITIMER_REAL, &it, NULL) < 0) { + raw_off(); + err(1, "Can't install wakeup timer"); + } + + len = read(STDIN_FILENO, buffer + skip, sizeof(buffer) - skip); + if (len <= 0) + break; + len += skip; + + for (cursor = buffer; --len >= 0;) { + unsigned isplain = 1, kc = *cursor++, rc = kc, isdown; + + if ((rc & 0xF0) == 0xE0 || (rc & 0xF8) == 0xF0) { + isplain = 0; + if (--len < 0) { + *buffer = (unsigned char)rc; + skip = 1; + break; + } + + kc <<= 8; + kc |= *cursor++; + rc = kc; + kc &= ((kc & 0xF000) == 0xE000) ? 0xFFF : 0xFF; + } + skip = 0; + + isdown = (0 == (kc & 0x80)); + kc &= ~0x0080; + if (! isplain) + kc |= 0x80; + + printf("keycode %3u %-7s ", + kc, (isdown ? "press" : "release")); + if (kc < map->maplen) + print_kmap_entry(map->map + kc, -1); + printf("\r\n"); + } + } + 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 set keyboard in raw mode (" + "WSDISPLAY_COMPAT_RAWKBD kernel option 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; +} + +#endif /* SMALL */ Index: wsconsctl.h =================================================================== RCS file: /Users/steffen/arena/code.openbsd/src/sbin/wsconsctl/wsconsctl.h,v retrieving revision 1.13 diff -a -p -u -r1.13 wsconsctl.h --- wsconsctl.h 20 Aug 2010 00:20:55 -0000 1.13 +++ wsconsctl.h 28 Mar 2012 17:38:14 -0000 @@ -69,6 +69,7 @@ struct field * field_by_value(struct field *, void *); void pr_field(const char *, struct field *, const char *); void rd_field(struct field *, char *, int); +void print_kmap_entry(struct wscons_keymap *, int); int name2ksym(char *); char * ksym2name(int); void ksymenc(int);