shithub: snippets

Download patch

ref: 0cd57b4514cb22dc3304f523680a1679e6e0479b
parent: 6c5f25a2fd0da669d735d457d0e7c04d2dc2efcc
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Feb 2 14:08:53 EST 2022

add kbd.[ch] (thanks phil9)

--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@
 
 * `atomics9*` a set of atomics for Plan 9
 * `c_builtins*` a few __builtin_* for Plan 9, useful for porting other software
+* `kbd.[ch]` API to handle keyboard on lower level, with all modifiers accessible, on Plan 9
 * `lrint.c` lrint* implementation
 * `msr.c` MSR reading tool
 * `nanosec.c` nanosec(), a replacement for (way more expensive) nsec()
--- /dev/null
+++ b/kbd.c
@@ -1,0 +1,143 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <keyboard.h>
+#include "kbd.h"
+
+/*
+
+example
+
+void
+threadmain(int, char**)
+{
+	Kbdctl *kctl;
+	Key k;
+	Alt a[] = {
+		{ nil, &k, CHANRCV },
+		{ nil, nil, CHANEND },
+	};
+
+	kctl = initkbd();
+	if(kctl == nil)
+		sysfatal("initkbd: %r");
+	a[0].c = kctl->c;
+	for(;;){
+		if(alt(a) == 0){
+			if(k.k == Kdel)
+				break;
+			else
+				fprint(2, "KEY '%C' (mods=%b)\n", k.k, k.mods);
+		}
+	}
+	closekbd(kctl);
+	threadexitsall(nil);
+}
+*/
+
+static void
+kbdproc(void *v)
+{
+	Kbdctl *kc;
+	char buf[128], buf2[128], *s;
+	long n;
+	Rune r;
+	Key k;
+	int mods = 0;
+
+	kc = v;
+	threadsetname("kbdproc");
+	buf[0] = 0;
+	buf2[0] = 0;
+	buf2[1] = 0;
+	while(kc->fd >= 0){
+		if(buf[0] != 0){
+			n = strlen(buf)+1;
+			memmove(buf, buf+n, sizeof(buf)-n);
+		}
+		if (buf[0] == 0) {
+			n = read(kc->fd, buf, sizeof(buf)-1);
+			if (n <= 0){
+				yield();
+				if(kc->fd < 0)
+					threadexits(nil);
+				break;
+			}
+			buf[n-1] = 0;
+			buf[n] = 0;
+		}
+		switch(buf[0]){
+		case 'c':
+			if(chartorune(&r, buf+1) > 0 && r != Runeerror){
+				k = (Key){ r, mods };
+				nbsend(kc->c, &k);
+			}
+		default:
+			continue;
+		case 'k':
+			s = buf+1;
+			while(*s){
+				s += chartorune(&r, s);
+				if(utfrune(buf2+1, r) == nil){
+					if(r == Kctl)
+						mods |= Mctrl;
+					else if(r == Kalt)
+						mods |= Malt;
+					else if(r == Kshift)
+						mods |= Mshift;
+					else{
+						k = (Key){r, mods};
+						send(kc->c, &k);
+					}
+				}
+			}
+			break;
+		case 'K':
+			s = buf2+1;
+			while(*s){
+				s += chartorune(&r, s);
+				if(utfrune(buf+1, r) == nil) {
+					if(r == Kctl)
+						mods ^= Mctrl;
+					else if(r == Kalt)
+						mods ^= Malt;
+					else if(r == Kshift)
+						mods ^= Mshift;
+				}
+			}
+			break;
+		}
+		strcpy(buf2, buf);
+	}
+}
+
+Kbdctl*
+initkbd(void)
+{
+	Kbdctl *kc;
+
+	kc = malloc(sizeof *kc);
+	if(kc == nil)
+		return nil;
+	kc->fd = open("/dev/kbd", OREAD);
+	if(kc->fd < 0){
+		free(kc);
+		return nil;
+	}
+	kc->c = chancreate(sizeof(Key), 0);
+	if(kc->c == nil){
+		close(kc->fd);
+		free(kc);
+		return nil;
+	}
+	kc->pid = proccreate(kbdproc, kc, 8192);
+	return kc;
+}
+
+void
+closekbd(Kbdctl *kc)
+{
+	close(kc->fd);
+	kc->fd = -1;
+	threadint(kc->pid);
+}
--- /dev/null
+++ b/kbd.h
@@ -1,0 +1,25 @@
+typedef struct Kbdctl Kbdctl;
+typedef struct Key Key;
+
+struct Kbdctl
+{
+	int fd;
+	int pid;
+	Channel *c;
+};
+
+struct Key
+{
+	Rune k;
+	ushort mods;
+};
+
+enum
+{
+	Mctrl	= 1<<0,
+	Malt	= 1<<1,
+	Mshift	= 1<<2,
+};
+
+Kbdctl *initkbd(void);
+void closekbd(Kbdctl*);