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