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;
+}

Reply via email to