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);

Reply via email to