ref: fbbb449cc0bd35ebb89b87d5b46ed2874246876e
parent: 98f4157b5a2f9bce37939e2ea807b631943d969c
author: cinap_lenrek <cinap_lenrek@centraldogma>
date: Sat May 28 04:16:01 EDT 2011
big /dev/kbd change, new format, support Alt+Stuff (key composing)
--- a/sys/man/8/kbdfs
+++ b/sys/man/8/kbdfs
@@ -152,26 +152,41 @@
.SS Keyboard
A read on the
.BR kbd
-file returns a null terminated, variable-length,
+file returns the character
+.B k,
+.B K
+or
+.B c
+followed by a null terminated, variable-length,
.SM UTF
-encoded string of all the keys that are currently pressed (key is
-down) on the keyboard. This includes all keys that have a keyboard
-mapping and modifier keys. No key is treated specially. A new event
-is generated on each state change or at keyboard repeat rate and put
-in a buffer. Each
-.IR read (2)
-will return a single event or block until there are new events
-available. The read data is always terminated with a null-byte,
-so when all keys are released (all keys are up), a single
-null-byte will be returned. Newly pressed keys are appended to the
-string before the null-byte. Key releases remove the
-character from the string. Change on a modifier key like
+encoded string. The
+.B k
+message is send when a key is pressed down
+and
+.B K
+when a key is released. The following string contains all the keycodes
+of the keys that are currently pressed down in decomposed form.
+This includes all keys that have a keyboard mapping and modifier keys.
+Some keys may produce multiple characters like
.B Shift
-or
-.B Num
-will not change
-the characters already present in the string, but will
-take effect on newly pressed keys. Opening the
+and
+.B a
+will produce
+.B Shift,
+.B a,
+.B A
+in the string. The string following the
+.B c
+message contains the single character that would have been appeared
+on the
+.BR cons
+file instead. The
+.B c
+message will be resent at the keyboard repeat rate.
+Each
+.IR read (2)
+will return a single message or block until there are new messages
+available. Opening the
.BR kbd
file disables input processing on the
.BR cons
@@ -222,4 +237,4 @@
.SH FILES
.B /dev/lib/kbmap/*
.SH SOURCE
-.B /sys/src/cmd/aux/kbdfs.c
+.B /sys/src/cmd/aux/kbdfs
--- a/sys/src/cmd/aux/kbdfs.c
+++ /dev/null
@@ -1,1179 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include <fcall.h>
-#include <thread.h>
-#include <keyboard.h>
-#include <9p.h>
-
-enum {
- Nscan= 128,
-
- Qroot= 0,
- Qkbd,
- Qkbin,
- Qkbmap,
- Qcons,
- Qconsctl,
- Nqid,
-
- Rawon= 0,
- Rawoff,
- Kbdflush,
-
- STACK = 8*1024,
-};
-
-typedef struct Key Key;
-typedef struct Scan Scan;
-
-struct Key {
- int down;
- int c;
- Rune r;
- Rune b;
-};
-
-struct Scan {
- int esc1;
- int esc2;
- int caps;
- int num;
- int shift;
- int ctl;
- int alt;
- int altgr;
- int leds;
-};
-
-struct Qtab {
- char *name;
- int mode;
- int type;
-} qtab[Nqid] = {
- "/",
- DMDIR|0500,
- QTDIR,
-
- "kbd",
- 0600,
- 0,
-
- "kbin",
- 0200,
- 0,
-
- "kbmap",
- 0600,
- 0,
-
- "cons",
- 0600,
- 0,
-
- "consctl",
- 0600,
- 0,
-};
-
-char Eshort[] = "read count too small";
-char Ebadarg[] = "invalid argument";
-char Eperm[] = "permission denied";
-char Einuse[] = "file in use";
-char Enonexist[] = "file does not exist";
-char Ebadspec[] = "bad attach specifier";
-char Ewalk[] = "walk in non directory";
-char Efront[] = "the front fell off";
-
-int scanfd;
-int ledsfd;
-int consfd;
-
-int kbdopen;
-int consopen;
-int consctlopen;
-
-int debug;
-
-Channel *keychan; /* Key */
-
-Channel *reqchan; /* Req* */
-Channel *ctlchan; /* int */
-
-Channel *rawchan; /* Rune */
-Channel *linechan; /* char * */
-Channel *kbdchan; /* char* */
-
-/*
- * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
- * A 'standard' keyboard doesn't produce anything above 0x58.
- */
-Rune kbtab[Nscan] =
-{
-[0x00] 0, 0x1b, '1', '2', '3', '4', '5', '6',
-[0x08] '7', '8', '9', '0', '-', '=', '\b', '\t',
-[0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
-[0x18] 'o', 'p', '[', ']', '\n', Kctl, 'a', 's',
-[0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
-[0x28] '\'', '`', Kshift, '\\', 'z', 'x', 'c', 'v',
-[0x30] 'b', 'n', 'm', ',', '.', '/', Kshift, '*',
-[0x38] Kalt, ' ', Kctl, KF|1, KF|2, KF|3, KF|4, KF|5,
-[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Knum, Kscroll, '7',
-[0x48] '8', '9', '-', '4', '5', '6', '+', '1',
-[0x50] '2', '3', '0', '.', 0, 0, 0, KF|11,
-[0x58] KF|12, 0, 0, 0, 0, 0, 0, 0,
-[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x78] 0, Kdown, 0, Kup, 0, 0, 0, 0,
-};
-
-Rune kbtabshift[Nscan] =
-{
-[0x00] 0, 0x1b, '!', '@', '#', '$', '%', '^',
-[0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
-[0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
-[0x18] 'O', 'P', '{', '}', '\n', Kctl, 'A', 'S',
-[0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
-[0x28] '"', '~', Kshift, '|', 'Z', 'X', 'C', 'V',
-[0x30] 'B', 'N', 'M', '<', '>', '?', Kshift, '*',
-[0x38] Kalt, ' ', Kctl, KF|1, KF|2, KF|3, KF|4, KF|5,
-[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Knum, Kscroll, '7',
-[0x48] '8', '9', '-', '4', '5', '6', '+', '1',
-[0x50] '2', '3', '0', '.', 0, 0, 0, KF|11,
-[0x58] KF|12, 0, 0, 0, 0, 0, 0, 0,
-[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x78] 0, Kup, 0, Kup, 0, 0, 0, 0,
-};
-
-Rune kbtabesc1[Nscan] =
-{
-[0x00] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x08] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x10] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x18] 0, 0, 0, 0, '\n', Kctl, 0, 0,
-[0x20] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x28] 0, 0, Kshift, 0, 0, 0, 0, 0,
-[0x30] 0, 0, 0, 0, 0, '/', 0, Kprint,
-[0x38] Kaltgr, 0, 0, 0, 0, 0, 0, 0,
-[0x40] 0, 0, 0, 0, 0, 0, Kbreak, Khome,
-[0x48] Kup, Kpgup, 0, Kleft, 0, Kright, 0, Kend,
-[0x50] Kdown, Kpgdown, Kins, Kdel, 0, 0, 0, 0,
-[0x58] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x78] 0, Kup, 0, 0, 0, 0, 0, 0,
-};
-
-Rune kbtabaltgr[Nscan] =
-{
-[0x00] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x08] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x10] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x18] 0, 0, 0, 0, '\n', Kctl, 0, 0,
-[0x20] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x28] 0, 0, Kshift, 0, 0, 0, 0, 0,
-[0x30] 0, 0, 0, 0, 0, '/', 0, Kprint,
-[0x38] Kaltgr, 0, 0, 0, 0, 0, 0, 0,
-[0x40] 0, 0, 0, 0, 0, 0, Kbreak, Khome,
-[0x48] Kup, Kpgup, 0, Kleft, 0, Kright, 0, Kend,
-[0x50] Kdown, Kpgdown, Kins, Kdel, 0, 0, 0, 0,
-[0x58] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x78] 0, Kup, 0, 0, 0, 0, 0, 0,
-};
-
-Rune kbtabctl[Nscan] =
-{
-[0x00] 0, '', '', '', '', '', '', '',
-[0x08] '', '', '', '', ' ', '', '\b', '\t',
-[0x10] '', '', '', '', '', '', '', '\t',
-[0x18] '', '', '', '', '\n', Kctl, '', '',
-[0x20] '', '', '', '\b', '\n', '', '', '',
-[0x28] '', 0, Kshift, '', '', '', '', '',
-[0x30] '', '', ' ', '', '', '', Kshift, '\n',
-[0x38] Kalt, 0, Kctl, '', '', '', '', '',
-[0x40] '', '', '', ' ', '', '', '', '',
-[0x48] '', '', ' ', '', '', '', '', '',
-[0x50] '', '', '', '', 0, 0, 0, '',
-[0x58] '', 0, 0, 0, 0, 0, 0, 0,
-[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
-[0x78] 0, '', 0, '\b', 0, 0, 0, 0,
-};
-
-void reboot(void);
-
-/*
- * Scan code processing
- */
-void
-kbdputsc(Scan *scan, int c)
-{
- Key key;
-
- /*
- * e0's is the first of a 2 character sequence, e1 the first
- * of a 3 character sequence (on the safari)
- */
- if(c == 0xe0){
- scan->esc1 = 1;
- return;
- } else if(c == 0xe1){
- scan->esc2 = 2;
- return;
- }
-
- key.down = (c & 0x80) == 0;
- key.c = c & 0x7f;
-
- if(key.c >= Nscan)
- return;
-
- if(scan->esc1)
- key.r = kbtabesc1[key.c];
- else if(scan->shift)
- key.r = kbtabshift[key.c];
- else if(scan->altgr)
- key.r = kbtabaltgr[key.c];
- else if(scan->ctl)
- key.r = kbtabctl[key.c];
- else
- key.r = kbtab[key.c];
-
- switch(key.r){
- case Spec|0x60:
- key.r = Kshift;
- break;
- case Spec|0x62:
- key.r = Kctl;
- break;
- case Spec|0x63:
- key.r = Kalt;
- break;
- }
-
- if(scan->esc1)
- key.b = key.r;
- else
- key.b = kbtab[key.c];
-
- if(scan->caps && key.r<='z' && key.r>='a')
- key.r += 'A' - 'a';
-
- if(scan->ctl && scan->alt && key.r == Kdel)
- reboot();
-
- send(keychan, &key);
-
- if(scan->esc1)
- scan->esc1 = 0;
- else if(scan->esc2)
- scan->esc2--;
-
- switch(key.r){
- case Kshift:
- scan->shift = key.down;
- break;
- case Kctl:
- scan->ctl = key.down;
- break;
- case Kaltgr:
- scan->altgr = key.down;
- break;
- case Kalt:
- scan->alt = key.down;
- break;
- case Knum:
- scan->num ^= key.down;
- break;
- case Kcaps:
- scan->caps ^= key.down;
- break;
- }
-}
-
-void
-setleds(Scan *scan, int leds)
-{
- char buf[8];
-
- if(ledsfd < 0 || scan->leds == leds)
- return;
- leds &= 7;
- snprint(buf, sizeof(buf), "%d", leds);
- pwrite(ledsfd, buf, strlen(buf), 0);
- scan->leds = leds;
-}
-
-/*
- * Read scan codes from scanfd
- */
-void
-scanproc(void *)
-{
- uchar buf[64];
- Scan scan;
- int i, n;
-
- threadsetname("scanproc");
-
- memset(&scan, 0, sizeof scan);
- while((n = read(scanfd, buf, sizeof buf)) > 0){
- for(i=0; i<n; i++)
- kbdputsc(&scan, buf[i]);
- setleds(&scan, (scan.num<<1) | (scan.caps<<2));
- }
-}
-
-char*
-utfconv(Rune *r, int n)
-{
- char *s, *p;
- int l;
-
- l = runenlen(r, n) + 1;
- s = emalloc9p(l);
- for(p = s; n > 0; r++, n--)
- p += runetochar(p, r);
- *p = 0;
- return s;
-}
-
-/*
- * Read key events from keychan and produce characters to
- * rawchan and keystate in kbdchan. this way here is only
- * one global keystate even if multiple keyboards are used.
- */
-void
-keyproc(void *)
-{
- Rune rb[Nscan*2];
- int cb[Nscan];
- Key key;
- int i, nb;
- char *s;
-
- threadsetname("keyproc");
-
- nb = 0;
- while(recv(keychan, &key) > 0){
- if(key.down){
- switch(key.r){
- case 0:
- case Kcaps:
- case Knum:
- case Kshift:
- case Kalt:
- case Kctl:
- case Kaltgr:
- break;
- default:
- nbsend(rawchan, &key.r);
- }
- }
-
- for(i=0; i<nb && cb[i] != key.c; i++)
- ;
- if(!key.down){
- while(i < nb && cb[i] == key.c){
- memmove(cb+i, cb+i+1, (nb-i+1) * sizeof(cb[0]));
- memmove(rb+i, rb+i+1, (nb-i+1) * sizeof(rb[0]));
- nb--;
- }
- } else if(i == nb && nb < nelem(cb) && key.b){
- cb[nb] = key.c;
- rb[nb] = key.b;
- nb++;
- if(nb < nelem(cb) && key.r && key.b != key.r){
- cb[nb] = key.c;
- rb[nb] = key.r;
- nb++;
- }
- }
- s = utfconv(rb, nb);
- if(nbsendp(kbdchan, s) <= 0)
- free(s);
- }
-}
-
-/*
- * Read characters from consfd (serial console)
- */
-void
-consproc(void *)
-{
- char *p, *e, *x, buf[64];
- int n, cr;
- Rune r;
-
- threadsetname("consproc");
-
- cr = 0;
- p = buf;
- e = buf + sizeof(buf);
- while((n = read(consfd, p, e - p)) > 0){
- x = buf + n;
- while(p < x && fullrune(p, x - p)){
- p += chartorune(&r, p);
- if(r){
- if(r == '\n' && cr){
- cr = 0;
- continue;
- }
- if(cr = (r == '\r'))
- r = '\n';
- send(rawchan, &r);
- }
- }
- n = x - p;
- memmove(buf, p, n);
- p = buf + n;
- }
-}
-
-/*
- * Cook lines for cons
- */
-void
-lineproc(void *aux)
-{
- Rune rb[256], r;
- Channel *cook;
- int nr, done;
-
- cook = aux;
-
- threadsetname("lineproc");
-
- for(;;){
- nr = 0;
- done = 0;
- do {
- recv(cook, &r);
- switch(r){
- case '\0': /* flush */
- nr = 0;
- continue;
- case '\b': /* backspace */
- case Knack: /* ^U */
- while(nr > 0){
- nr--;
- fprint(1, "\b");
- if(r == '\b')
- break;
- }
- continue;
- case Keof: /* ^D */
- done = 1;
- break;
- case '\n':
- done = 1;
- /* no break */
- default:
- rb[nr++] = r;
- fprint(1, "%C", r);
- }
- } while(!done && nr < nelem(rb));
- sendp(linechan, utfconv(rb, nr));
- }
-}
-
-/*
- * Queue reads to cons and kbd, flushing and
- * relay data between 9p and rawchan / kbdchan.
- */
-void
-ctlproc(void *)
-{
- struct {
- Req *h;
- Req **t;
- } qcons, qkbd, *q;
- enum { Areq, Actl, Araw, Aline, Akbd, Aend };
- Alt a[Aend+1];
- Req *req;
- Fid *fid;
- Rune r;
- char *s, *b, *p, *e;
- int c, n, raw;
- Channel *cook;
-
- threadsetname("ctlproc");
-
- cook = chancreate(sizeof(Rune), 0);
-
- if(scanfd >= 0)
- proccreate(scanproc, nil, STACK);
- if(consfd >= 0)
- proccreate(consproc, nil, STACK);
-
- threadcreate(keyproc, nil, STACK);
- threadcreate(lineproc, cook, STACK);
-
- raw = 0;
-
- b = p = e = nil;
-
- qcons.h = nil;
- qcons.t = &qcons.h;
- qkbd.h = nil;
- qkbd.t = &qkbd.h;
-
- memset(a, 0, sizeof a);
-
- a[Areq].c = reqchan;
- a[Areq].v = &req;
- a[Areq].op = CHANRCV;
-
- a[Actl].c = ctlchan;
- a[Actl].v = &c;
- a[Actl].op = CHANRCV;
-
- a[Araw].c = rawchan;
- a[Araw].v = &r;
- a[Araw].op = CHANRCV;
-
- a[Aline].c = linechan;
- a[Aline].v = &s;
- a[Aline].op = CHANRCV;
-
- a[Akbd].c = kbdchan;
- a[Akbd].v = &s;
- a[Akbd].op = CHANRCV;
-
- a[Aend].op = CHANEND;
-
- for(;;){
- s = nil;
-
- a[Araw].op = (b == nil) ? CHANRCV : CHANNOP;
- a[Aline].op = (b == nil) ? CHANRCV : CHANNOP;
- a[Akbd].op = qkbd.h || !kbdopen ? CHANRCV : CHANNOP;
-
- switch(alt(a)){
- case Areq:
- fid = req->fid;
- if(req->ifcall.type == Tflush){
- Req **rr;
-
- fid = req->oldreq->fid;
- q = fid->qid.path == Qcons ? &qcons : &qkbd;
- for(rr = &q->h; *rr && *rr != req->oldreq; rr = &((*rr)->aux))
- ;
- if(*rr == req->oldreq){
- if((*rr = req->oldreq->aux) == nil)
- q->t = rr;
- req->oldreq->aux = nil;
- respond(req->oldreq, "interrupted");
- }
- respond(req, nil);
- } else if(req->ifcall.type == Tread){
- q = fid->qid.path == Qcons ? &qcons : &qkbd;
- req->aux = nil;
- *q->t = req;
- q->t = &req->aux;
- goto Havereq;
- } else
- respond(req, Efront);
- break;
-
- case Actl:
- switch(c){
- case Rawoff:
- case Rawon:
- if(raw = (c == Rawon)){
- while(s = nbrecvp(linechan))
- free(s);
- r = '\0';
- send(cook, &r);
- free(b);
- b = nil;
- }
- break;
- case Kbdflush:
- while(s = nbrecvp(kbdchan))
- free(s);
- break;
- }
- break;
-
- case Araw:
- if(raw || kbdopen){
- s = emalloc9p(UTFmax+1);
- s[runetochar(s, &r)] = 0;
- } else {
- nbsend(cook, &r);
- break;
- }
- /* no break */
-
- case Aline:
- b = s;
- p = s;
- e = s + strlen(s);
-
- Havereq:
- if(kbdopen){
- free(b);
- b = nil;
- break;
- }
- while(b && (req = qcons.h)){
- if((qcons.h = req->aux) == nil)
- qcons.t = &qcons.h;
- n = e - p;
- if(req->ifcall.count < n)
- n = req->ifcall.count;
- req->ofcall.count = n;
- memmove(req->ofcall.data, p, n);
- respond(req, nil);
- p += n;
- if(p >= e){
- free(b);
- b = nil;
- }
- }
- break;
-
- case Akbd:
- if(req = qkbd.h){
- if((qkbd.h = req->aux) == nil)
- qkbd.t = &qkbd.h;
- n = strlen(s) + 1;
- if(n > req->ifcall.count)
- respond(req, Eshort);
- else {
- req->ofcall.count = n;
- memmove(req->ofcall.data, s, n);
- respond(req, nil);
- }
- }
- free(s);
- break;
- }
- }
-}
-
-/*
- * Keyboard layout maps
- */
-
-Rune*
-kbmapent(int t, int sc)
-{
- if(sc < 0 || sc >= Nscan)
- return nil;
- switch(t){
- default:
- return nil;
- case 0:
- return &kbtab[sc];
- case 1:
- return &kbtabshift[sc];
- case 2:
- return &kbtabesc1[sc];
- case 3:
- return &kbtabaltgr[sc];
- case 4:
- return &kbtabctl[sc];
- }
-}
-
-void
-kbmapread(Req *req)
-{
- char tmp[3*12+1];
- int t, sc, off, n;
- Rune *rp;
-
- off = req->ifcall.offset/(sizeof(tmp)-1);
- t = off/Nscan;
- sc = off%Nscan;
- if(rp = kbmapent(t, sc))
- sprint(tmp, "%11d %11d %11d\n", t, sc, *rp);
- else
- *tmp = 0;
- n = strlen(tmp);
- if(req->ifcall.count < n)
- n = req->ifcall.count;
- req->ofcall.count = n;
- memmove(req->ofcall.data, tmp, n);
- respond(req, nil);
-}
-
-void
-kbmapwrite(Req *req)
-{
- char line[100], *lp, *b;
- Rune r, *rp;
- int sc, t, l;
- Fid *f;
-
- f = req->fid;
- b = req->ifcall.data;
- l = req->ifcall.count;
- lp = line;
- if(f->aux){
- strcpy(line, f->aux);
- lp = line+strlen(line);
- free(f->aux);
- f->aux = nil;
- }
- while(--l >= 0) {
- *lp++ = *b++;
- if(lp[-1] == '\n' || lp == &line[sizeof(line)-1]) {
- *lp = 0;
- if(*line == 0){
- Badarg:
- respond(req, Ebadarg);
- return;
- }
- if(*line == '\n' || *line == '#'){
- lp = line;
- continue;
- }
- lp = line;
- while(*lp == ' ' || *lp == '\t')
- lp++;
- t = strtoul(line, &lp, 0);
- sc = strtoul(lp, &lp, 0);
- while(*lp == ' ' || *lp == '\t')
- lp++;
- if((rp = kbmapent(t, sc)) == nil)
- goto Badarg;
- r = 0;
- if(*lp == '\'' && lp[1])
- chartorune(&r, lp+1);
- else if(*lp == '^' && lp[1]){
- chartorune(&r, lp+1);
- if(0x40 <= r && r < 0x60)
- r -= 0x40;
- else
- goto Badarg;
- }else if(*lp == 'M' && ('1' <= lp[1] && lp[1] <= '5'))
- r = 0xF900+lp[1]-'0';
- else if(*lp>='0' && *lp<='9') /* includes 0x... */
- r = strtoul(lp, &lp, 0);
- else
- goto Badarg;
- *rp = r;
- lp = line;
- }
- }
- if(lp != line){
- l = lp-line;
- f->aux = lp = emalloc9p(l+1);
- memmove(lp, line, l);
- lp[l] = 0;
- }
- req->ofcall.count = req->ifcall.count;
- respond(req, nil);
-}
-
-/*
- * Filesystem
- */
-
-static char*
-getauser(void)
-{
- static char user[64];
- int fd;
- int n;
-
- if(*user)
- return user;
- if((fd = open("/dev/user", OREAD)) < 0)
- strcpy(user, "none");
- else {
- n = read(fd, user, (sizeof user)-1);
- close(fd);
- if(n < 0)
- strcpy(user, "none");
- else
- user[n] = 0;
- }
- return user;
-}
-
-static int
-fillstat(ulong qid, Dir *d)
-{
- struct Qtab *t;
-
- memset(d, 0, sizeof *d);
- d->uid = getauser();
- d->gid = getauser();
- d->muid = "";
- d->qid = (Qid){qid, 0, 0};
- d->atime = time(0);
- t = qtab + qid;
- d->name = t->name;
- d->qid.type = t->type;
- d->mode = t->mode;
- return 1;
-}
-
-static void
-fsattach(Req *r)
-{
- char *spec;
-
- spec = r->ifcall.aname;
- if(spec && spec[0]){
- respond(r, Ebadspec);
- return;
- }
- r->fid->qid = (Qid){Qroot, 0, QTDIR};
- r->ofcall.qid = r->fid->qid;
- respond(r, nil);
-}
-
-static void
-fsstat(Req *r)
-{
- fillstat((ulong)r->fid->qid.path, &r->d);
- r->d.name = estrdup9p(r->d.name);
- r->d.uid = estrdup9p(r->d.uid);
- r->d.gid = estrdup9p(r->d.gid);
- r->d.muid = estrdup9p(r->d.muid);
- respond(r, nil);
-}
-
-static char*
-fswalk1(Fid *fid, char *name, Qid *qid)
-{
- int i;
- ulong path;
-
- path = fid->qid.path;
- switch(path){
- case Qroot:
- if (strcmp(name, "..") == 0) {
- *qid = (Qid){Qroot, 0, QTDIR};
- fid->qid = *qid;
- return nil;
- }
- for(i = fid->qid.path; i<Nqid; i++){
- if(strcmp(name, qtab[i].name) != 0)
- continue;
- *qid = (Qid){i, 0, 0};
- fid->qid = *qid;
- return nil;
- }
- return Enonexist;
-
- default:
- return Ewalk;
- }
-}
-
-static void
-fsopen(Req *r)
-{
- Fid *f;
- static int need[4] = { 4, 2, 6, 1 };
- struct Qtab *t;
- int n;
-
- f = r->fid;
- t = qtab + f->qid.path;
- n = need[r->ifcall.mode & 3]<<6;
- if((n & t->mode) != n)
- respond(r, Eperm);
- else{
- f->aux = nil;
- switch((ulong)f->qid.path){
- case Qkbd:
- if(kbdopen){
- respond(r, Einuse);
- return;
- }
- kbdopen++;
- sendul(ctlchan, Kbdflush);
- break;
- case Qcons:
- consopen++;
- break;
- case Qconsctl:
- consctlopen++;
- break;
- }
- respond(r, nil);
- }
-}
-
-static int
-readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
-{
- int i, m, n;
- long pos;
- Dir d;
-
- n = 0;
- pos = 0;
- for (i = 1; i < Nqid; i++){
- fillstat(i, &d);
- m = convD2M(&d, &buf[n], blen-n);
- if(off <= pos){
- if(m <= BIT16SZ || m > cnt)
- break;
- n += m;
- cnt -= m;
- }
- pos += m;
- }
- return n;
-}
-
-static void
-fsread(Req *r)
-{
- Fid *f;
-
- f = r->fid;
- switch((ulong)f->qid.path){
- default:
- respond(r, Efront);
- return;
-
- case Qroot:
- r->ofcall.count = readtopdir(f, (void*)r->ofcall.data, r->ifcall.offset,
- r->ifcall.count, r->ifcall.count);
- break;
-
- case Qkbd:
- case Qcons:
- sendp(reqchan, r);
- return;
-
- case Qkbmap:
- kbmapread(r);
- return;
- }
- respond(r, nil);
-}
-
-static void
-fswrite(Req *r)
-{
- Fid *f;
- char *p;
- int n, i;
-
- f = r->fid;
- switch((ulong)f->qid.path){
- default:
- respond(r, Efront);
- return;
-
- case Qcons:
- n = r->ifcall.count;
- if(write(1, r->ifcall.data, n) != n){
- responderror(r);
- return;
- }
- r->ofcall.count = n;
- break;
-
- case Qconsctl:
- p = r->ifcall.data;
- n = r->ifcall.count;
- if(n >= 5 && memcmp(p, "rawon", 5) == 0)
- sendul(ctlchan, Rawon);
- else if(n >= 6 && memcmp(p, "rawoff", 6) == 0)
- sendul(ctlchan, Rawoff);
- else {
- respond(r, Ebadarg);
- return;
- }
- r->ofcall.count = n;
- break;
-
- case Qkbin:
- if(f->aux == nil){
- f->aux = emalloc9p(sizeof(Scan));
- memset(f->aux, 0, sizeof(Scan));
- }
- for(i=0; i<r->ifcall.count; i++)
- kbdputsc((Scan*)f->aux, (uchar)r->ifcall.data[i]);
- r->ofcall.count = i;
- break;
-
- case Qkbmap:
- kbmapwrite(r);
- return;
-
- }
- respond(r, nil);
-}
-
-static void
-fsflush(Req *r)
-{
- switch((ulong)r->oldreq->fid->qid.path) {
- case Qkbd:
- case Qcons:
- sendp(reqchan, r);
- return;
- }
- respond(r, nil);
-}
-
-static void
-fsdestroyfid(Fid *f)
-{
- void *p;
-
- if(f->omode != -1)
- switch((ulong)f->qid.path){
- case Qkbin:
- case Qkbmap:
- if(p = f->aux){
- f->aux = nil;
- free(p);
- }
- break;
- case Qkbd:
- kbdopen--;
- break;
- case Qcons:
- consopen--;
- break;
- case Qconsctl:
- if(--consctlopen == 0)
- sendul(ctlchan, Rawoff);
- break;
- }
-}
-
-static void
-fsend(Srv*)
-{
- threadexitsall(nil);
-}
-
-Srv fs = {
- .attach= fsattach,
- .walk1= fswalk1,
- .open= fsopen,
- .read= fsread,
- .write= fswrite,
- .stat= fsstat,
- .flush= fsflush,
- .destroyfid= fsdestroyfid,
- .end= fsend,
-};
-
-void
-reboot(void)
-{
- int fd;
-
- if(debug)
- return;
-
- if((fd = open("/dev/reboot", OWRITE)) < 0){
- fprint(2, "can't open /dev/reboot: %r\n");
- return;
- }
- fprint(fd, "reboot\n");
- close(fd);
-}
-
-void
-elevate(void)
-{
- char buf[128];
- Dir *d, nd;
- int fd;
-
- if(debug)
- return;
-
- snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
- if((fd = open(buf, OWRITE)) < 0){
- fprint(2, "can't open %s: %r\n", buf);
- return;
- }
-
- /* get higher than normal priority */
- fprint(fd, "pri 16\n");
-
- /* always present in physical memory */
- fprint(fd, "noswap\n");
-
- /* dont let anybody kill us */
- if(d = dirfstat(fd)){
- nulldir(&nd);
- nd.mode = d->mode & ~0222;
- dirfwstat(fd, &nd);
- free(d);
- }
-
- close(fd);
-
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: %s [ -dD ] [ -s srv ] [ -m mntpnt ] [ file ]\n", argv0);
- exits("usage");
-}
-
-void
-threadmain(int argc, char** argv)
-{
- char *mtpt = "/dev";
- char *srv = nil;
-
- consfd = -1;
-
- ARGBEGIN{
- case 'd':
- debug++;
- break;
- case 'D':
- chatty9p++;
- break;
- case 's':
- srv = EARGF(usage());
- break;
- case 'm':
- mtpt = EARGF(usage());
- break;
- default:
- usage();
- }ARGEND
-
- if((scanfd = open("/dev/scancode", OREAD)) < 0)
- fprint(2, "%s: warning: can't open /dev/scancode: %r\n", argv0);
- if((ledsfd = open("/dev/leds", OWRITE)) < 0)
- fprint(2, "%s: warning: can't open /dev/leds: %r\n", argv0);
-
- if(*argv)
- if((consfd = open(*argv, OREAD)) < 0)
- fprint(2, "%s: warning: can't open %s: %r\n", argv0, *argv);
-
- keychan = chancreate(sizeof(Key), 8);
- reqchan = chancreate(sizeof(Req*), 0);
- ctlchan = chancreate(sizeof(int), 0);
- rawchan = chancreate(sizeof(Rune), 32);
- linechan = chancreate(sizeof(char*), 16);
- kbdchan = chancreate(sizeof(char*), 16);
-
- if(!(keychan && reqchan && ctlchan && rawchan && linechan && kbdchan))
- sysfatal("allocating chans");
-
- elevate();
- procrfork(ctlproc, nil, STACK, RFNAMEG|RFNOTEG);
- threadpostmountsrv(&fs, srv, mtpt, MBEFORE);
-}
--- /dev/null
+++ b/sys/src/cmd/aux/kbdfs/kbdfs.c
@@ -1,0 +1,1279 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <fcall.h>
+#include <thread.h>
+#include <keyboard.h>
+#include <9p.h>
+
+enum {
+ Nscan= 128,
+
+ Qroot= 0,
+ Qkbd,
+ Qkbin,
+ Qkbmap,
+ Qcons,
+ Qconsctl,
+ Nqid,
+
+ Rawon= 0,
+ Rawoff,
+ Kbdflush,
+
+ STACK = 8*1024,
+};
+
+typedef struct Key Key;
+typedef struct Scan Scan;
+
+struct Key {
+ int down;
+ int c;
+ Rune r;
+ Rune b;
+};
+
+struct Scan {
+ int esc1;
+ int esc2;
+ int caps;
+ int num;
+ int shift;
+ int ctl;
+ int alt;
+ int altgr;
+ int leds;
+};
+
+struct Qtab {
+ char *name;
+ int mode;
+ int type;
+} qtab[Nqid] = {
+ "/",
+ DMDIR|0500,
+ QTDIR,
+
+ "kbd",
+ 0600,
+ 0,
+
+ "kbin",
+ 0200,
+ 0,
+
+ "kbmap",
+ 0600,
+ 0,
+
+ "cons",
+ 0600,
+ 0,
+
+ "consctl",
+ 0600,
+ 0,
+};
+
+char Eshort[] = "read count too small";
+char Ebadarg[] = "invalid argument";
+char Eperm[] = "permission denied";
+char Einuse[] = "file in use";
+char Enonexist[] = "file does not exist";
+char Ebadspec[] = "bad attach specifier";
+char Ewalk[] = "walk in non directory";
+char Efront[] = "the front fell off";
+
+int scanfd;
+int ledsfd;
+int consfd;
+
+int kbdopen;
+int consopen;
+int consctlopen;
+
+int debug;
+
+Channel *keychan; /* Key */
+
+Channel *reqchan; /* Req* */
+Channel *ctlchan; /* int */
+
+Channel *rawchan; /* Rune */
+Channel *runechan; /* Rune */
+Channel *linechan; /* char * */
+Channel *kbdchan; /* char* */
+
+/*
+ * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
+ * A 'standard' keyboard doesn't produce anything above 0x58.
+ */
+Rune kbtab[Nscan] =
+{
+[0x00] 0, 0x1b, '1', '2', '3', '4', '5', '6',
+[0x08] '7', '8', '9', '0', '-', '=', '\b', '\t',
+[0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+[0x18] 'o', 'p', '[', ']', '\n', Kctl, 'a', 's',
+[0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+[0x28] '\'', '`', Kshift, '\\', 'z', 'x', 'c', 'v',
+[0x30] 'b', 'n', 'm', ',', '.', '/', Kshift, '*',
+[0x38] Kalt, ' ', Kctl, KF|1, KF|2, KF|3, KF|4, KF|5,
+[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Knum, Kscroll, '7',
+[0x48] '8', '9', '-', '4', '5', '6', '+', '1',
+[0x50] '2', '3', '0', '.', 0, 0, 0, KF|11,
+[0x58] KF|12, 0, 0, 0, 0, 0, 0, 0,
+[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x78] 0, Kdown, 0, Kup, 0, 0, 0, 0,
+};
+
+Rune kbtabshift[Nscan] =
+{
+[0x00] 0, 0x1b, '!', '@', '#', '$', '%', '^',
+[0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
+[0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+[0x18] 'O', 'P', '{', '}', '\n', Kctl, 'A', 'S',
+[0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+[0x28] '"', '~', Kshift, '|', 'Z', 'X', 'C', 'V',
+[0x30] 'B', 'N', 'M', '<', '>', '?', Kshift, '*',
+[0x38] Kalt, ' ', Kctl, KF|1, KF|2, KF|3, KF|4, KF|5,
+[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Knum, Kscroll, '7',
+[0x48] '8', '9', '-', '4', '5', '6', '+', '1',
+[0x50] '2', '3', '0', '.', 0, 0, 0, KF|11,
+[0x58] KF|12, 0, 0, 0, 0, 0, 0, 0,
+[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x78] 0, Kup, 0, Kup, 0, 0, 0, 0,
+};
+
+Rune kbtabesc1[Nscan] =
+{
+[0x00] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x08] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x10] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x18] 0, 0, 0, 0, '\n', Kctl, 0, 0,
+[0x20] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x28] 0, 0, Kshift, 0, 0, 0, 0, 0,
+[0x30] 0, 0, 0, 0, 0, '/', 0, Kprint,
+[0x38] Kaltgr, 0, 0, 0, 0, 0, 0, 0,
+[0x40] 0, 0, 0, 0, 0, 0, Kbreak, Khome,
+[0x48] Kup, Kpgup, 0, Kleft, 0, Kright, 0, Kend,
+[0x50] Kdown, Kpgdown, Kins, Kdel, 0, 0, 0, 0,
+[0x58] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x78] 0, Kup, 0, 0, 0, 0, 0, 0,
+};
+
+Rune kbtabaltgr[Nscan] =
+{
+[0x00] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x08] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x10] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x18] 0, 0, 0, 0, '\n', Kctl, 0, 0,
+[0x20] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x28] 0, 0, Kshift, 0, 0, 0, 0, 0,
+[0x30] 0, 0, 0, 0, 0, '/', 0, Kprint,
+[0x38] Kaltgr, 0, 0, 0, 0, 0, 0, 0,
+[0x40] 0, 0, 0, 0, 0, 0, Kbreak, Khome,
+[0x48] Kup, Kpgup, 0, Kleft, 0, Kright, 0, Kend,
+[0x50] Kdown, Kpgdown, Kins, Kdel, 0, 0, 0, 0,
+[0x58] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x78] 0, Kup, 0, 0, 0, 0, 0, 0,
+};
+
+Rune kbtabctl[Nscan] =
+{
+[0x00] 0, '', '', '', '', '', '', '',
+[0x08] '', '', '', '', ' ', '', '\b', '\t',
+[0x10] '', '', '', '', '', '', '', '\t',
+[0x18] '', '', '', '', '\n', Kctl, '', '',
+[0x20] '', '', '', '\b', '\n', '', '', '',
+[0x28] '', 0, Kshift, '', '', '', '', '',
+[0x30] '', '', ' ', '', '', '', Kshift, '\n',
+[0x38] Kalt, 0, Kctl, '', '', '', '', '',
+[0x40] '', '', '', ' ', '', '', '', '',
+[0x48] '', '', ' ', '', '', '', '', '',
+[0x50] '', '', '', '', 0, 0, 0, '',
+[0x58] '', 0, 0, 0, 0, 0, 0, 0,
+[0x60] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x68] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
+[0x78] 0, '', 0, '\b', 0, 0, 0, 0,
+};
+
+void reboot(void);
+
+/*
+ * Scan code processing
+ */
+void
+kbdputsc(Scan *scan, int c)
+{
+ Key key;
+
+ /*
+ * e0's is the first of a 2 character sequence, e1 the first
+ * of a 3 character sequence (on the safari)
+ */
+ if(c == 0xe0){
+ scan->esc1 = 1;
+ return;
+ } else if(c == 0xe1){
+ scan->esc2 = 2;
+ return;
+ }
+
+ key.down = (c & 0x80) == 0;
+ key.c = c & 0x7f;
+
+ if(key.c >= Nscan)
+ return;
+
+ if(scan->esc1)
+ key.r = kbtabesc1[key.c];
+ else if(scan->shift)
+ key.r = kbtabshift[key.c];
+ else if(scan->altgr)
+ key.r = kbtabaltgr[key.c];
+ else if(scan->ctl)
+ key.r = kbtabctl[key.c];
+ else
+ key.r = kbtab[key.c];
+
+ switch(key.r){
+ case Spec|0x60:
+ key.r = Kshift;
+ break;
+ case Spec|0x62:
+ key.r = Kctl;
+ break;
+ case Spec|0x63:
+ key.r = Kalt;
+ break;
+ }
+
+ if(scan->esc1)
+ key.b = key.r;
+ else
+ key.b = kbtab[key.c];
+
+ if(scan->caps && key.r<='z' && key.r>='a')
+ key.r += 'A' - 'a';
+
+ if(scan->ctl && scan->alt && key.r == Kdel)
+ reboot();
+
+ send(keychan, &key);
+
+ if(scan->esc1)
+ scan->esc1 = 0;
+ else if(scan->esc2)
+ scan->esc2--;
+
+ switch(key.r){
+ case Kshift:
+ scan->shift = key.down;
+ break;
+ case Kctl:
+ scan->ctl = key.down;
+ break;
+ case Kaltgr:
+ scan->altgr = key.down;
+ break;
+ case Kalt:
+ scan->alt = key.down;
+ break;
+ case Knum:
+ scan->num ^= key.down;
+ break;
+ case Kcaps:
+ scan->caps ^= key.down;
+ break;
+ }
+}
+
+void
+setleds(Scan *scan, int leds)
+{
+ char buf[8];
+
+ if(ledsfd < 0 || scan->leds == leds)
+ return;
+ leds &= 7;
+ snprint(buf, sizeof(buf), "%d", leds);
+ pwrite(ledsfd, buf, strlen(buf), 0);
+ scan->leds = leds;
+}
+
+/*
+ * Read scan codes from scanfd
+ */
+void
+scanproc(void *)
+{
+ uchar buf[64];
+ Scan scan;
+ int i, n;
+
+ threadsetname("scanproc");
+
+ memset(&scan, 0, sizeof scan);
+ while((n = read(scanfd, buf, sizeof buf)) > 0){
+ for(i=0; i<n; i++)
+ kbdputsc(&scan, buf[i]);
+ setleds(&scan, (scan.num<<1) | (scan.caps<<2));
+ }
+}
+
+char*
+utfconv(Rune *r, int n)
+{
+ char *s, *p;
+ int l;
+
+ l = runenlen(r, n) + 1;
+ s = emalloc9p(l);
+ for(p = s; n > 0; r++, n--)
+ p += runetochar(p, r);
+ *p = 0;
+ return s;
+}
+
+/*
+ * Read key events from keychan and produce characters to
+ * rawchan and keystate in kbdchan. this way here is only
+ * one global keystate even if multiple keyboards are used.
+ */
+void
+keyproc(void *)
+{
+ Rune rb[Nscan*2+1];
+ int cb[Nscan];
+ Key key;
+ int i, nb;
+ char *s;
+
+ threadsetname("keyproc");
+
+ nb = 0;
+ while(recv(keychan, &key) > 0){
+ if(key.down && key.r)
+ nbsend(rawchan, &key.r);
+
+ rb[0] = 0;
+ for(i=0; i<nb && cb[i] != key.c; i++)
+ ;
+ if(!key.down){
+ while(i < nb && cb[i] == key.c){
+ memmove(cb+i, cb+i+1, (nb-i+1) * sizeof(cb[0]));
+ memmove(rb+i+1, rb+i+2, (nb-i+1) * sizeof(rb[0]));
+ nb--;
+ rb[0] = 'K';
+ }
+ } else if(i == nb && nb < nelem(cb) && key.b){
+ cb[nb] = key.c;
+ rb[nb+1] = key.b;
+ nb++;
+ if(nb < nelem(cb) && key.r && key.b != key.r){
+ cb[nb] = key.c;
+ rb[nb+1] = key.r;
+ nb++;
+ }
+ rb[0] = 'k';
+ }
+ if(rb[0]){
+ s = utfconv(rb, nb+1);
+ if(nbsendp(kbdchan, s) <= 0)
+ free(s);
+ }
+ }
+}
+
+/*
+ * Read characters from consfd (serial console)
+ */
+void
+consproc(void *)
+{
+ char *p, *e, *x, buf[64];
+ int n, cr;
+ Rune r;
+
+ threadsetname("consproc");
+
+ cr = 0;
+ p = buf;
+ e = buf + sizeof(buf);
+ while((n = read(consfd, p, e - p)) > 0){
+ x = buf + n;
+ while(p < x && fullrune(p, x - p)){
+ p += chartorune(&r, p);
+ if(r){
+ if(r == '\n' && cr){
+ cr = 0;
+ continue;
+ }
+ if(cr = (r == '\r'))
+ r = '\n';
+ send(runechan, &r);
+ }
+ }
+ n = x - p;
+ memmove(buf, p, n);
+ p = buf + n;
+ }
+}
+
+static int
+nextrune(Channel *ch, Rune *r)
+{
+ while(recv(ch, r) > 0){
+ switch(*r){
+ case 0:
+ case Kcaps:
+ case Knum:
+ case Kshift:
+ case Kctl:
+ case Kaltgr:
+ /* ignore these special keys */
+ continue;
+
+ case Kalt:
+ /* latin escape! */
+ return 1;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * Read runes from rawchan, possibly compose special characters
+ * and output the new runes to runechan
+ */
+void
+runeproc(void *)
+{
+ static struct {
+ char *ld; /* must be seen before using this conversion */
+ char *si; /* options for last input characters */
+ Rune *so; /* the corresponding Rune for each si entry */
+ } tab[] = {
+#include "latin1.h"
+ };
+ Rune r, rr;
+ int i, j;
+
+ threadsetname("runeproc");
+
+ while((i = nextrune(rawchan, &r)) >= 0){
+ if(i == 0){
+Forward:
+ send(runechan, &r);
+ continue;
+ }
+
+ /* latin sequence */
+ if(nextrune(rawchan, &r))
+ continue;
+
+ if(r == 'X'){
+ r = 0;
+ for(i = 0; i<4; i++){
+ if(nextrune(rawchan, &rr))
+ break;
+ r <<= 4;
+ if(rr >= '0' && rr <= '9')
+ r |= (rr - '0');
+ else if(rr >= 'a' && rr <= 'f')
+ r |= 10 + (rr - 'a');
+ else if(rr >= 'A' && rr <= 'F')
+ r |= 10 + (rr - 'A');
+ else
+ break;
+ }
+ if(i == 4 && r > 0)
+ goto Forward;
+ } else {
+ if(nextrune(rawchan, &rr))
+ continue;
+ for(i = 0; i<nelem(tab); i++){
+ if(tab[i].ld[0] != r)
+ continue;
+ if(tab[i].ld[1] == 0)
+ break;
+ if(tab[i].ld[1] == rr){
+ nextrune(rawchan, &rr);
+ break;
+ }
+ }
+ if(i == nelem(tab) || rr == 0)
+ continue;
+ for(j = 0; tab[i].si[j]; j++){
+ if(tab[i].si[j] != rr)
+ continue;
+ r = tab[i].so[j];
+ goto Forward;
+ }
+ }
+ }
+}
+
+/*
+ * Cook lines for cons
+ */
+void
+lineproc(void *aux)
+{
+ Rune rb[256], r;
+ Channel *cook;
+ int nr, done;
+
+ cook = aux;
+
+ threadsetname("lineproc");
+
+ for(;;){
+ nr = 0;
+ done = 0;
+ do {
+ recv(cook, &r);
+ switch(r){
+ case '\0': /* flush */
+ nr = 0;
+ continue;
+ case '\b': /* backspace */
+ case Knack: /* ^U */
+ while(nr > 0){
+ nr--;
+ fprint(1, "\b");
+ if(r == '\b')
+ break;
+ }
+ continue;
+ case Keof: /* ^D */
+ done = 1;
+ break;
+ case '\n':
+ done = 1;
+ /* no break */
+ default:
+ rb[nr++] = r;
+ fprint(1, "%C", r);
+ }
+ } while(!done && nr < nelem(rb));
+ sendp(linechan, utfconv(rb, nr));
+ }
+}
+
+/*
+ * Queue reads to cons and kbd, flushing and
+ * relay data between 9p and rawchan / kbdchan.
+ */
+void
+ctlproc(void *)
+{
+ struct {
+ Req *h;
+ Req **t;
+ } qcons, qkbd, *q;
+ enum { Areq, Actl, Arune, Aline, Akbd, Aend };
+ Alt a[Aend+1];
+ Req *req;
+ Fid *fid;
+ Rune r;
+ char *s, *b, *p, *e;
+ int c, n, raw;
+ Channel *cook;
+
+ threadsetname("ctlproc");
+
+ cook = chancreate(sizeof(Rune), 0);
+
+ if(scanfd >= 0)
+ proccreate(scanproc, nil, STACK); /* scanfd -> keychan */
+ if(consfd >= 0)
+ proccreate(consproc, nil, STACK); /* consfd -> runechan */
+
+ threadcreate(keyproc, nil, STACK); /* keychan -> rawchan, kbdchan */
+ threadcreate(runeproc, nil, STACK); /* rawchan -> runechan */
+ threadcreate(lineproc, cook, STACK); /* cook -> linechan */
+
+ raw = 0;
+
+ b = p = e = nil;
+
+ qcons.h = nil;
+ qcons.t = &qcons.h;
+ qkbd.h = nil;
+ qkbd.t = &qkbd.h;
+
+ memset(a, 0, sizeof a);
+
+ a[Areq].c = reqchan;
+ a[Areq].v = &req;
+ a[Areq].op = CHANRCV;
+
+ a[Actl].c = ctlchan;
+ a[Actl].v = &c;
+ a[Actl].op = CHANRCV;
+
+ a[Arune].c = runechan;
+ a[Arune].v = &r;
+ a[Arune].op = CHANRCV;
+
+ a[Aline].c = linechan;
+ a[Aline].v = &s;
+ a[Aline].op = CHANRCV;
+
+ a[Akbd].c = kbdchan;
+ a[Akbd].v = &s;
+ a[Akbd].op = CHANRCV;
+
+ a[Aend].op = CHANEND;
+
+ for(;;){
+ s = nil;
+
+ if(kbdopen){
+ a[Arune].op = qkbd.h ? CHANRCV : CHANNOP;
+ a[Akbd].op = qkbd.h ? CHANRCV : CHANNOP;
+ a[Aline].op = CHANNOP;
+ }else{
+ a[Arune].op = (b == nil) ? CHANRCV : CHANNOP;
+ a[Akbd].op = CHANRCV;
+ a[Aline].op = (b == nil) ? CHANRCV : CHANNOP;
+ }
+
+ switch(alt(a)){
+ case Areq:
+ fid = req->fid;
+ if(req->ifcall.type == Tflush){
+ Req **rr;
+
+ fid = req->oldreq->fid;
+ q = fid->qid.path == Qcons ? &qcons : &qkbd;
+ for(rr = &q->h; *rr && *rr != req->oldreq; rr = &((*rr)->aux))
+ ;
+ if(*rr == req->oldreq){
+ if((*rr = req->oldreq->aux) == nil)
+ q->t = rr;
+ req->oldreq->aux = nil;
+ respond(req->oldreq, "interrupted");
+ }
+ respond(req, nil);
+ } else if(req->ifcall.type == Tread){
+ q = fid->qid.path == Qcons ? &qcons : &qkbd;
+ req->aux = nil;
+ *q->t = req;
+ q->t = &req->aux;
+ goto Havereq;
+ } else
+ respond(req, Efront);
+ break;
+
+ case Actl:
+ switch(c){
+ case Rawoff:
+ case Rawon:
+ if(raw = (c == Rawon)){
+ while(s = nbrecvp(linechan))
+ free(s);
+ r = '\0';
+ send(cook, &r);
+ free(b);
+ b = nil;
+ }
+ break;
+ case Kbdflush:
+ while(s = nbrecvp(kbdchan))
+ free(s);
+ break;
+ }
+ break;
+
+ case Arune:
+ if(kbdopen){
+ s = emalloc9p(UTFmax+2);
+ s[0] = 'c';
+ s[1+runetochar(s+1, &r)] = 0;
+ goto Havekbd;
+ }
+
+ if(raw){
+ s = emalloc9p(UTFmax+1);
+ s[runetochar(s, &r)] = 0;
+ } else {
+ nbsend(cook, &r);
+ break;
+ }
+ /* no break */
+
+ case Aline:
+ b = s;
+ p = s;
+ e = s + strlen(s);
+
+ Havereq:
+ while(b && (req = qcons.h)){
+ if((qcons.h = req->aux) == nil)
+ qcons.t = &qcons.h;
+ n = e - p;
+ if(req->ifcall.count < n)
+ n = req->ifcall.count;
+ req->ofcall.count = n;
+ memmove(req->ofcall.data, p, n);
+ respond(req, nil);
+ p += n;
+ if(p >= e){
+ free(b);
+ b = nil;
+ }
+ }
+ break;
+
+ case Akbd:
+ Havekbd:
+ if(req = qkbd.h){
+ if((qkbd.h = req->aux) == nil)
+ qkbd.t = &qkbd.h;
+ n = strlen(s) + 1;
+ if(n > req->ifcall.count)
+ respond(req, Eshort);
+ else {
+ req->ofcall.count = n;
+ memmove(req->ofcall.data, s, n);
+ respond(req, nil);
+ }
+ }
+ free(s);
+ break;
+ }
+ }
+}
+
+/*
+ * Keyboard layout maps
+ */
+
+Rune*
+kbmapent(int t, int sc)
+{
+ if(sc < 0 || sc >= Nscan)
+ return nil;
+ switch(t){
+ default:
+ return nil;
+ case 0:
+ return &kbtab[sc];
+ case 1:
+ return &kbtabshift[sc];
+ case 2:
+ return &kbtabesc1[sc];
+ case 3:
+ return &kbtabaltgr[sc];
+ case 4:
+ return &kbtabctl[sc];
+ }
+}
+
+void
+kbmapread(Req *req)
+{
+ char tmp[3*12+1];
+ int t, sc, off, n;
+ Rune *rp;
+
+ off = req->ifcall.offset/(sizeof(tmp)-1);
+ t = off/Nscan;
+ sc = off%Nscan;
+ if(rp = kbmapent(t, sc))
+ sprint(tmp, "%11d %11d %11d\n", t, sc, *rp);
+ else
+ *tmp = 0;
+ n = strlen(tmp);
+ if(req->ifcall.count < n)
+ n = req->ifcall.count;
+ req->ofcall.count = n;
+ memmove(req->ofcall.data, tmp, n);
+ respond(req, nil);
+}
+
+void
+kbmapwrite(Req *req)
+{
+ char line[100], *lp, *b;
+ Rune r, *rp;
+ int sc, t, l;
+ Fid *f;
+
+ f = req->fid;
+ b = req->ifcall.data;
+ l = req->ifcall.count;
+ lp = line;
+ if(f->aux){
+ strcpy(line, f->aux);
+ lp = line+strlen(line);
+ free(f->aux);
+ f->aux = nil;
+ }
+ while(--l >= 0) {
+ *lp++ = *b++;
+ if(lp[-1] == '\n' || lp == &line[sizeof(line)-1]) {
+ *lp = 0;
+ if(*line == 0){
+ Badarg:
+ respond(req, Ebadarg);
+ return;
+ }
+ if(*line == '\n' || *line == '#'){
+ lp = line;
+ continue;
+ }
+ lp = line;
+ while(*lp == ' ' || *lp == '\t')
+ lp++;
+ t = strtoul(line, &lp, 0);
+ sc = strtoul(lp, &lp, 0);
+ while(*lp == ' ' || *lp == '\t')
+ lp++;
+ if((rp = kbmapent(t, sc)) == nil)
+ goto Badarg;
+ r = 0;
+ if(*lp == '\'' && lp[1])
+ chartorune(&r, lp+1);
+ else if(*lp == '^' && lp[1]){
+ chartorune(&r, lp+1);
+ if(0x40 <= r && r < 0x60)
+ r -= 0x40;
+ else
+ goto Badarg;
+ }else if(*lp == 'M' && ('1' <= lp[1] && lp[1] <= '5'))
+ r = 0xF900+lp[1]-'0';
+ else if(*lp>='0' && *lp<='9') /* includes 0x... */
+ r = strtoul(lp, &lp, 0);
+ else
+ goto Badarg;
+ *rp = r;
+ lp = line;
+ }
+ }
+ if(lp != line){
+ l = lp-line;
+ f->aux = lp = emalloc9p(l+1);
+ memmove(lp, line, l);
+ lp[l] = 0;
+ }
+ req->ofcall.count = req->ifcall.count;
+ respond(req, nil);
+}
+
+/*
+ * Filesystem
+ */
+
+static char*
+getauser(void)
+{
+ static char user[64];
+ int fd;
+ int n;
+
+ if(*user)
+ return user;
+ if((fd = open("/dev/user", OREAD)) < 0)
+ strcpy(user, "none");
+ else {
+ n = read(fd, user, (sizeof user)-1);
+ close(fd);
+ if(n < 0)
+ strcpy(user, "none");
+ else
+ user[n] = 0;
+ }
+ return user;
+}
+
+static int
+fillstat(ulong qid, Dir *d)
+{
+ struct Qtab *t;
+
+ memset(d, 0, sizeof *d);
+ d->uid = getauser();
+ d->gid = getauser();
+ d->muid = "";
+ d->qid = (Qid){qid, 0, 0};
+ d->atime = time(0);
+ t = qtab + qid;
+ d->name = t->name;
+ d->qid.type = t->type;
+ d->mode = t->mode;
+ return 1;
+}
+
+static void
+fsattach(Req *r)
+{
+ char *spec;
+
+ spec = r->ifcall.aname;
+ if(spec && spec[0]){
+ respond(r, Ebadspec);
+ return;
+ }
+ r->fid->qid = (Qid){Qroot, 0, QTDIR};
+ r->ofcall.qid = r->fid->qid;
+ respond(r, nil);
+}
+
+static void
+fsstat(Req *r)
+{
+ fillstat((ulong)r->fid->qid.path, &r->d);
+ r->d.name = estrdup9p(r->d.name);
+ r->d.uid = estrdup9p(r->d.uid);
+ r->d.gid = estrdup9p(r->d.gid);
+ r->d.muid = estrdup9p(r->d.muid);
+ respond(r, nil);
+}
+
+static char*
+fswalk1(Fid *fid, char *name, Qid *qid)
+{
+ int i;
+ ulong path;
+
+ path = fid->qid.path;
+ switch(path){
+ case Qroot:
+ if (strcmp(name, "..") == 0) {
+ *qid = (Qid){Qroot, 0, QTDIR};
+ fid->qid = *qid;
+ return nil;
+ }
+ for(i = fid->qid.path; i<Nqid; i++){
+ if(strcmp(name, qtab[i].name) != 0)
+ continue;
+ *qid = (Qid){i, 0, 0};
+ fid->qid = *qid;
+ return nil;
+ }
+ return Enonexist;
+
+ default:
+ return Ewalk;
+ }
+}
+
+static void
+fsopen(Req *r)
+{
+ Fid *f;
+ static int need[4] = { 4, 2, 6, 1 };
+ struct Qtab *t;
+ int n;
+
+ f = r->fid;
+ t = qtab + f->qid.path;
+ n = need[r->ifcall.mode & 3]<<6;
+ if((n & t->mode) != n)
+ respond(r, Eperm);
+ else{
+ f->aux = nil;
+ switch((ulong)f->qid.path){
+ case Qkbd:
+ if(kbdopen){
+ respond(r, Einuse);
+ return;
+ }
+ kbdopen++;
+ sendul(ctlchan, Kbdflush);
+ break;
+ case Qcons:
+ consopen++;
+ break;
+ case Qconsctl:
+ consctlopen++;
+ break;
+ }
+ respond(r, nil);
+ }
+}
+
+static int
+readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
+{
+ int i, m, n;
+ long pos;
+ Dir d;
+
+ n = 0;
+ pos = 0;
+ for (i = 1; i < Nqid; i++){
+ fillstat(i, &d);
+ m = convD2M(&d, &buf[n], blen-n);
+ if(off <= pos){
+ if(m <= BIT16SZ || m > cnt)
+ break;
+ n += m;
+ cnt -= m;
+ }
+ pos += m;
+ }
+ return n;
+}
+
+static void
+fsread(Req *r)
+{
+ Fid *f;
+
+ f = r->fid;
+ switch((ulong)f->qid.path){
+ default:
+ respond(r, Efront);
+ return;
+
+ case Qroot:
+ r->ofcall.count = readtopdir(f, (void*)r->ofcall.data, r->ifcall.offset,
+ r->ifcall.count, r->ifcall.count);
+ break;
+
+ case Qkbd:
+ case Qcons:
+ sendp(reqchan, r);
+ return;
+
+ case Qkbmap:
+ kbmapread(r);
+ return;
+ }
+ respond(r, nil);
+}
+
+static void
+fswrite(Req *r)
+{
+ Fid *f;
+ char *p;
+ int n, i;
+
+ f = r->fid;
+ switch((ulong)f->qid.path){
+ default:
+ respond(r, Efront);
+ return;
+
+ case Qcons:
+ n = r->ifcall.count;
+ if(write(1, r->ifcall.data, n) != n){
+ responderror(r);
+ return;
+ }
+ r->ofcall.count = n;
+ break;
+
+ case Qconsctl:
+ p = r->ifcall.data;
+ n = r->ifcall.count;
+ if(n >= 5 && memcmp(p, "rawon", 5) == 0)
+ sendul(ctlchan, Rawon);
+ else if(n >= 6 && memcmp(p, "rawoff", 6) == 0)
+ sendul(ctlchan, Rawoff);
+ else {
+ respond(r, Ebadarg);
+ return;
+ }
+ r->ofcall.count = n;
+ break;
+
+ case Qkbin:
+ if(f->aux == nil){
+ f->aux = emalloc9p(sizeof(Scan));
+ memset(f->aux, 0, sizeof(Scan));
+ }
+ for(i=0; i<r->ifcall.count; i++)
+ kbdputsc((Scan*)f->aux, (uchar)r->ifcall.data[i]);
+ r->ofcall.count = i;
+ break;
+
+ case Qkbmap:
+ kbmapwrite(r);
+ return;
+
+ }
+ respond(r, nil);
+}
+
+static void
+fsflush(Req *r)
+{
+ switch((ulong)r->oldreq->fid->qid.path) {
+ case Qkbd:
+ case Qcons:
+ sendp(reqchan, r);
+ return;
+ }
+ respond(r, nil);
+}
+
+static void
+fsdestroyfid(Fid *f)
+{
+ void *p;
+
+ if(f->omode != -1)
+ switch((ulong)f->qid.path){
+ case Qkbin:
+ case Qkbmap:
+ if(p = f->aux){
+ f->aux = nil;
+ free(p);
+ }
+ break;
+ case Qkbd:
+ kbdopen--;
+ break;
+ case Qcons:
+ consopen--;
+ break;
+ case Qconsctl:
+ if(--consctlopen == 0)
+ sendul(ctlchan, Rawoff);
+ break;
+ }
+}
+
+static void
+fsend(Srv*)
+{
+ threadexitsall(nil);
+}
+
+Srv fs = {
+ .attach= fsattach,
+ .walk1= fswalk1,
+ .open= fsopen,
+ .read= fsread,
+ .write= fswrite,
+ .stat= fsstat,
+ .flush= fsflush,
+ .destroyfid= fsdestroyfid,
+ .end= fsend,
+};
+
+void
+reboot(void)
+{
+ int fd;
+
+ if(debug)
+ return;
+
+ if((fd = open("/dev/reboot", OWRITE)) < 0){
+ fprint(2, "can't open /dev/reboot: %r\n");
+ return;
+ }
+ fprint(fd, "reboot\n");
+ close(fd);
+}
+
+void
+elevate(void)
+{
+ char buf[128];
+ Dir *d, nd;
+ int fd;
+
+ if(debug)
+ return;
+
+ snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
+ if((fd = open(buf, OWRITE)) < 0){
+ fprint(2, "can't open %s: %r\n", buf);
+ return;
+ }
+
+ /* get higher than normal priority */
+ fprint(fd, "pri 16\n");
+
+ /* always present in physical memory */
+ fprint(fd, "noswap\n");
+
+ /* dont let anybody kill us */
+ if(d = dirfstat(fd)){
+ nulldir(&nd);
+ nd.mode = d->mode & ~0222;
+ dirfwstat(fd, &nd);
+ free(d);
+ }
+
+ close(fd);
+
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [ -dD ] [ -s srv ] [ -m mntpnt ] [ file ]\n", argv0);
+ exits("usage");
+}
+
+void
+threadmain(int argc, char** argv)
+{
+ char *mtpt = "/dev";
+ char *srv = nil;
+
+ consfd = -1;
+
+ ARGBEGIN{
+ case 'd':
+ debug++;
+ break;
+ case 'D':
+ chatty9p++;
+ break;
+ case 's':
+ srv = EARGF(usage());
+ break;
+ case 'm':
+ mtpt = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if((scanfd = open("/dev/scancode", OREAD)) < 0)
+ fprint(2, "%s: warning: can't open /dev/scancode: %r\n", argv0);
+ if((ledsfd = open("/dev/leds", OWRITE)) < 0)
+ fprint(2, "%s: warning: can't open /dev/leds: %r\n", argv0);
+
+ if(*argv)
+ if((consfd = open(*argv, OREAD)) < 0)
+ fprint(2, "%s: warning: can't open %s: %r\n", argv0, *argv);
+
+ keychan = chancreate(sizeof(Key), 8);
+ reqchan = chancreate(sizeof(Req*), 0);
+ ctlchan = chancreate(sizeof(int), 0);
+ rawchan = chancreate(sizeof(Rune), 16);
+ runechan = chancreate(sizeof(Rune), 32);
+ linechan = chancreate(sizeof(char*), 16);
+ kbdchan = chancreate(sizeof(char*), 16);
+
+ if(!(keychan && reqchan && ctlchan && rawchan && runechan && linechan && kbdchan))
+ sysfatal("allocating chans");
+
+ elevate();
+ procrfork(ctlproc, nil, STACK, RFNAMEG|RFNOTEG);
+ threadpostmountsrv(&fs, srv, mtpt, MBEFORE);
+}
--- /dev/null
+++ b/sys/src/cmd/aux/kbdfs/mkfile
@@ -1,0 +1,16 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin/aux
+
+TARG=kbdfs
+OFILES=kbdfs.$O
+HFILES=latin1.h
+CLEANFILES=latin1.h mklatin.$cputype
+
+</sys/src/cmd/mkone
+
+mklatin.$cputype: mkfile.mklatin
+ @{objtype=$cputype mk -f $prereq $target}
+
+latin1.h: mklatin.$cputype /lib/keyboard
+ $prereq >$target
--- /dev/null
+++ b/sys/src/cmd/aux/kbdfs/mkfile.mklatin
@@ -1,0 +1,7 @@
+</$objtype/mkfile
+
+mklatin.$cputype: mklatin.$O
+ $LD $LDFLAGS -o $target $prereq
+
+</sys/src/cmd/mkone
+
--- /dev/null
+++ b/sys/src/cmd/aux/kbdfs/mklatin.c
@@ -1,0 +1,232 @@
+/*
+ * Parse /lib/keyboard to create latin1.h table for kernel.
+ * mklatinkbd -r prints an array of integers rather than a Rune string literal.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+
+int rflag;
+
+enum {
+ MAXLD = 2, /* latin1.c assumes this is 2 */
+};
+
+char *head = ""
+"/*\n"
+" * This is automatically generated by %s from /lib/keyboard\n"
+" * Edit /lib/keyboard instead.\n"
+" */\n";
+
+/*
+ * latin1.c assumes that strlen(ld) is at most 2.
+ * It also assumes that latintab[i].ld can be a prefix of latintab[j].ld
+ * only when j < i. We ensure this by sorting the output by prefix length.
+ * The so array is indexed by the character value.
+ */
+
+typedef struct Trie Trie;
+struct Trie {
+ int n; /* of characters r */
+ char seq[MAXLD+1];
+ Rune r[256];
+ Trie *link[256];
+};
+
+Trie *root;
+
+Trie*
+mktrie(char *seq)
+{
+ uchar *q;
+ Trie **tp;
+
+ if(root == nil) {
+ root = malloc(sizeof *root);
+ memset(root, 0, sizeof *root);
+ }
+
+ assert(seq[0] != '\0');
+
+ tp = &root;
+ for(q=(uchar*)seq; *(q+1) != '\0'; q++) {
+ tp = &(*tp)->link[*q];
+ if(*tp == nil) {
+ *tp = malloc(sizeof(**tp));
+ assert(*tp != nil);
+ memset(*tp, 0, sizeof(**tp));
+ strcpy((*tp)->seq, seq);
+ (*tp)->seq[q+1-(uchar*)seq] = '\0';
+ }
+ }
+
+ assert(*tp != nil);
+ return *tp;
+}
+
+/* add character sequence s meaning rune r */
+void
+insert(char *s, Rune r)
+{
+ uchar lastc;
+ int len;
+ Trie *t;
+
+ len = strlen(s);
+ lastc = (uchar)s[len-1];
+
+ t = mktrie(s);
+ if(t->r[lastc]) {
+ fprint(2, "warning: table duplicate: %s is %C and %C\n", s, t->r[lastc], r);
+ return;
+ }
+ t->r[lastc] = r;
+ t->n++;
+}
+
+void
+cprintchar(Biobuf *b, int c)
+{
+ /* print a byte c safe for a C string. */
+ switch(c) {
+ case '\'':
+ case '\"':
+ case '\\':
+ Bprint(b, "\\%c", c);
+ break;
+ case '\t':
+ Bprint(b, "\\t");
+ break;
+ default:
+ if(isascii(c) && isprint(c))
+ Bprint(b, "%c", c);
+ else
+ Bprint(b, "\\x%.2x", c);
+ break;
+ }
+}
+
+void
+cprints(Biobuf *b, char *p)
+{
+ while(*p != '\0')
+ cprintchar(b, *p++);
+}
+
+
+void
+printtrie(Biobuf *b, Trie *t)
+{
+ int i;
+
+ for(i=0; i<256; i++)
+ if(t->link[i])
+ printtrie(b, t->link[i]);
+
+ if(t->n > 0) {
+ Bprint(b, "\t\"");
+ cprints(b, t->seq);
+ Bprint(b, "\", \"");
+ for(i=0; i<256; i++)
+ if(t->r[i])
+ cprintchar(b, i);
+ Bprint(b, "\",\t");
+ if(rflag) {
+ Bprint(b, "{");
+ for(i=0; i<256; i++)
+ if(t->r[i])
+ Bprint(b, " 0x%.4ux,", t->r[i]);
+ Bprint(b, " }");
+ } else {
+ Bprint(b, "L\"");
+ for(i=0; i<256; i++)
+ if(t->r[i])
+ Bprint(b, "%C", t->r[i]);
+ Bprint(b, "\"");
+ }
+ Bprint(b, ",\n");
+ }
+}
+
+void
+readfile(char *fname)
+{
+ Biobuf *b;
+ char *line, *p;
+ char *seq;
+ int inseq;
+ int lineno;
+ Rune r;
+
+ if((b = Bopen(fname, OREAD)) == 0) {
+ fprint(2, "cannot open \"%s\": %r\n", fname);
+ exits("open");
+ }
+
+ lineno = 0;
+ while((line = Brdline(b, '\n')) != 0) {
+ lineno++;
+ if(line[0] == '#')
+ continue;
+
+ r = strtol(line, nil, 16);
+ p = strchr(line, ' ');
+ if(r == 0 || p != line+4 || p[0] != ' ' || p[1] != ' ') {
+ fprint(2, "%s:%d: cannot parse line\n", fname, lineno);
+ continue;
+ }
+
+ p = line+6;
+/* 00AE Or rO ® registered trade mark sign */
+ for(inseq=1, seq=p; (uchar)*p < Runeself; p++) {
+ if(*p == '\0' || isspace(*p)) {
+ if(inseq && p-seq >= 2) {
+ *p = '\0';
+ inseq = 0;
+ insert(seq, r);
+ *p = ' ';
+ }
+ if(*p == '\0')
+ break;
+ } else {
+ if(!inseq) {
+ seq = p;
+ inseq = 1;
+ }
+ }
+ }
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: mklatinkbd [-r] [/lib/keyboard]\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ Biobuf bout;
+
+ ARGBEGIN{
+ case 'r': /* print rune values */
+ rflag = 1;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc > 1)
+ usage();
+
+ readfile(argc == 1 ? argv[0] : "/fd/0");
+
+ Binit(&bout, 1, OWRITE);
+ if(root)
+ printtrie(&bout, root);
+ exits(0);
+}
--- a/sys/src/cmd/aux/mkfile
+++ b/sys/src/cmd/aux/mkfile
@@ -17,11 +17,9 @@
disksim\
getflags\
icanhasmsi\
- kbdfs\
lines\
listen\
listen1\
- mklatinkbd\
ms2\
msexceltables\
mswordstrings\
@@ -57,6 +55,7 @@
DIRS=mnihongo\
flashfs\
gps\
+ kbdfs\
na\
vga\
realemu
--- a/sys/src/cmd/aux/mklatinkbd.c
+++ /dev/null
@@ -1,232 +1,0 @@
-/*
- * Parse /lib/keyboard to create latin1.h table for kernel.
- * mklatinkbd -r prints an array of integers rather than a Rune string literal.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ctype.h>
-
-int rflag;
-
-enum {
- MAXLD = 2, /* latin1.c assumes this is 2 */
-};
-
-char *head = ""
-"/*\n"
-" * This is automatically generated by %s from /lib/keyboard\n"
-" * Edit /lib/keyboard instead.\n"
-" */\n";
-
-/*
- * latin1.c assumes that strlen(ld) is at most 2.
- * It also assumes that latintab[i].ld can be a prefix of latintab[j].ld
- * only when j < i. We ensure this by sorting the output by prefix length.
- * The so array is indexed by the character value.
- */
-
-typedef struct Trie Trie;
-struct Trie {
- int n; /* of characters r */
- char seq[MAXLD+1];
- Rune r[256];
- Trie *link[256];
-};
-
-Trie *root;
-
-Trie*
-mktrie(char *seq)
-{
- uchar *q;
- Trie **tp;
-
- if(root == nil) {
- root = malloc(sizeof *root);
- memset(root, 0, sizeof *root);
- }
-
- assert(seq[0] != '\0');
-
- tp = &root;
- for(q=(uchar*)seq; *(q+1) != '\0'; q++) {
- tp = &(*tp)->link[*q];
- if(*tp == nil) {
- *tp = malloc(sizeof(**tp));
- assert(*tp != nil);
- memset(*tp, 0, sizeof(**tp));
- strcpy((*tp)->seq, seq);
- (*tp)->seq[q+1-(uchar*)seq] = '\0';
- }
- }
-
- assert(*tp != nil);
- return *tp;
-}
-
-/* add character sequence s meaning rune r */
-void
-insert(char *s, Rune r)
-{
- uchar lastc;
- int len;
- Trie *t;
-
- len = strlen(s);
- lastc = (uchar)s[len-1];
-
- t = mktrie(s);
- if(t->r[lastc]) {
- fprint(2, "warning: table duplicate: %s is %C and %C\n", s, t->r[lastc], r);
- return;
- }
- t->r[lastc] = r;
- t->n++;
-}
-
-void
-cprintchar(Biobuf *b, int c)
-{
- /* print a byte c safe for a C string. */
- switch(c) {
- case '\'':
- case '\"':
- case '\\':
- Bprint(b, "\\%c", c);
- break;
- case '\t':
- Bprint(b, "\\t");
- break;
- default:
- if(isascii(c) && isprint(c))
- Bprint(b, "%c", c);
- else
- Bprint(b, "\\x%.2x", c);
- break;
- }
-}
-
-void
-cprints(Biobuf *b, char *p)
-{
- while(*p != '\0')
- cprintchar(b, *p++);
-}
-
-
-void
-printtrie(Biobuf *b, Trie *t)
-{
- int i;
-
- for(i=0; i<256; i++)
- if(t->link[i])
- printtrie(b, t->link[i]);
-
- if(t->n > 0) {
- Bprint(b, "\t\"");
- cprints(b, t->seq);
- Bprint(b, "\", \"");
- for(i=0; i<256; i++)
- if(t->r[i])
- cprintchar(b, i);
- Bprint(b, "\",\t");
- if(rflag) {
- Bprint(b, "{");
- for(i=0; i<256; i++)
- if(t->r[i])
- Bprint(b, " 0x%.4ux,", t->r[i]);
- Bprint(b, " }");
- } else {
- Bprint(b, "L\"");
- for(i=0; i<256; i++)
- if(t->r[i])
- Bprint(b, "%C", t->r[i]);
- Bprint(b, "\"");
- }
- Bprint(b, ",\n");
- }
-}
-
-void
-readfile(char *fname)
-{
- Biobuf *b;
- char *line, *p;
- char *seq;
- int inseq;
- int lineno;
- Rune r;
-
- if((b = Bopen(fname, OREAD)) == 0) {
- fprint(2, "cannot open \"%s\": %r\n", fname);
- exits("open");
- }
-
- lineno = 0;
- while((line = Brdline(b, '\n')) != 0) {
- lineno++;
- if(line[0] == '#')
- continue;
-
- r = strtol(line, nil, 16);
- p = strchr(line, ' ');
- if(r == 0 || p != line+4 || p[0] != ' ' || p[1] != ' ') {
- fprint(2, "%s:%d: cannot parse line\n", fname, lineno);
- continue;
- }
-
- p = line+6;
-/* 00AE Or rO ® registered trade mark sign */
- for(inseq=1, seq=p; (uchar)*p < Runeself; p++) {
- if(*p == '\0' || isspace(*p)) {
- if(inseq && p-seq >= 2) {
- *p = '\0';
- inseq = 0;
- insert(seq, r);
- *p = ' ';
- }
- if(*p == '\0')
- break;
- } else {
- if(!inseq) {
- seq = p;
- inseq = 1;
- }
- }
- }
- }
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: mklatinkbd [-r] [/lib/keyboard]\n");
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- Biobuf bout;
-
- ARGBEGIN{
- case 'r': /* print rune values */
- rflag = 1;
- break;
- default:
- usage();
- }ARGEND
-
- if(argc > 1)
- usage();
-
- readfile(argc == 1 ? argv[0] : "/fd/0");
-
- Binit(&bout, 1, OWRITE);
- if(root)
- printtrie(&bout, root);
- exits(0);
-}
--- a/sys/src/cmd/rio/rio.c
+++ b/sys/src/cmd/rio/rio.c
@@ -1234,10 +1234,8 @@
e = p + n;
while(p < e && fullrune(p, e - p)){
p += chartorune(&r, p);
- if(r){
- chanprint(c, "%C", r);
- chanprint(c, "");
- }
+ if(r)
+ chanprint(c, "c%C", r);
}
n = e - p;
memmove(buf, p, n);
--- a/sys/src/cmd/rio/wind.c
+++ b/sys/src/cmd/rio/wind.c
@@ -292,20 +292,16 @@
}
switch(alt(alts)){
case WKbd:
- if(utflen(kbds) >= utflen(kbdq[kbdqw] ? kbdq[kbdqw] : "")){
- Rune r;
-
- i = 0;
- r = 0;
- while(kbds[i])
- i += chartorune(&r, kbds+i);
- if(!w->kbdopen)
- wkeyctl(w, r);
- }
if(w->kbdopen){
i = (kbdqw+1) % nelem(kbdq);
if(i != kbdqr)
kbdqw = i;
+ } else if(*kbds == 'c'){
+ Rune r;
+
+ chartorune(&r, kbds+1);
+ if(r)
+ wkeyctl(w, r);
}
free(kbdq[kbdqw]);
kbdq[kbdqw] = kbds;
@@ -319,7 +315,7 @@
sendp(krm.ck, kbdq[i]);
kbdq[i] = nil;
}else
- sendp(krm.ck, strdup(""));
+ sendp(krm.ck, strdup("K"));
continue;
case WMouse:
--- a/sys/src/games/doom/i_video.c
+++ b/sys/src/games/doom/i_video.c
@@ -217,32 +217,40 @@
sysfatal("can't open kbd: %r");
buf2[0] = 0;
+ buf2[1] = 0;
while((n = read(kfd, buf, sizeof(buf))) > 0){
buf[n-1] = 0;
- s = buf;
- while(*s){
- s += chartorune(&r, s);
- if(utfrune(buf2, r) == nil){
- e.type = ev_keydown;
- if(e.data1 = runetokey(r)){
- e.data2 = *s == 0 ? e.data1 : -1;
- e.data3 = *s ? e.data1 : -1;
- D_PostEvent(&e);
+ switch(buf[0]){
+ case 'k':
+ s = buf+1;
+ while(*s){
+ s += chartorune(&r, s);
+ if(utfrune(buf2+1, r) == nil){
+ if(e.data1 = runetokey(r)){
+ e.data2 = *s == 0 ? e.data1 : -1;
+ e.data3 = -1;
+ e.type = ev_keydown;
+ D_PostEvent(&e);
+ }
}
}
- }
- s = buf2;
- while(*s){
- s += chartorune(&r, s);
- if(utfrune(buf, r) == nil){
- e.type = ev_keyup;
- if(e.data1 = runetokey(r)){
- e.data2 = -1;
- e.data3 = -1;
- D_PostEvent(&e);
+ break;
+ case 'K':
+ s = buf2+1;
+ while(*s){
+ s += chartorune(&r, s);
+ if(utfrune(buf+1, r) == nil){
+ if(e.data1 = runetokey(r)){
+ e.data2 = e.data3 = -1;
+ e.type = ev_keyup;
+ D_PostEvent(&e);
+ }
}
}
+ break;
+ default:
+ continue;
}
strcpy(buf2, buf);
}