code: plan9front

Download patch

ref: 4df727b57afa439027df111205b29ed4590f6a72
parent: 444ba84bc1bb4ce22e6675cd49470b437e7bc3a7
author: Jacob Moody <moody@posixcafe.org>
date: Mon May 22 12:36:32 EDT 2023

kbremap: switch keyboard maps with a keyboard shortcut

--- a/sys/man/1/kbmap
+++ b/sys/man/1/kbmap
@@ -1,11 +1,22 @@
 .TH KBMAP 1
 .SH NAME
-kbmap \- show a list of available keyboard maps and switch between them.
+kbmap, kbremap \- show a list of available keyboard maps and switch between them.
 .SH SYNOPSIS
 .B kbmap
 [
 .IR file ...
 ]
+.PP
+.B kbremap
+[
+.B -m
+.I mod
+]
+[
+.B -k
+.I scancode
+]
+map1 map2 ...
 .SH DESCRIPTION
 .I Kbmap
 shows a single column consisting of the names of keyboard maps for different
@@ -18,16 +29,49 @@
 keyboard mapping defined in the corresponding file to become current
 for the system; typing 'q' quits.
 .PP
+.I Kbremap
+reads keyboard events from standard input, filters out a shortcut
+to change the keyboard map, and writes the result to standard
+output. The shortcut cycles through the keyboard maps provided
+as arguments. By default this shortcut is mapped to
+.LR Ctrl
++
+.LR Space .
+The
+.B -m
+and
+.B -k
+flags change the default mod and key used respectfully.
+.I Mod
+is given as a numeric shift layer as understood by
+.IR kbdfs (8).
+.PP
 .I Kbmap
-requires that the file
+and
+.I kbremap
+require that the file
 .B /dev/kbmap
 served by 
 .IR kbdfs (8)
 exists and is writable.
-..SH FILES
-.TF /lib/kbmap/*
+.SH EXAMPLES
+Use
+.I kbremap
+with
+.B /dev/kbdtap
+provided by
+.IR rio (4):
+.IP
+.EX
+kbremap us de uk </dev/kbdtap >/dev/kbdtap
+.EE
+.PP
+.SH FILES
+.B /sys/lib/kbmap/*
 .SH SOURCE
 .B /sys/src/cmd/kbmap.c
+.br
+.B /sys/src/cmd/kbremap.c
 .SH "SEE ALSO"
 .IR kbdfs (8)
 .SH BUGS
--- /dev/null
+++ b/sys/src/cmd/kbremap.c
@@ -1,0 +1,80 @@
+#include <u.h>
+#include <libc.h>
+
+char *mod = "4";
+char *key = "57";
+enum{ Kswitch = 0xF000|0x0701 };
+
+static void
+writemap(char *file)
+{
+	int i, fd, ofd;
+	char buf[8192];
+
+	if((fd = open(file, OREAD)) < 0)
+		sysfatal("cannot open %s: %r", file);
+
+	if((ofd = open("/dev/kbmap", OWRITE)) < 0)
+		sysfatal("cannot open /dev/kbmap: %r");
+
+	while((i = read(fd, buf, sizeof buf)) > 0)
+		if(write(ofd, buf, i) != i)
+			sysfatal("writing /dev/kbmap: %r");
+
+	fprint(ofd, "%s\t%s\t0x%X\n", mod, key, Kswitch);
+	close(fd);
+	close(ofd);
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [ -m mod ] [ -k scancode ] map1 map2 ...\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	char *p, buf[8192];
+	Rune r;
+	long n;
+	int index;
+
+	index = 0;
+	ARGBEGIN{
+	case 'm':
+		mod = EARGF(usage());
+		break;
+	case 'k':
+		key = EARGF(usage());
+		break;
+	default:
+		usage();
+	}ARGEND;
+	if(argc < 2)
+		usage();
+
+	chdir("/sys/lib/kbmap");
+	writemap("ascii");
+	writemap(argv[0]);
+	for(;;){
+		n = read(0, buf, sizeof buf - 1);
+		if(n <= 0)
+			break;
+		buf[n] = '\0';
+		for(p = buf; p < buf+n; p += strlen(p) + 1){
+			chartorune(&r, p+1);
+			if(*p != 'c' || r != Kswitch){
+				write(1, p, strlen(p));
+				continue;
+			}
+			index++;
+			if(argv[index] == nil)
+				index = 0;
+			writemap("ascii");
+			writemap(argv[index]);
+		}
+	}
+	exits(nil);
+}