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