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