From fbbb449cc0bd35ebb89b87d5b46ed2874246876e Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 28 May 2011 08:16:01 +0000 Subject: big /dev/kbd change, new format, support Alt+Stuff (key composing) --- sys/man/8/kbdfs | 53 +- sys/src/cmd/aux/kbdfs.c | 1179 ------------------------------- sys/src/cmd/aux/kbdfs/kbdfs.c | 1279 ++++++++++++++++++++++++++++++++++ sys/src/cmd/aux/kbdfs/mkfile | 16 + sys/src/cmd/aux/kbdfs/mkfile.mklatin | 7 + sys/src/cmd/aux/kbdfs/mklatin.c | 232 ++++++ sys/src/cmd/aux/mkfile | 3 +- sys/src/cmd/aux/mklatinkbd.c | 232 ------ sys/src/cmd/rio/rio.c | 6 +- sys/src/cmd/rio/wind.c | 18 +- sys/src/games/doom/i_video.c | 46 +- 11 files changed, 1605 insertions(+), 1466 deletions(-) delete mode 100644 sys/src/cmd/aux/kbdfs.c create mode 100644 sys/src/cmd/aux/kbdfs/kbdfs.c create mode 100644 sys/src/cmd/aux/kbdfs/mkfile create mode 100644 sys/src/cmd/aux/kbdfs/mkfile.mklatin create mode 100644 sys/src/cmd/aux/kbdfs/mklatin.c delete mode 100644 sys/src/cmd/aux/mklatinkbd.c diff --git a/sys/man/8/kbdfs b/sys/man/8/kbdfs index 7149cbd62..733953bdf 100644 --- a/sys/man/8/kbdfs +++ b/sys/man/8/kbdfs @@ -152,26 +152,41 @@ This is used on serial consoles. .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 @@ to represent a control character. .SH FILES .B /dev/lib/kbmap/* .SH SOURCE -.B /sys/src/cmd/aux/kbdfs.c +.B /sys/src/cmd/aux/kbdfs diff --git a/sys/src/cmd/aux/kbdfs.c b/sys/src/cmd/aux/kbdfs.c deleted file mode 100644 index 1a0a0fa3d..000000000 --- a/sys/src/cmd/aux/kbdfs.c +++ /dev/null @@ -1,1179 +0,0 @@ -#include -#include -#include -#include -#include -#include -#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 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 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; iqid = *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; iifcall.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); -} diff --git a/sys/src/cmd/aux/kbdfs/kbdfs.c b/sys/src/cmd/aux/kbdfs/kbdfs.c new file mode 100644 index 000000000..2da4f958f --- /dev/null +++ b/sys/src/cmd/aux/kbdfs/kbdfs.c @@ -0,0 +1,1279 @@ +#include +#include +#include +#include +#include +#include +#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 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 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 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; iqid = *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; iifcall.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); +} diff --git a/sys/src/cmd/aux/kbdfs/mkfile b/sys/src/cmd/aux/kbdfs/mkfile new file mode 100644 index 000000000..dea627845 --- /dev/null +++ b/sys/src/cmd/aux/kbdfs/mkfile @@ -0,0 +1,16 @@ +$target diff --git a/sys/src/cmd/aux/kbdfs/mkfile.mklatin b/sys/src/cmd/aux/kbdfs/mkfile.mklatin new file mode 100644 index 000000000..ba34ac12c --- /dev/null +++ b/sys/src/cmd/aux/kbdfs/mkfile.mklatin @@ -0,0 +1,7 @@ + +#include +#include +#include + +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); +} diff --git a/sys/src/cmd/aux/mkfile b/sys/src/cmd/aux/mkfile index d46602c63..943ae06f2 100644 --- a/sys/src/cmd/aux/mkfile +++ b/sys/src/cmd/aux/mkfile @@ -17,11 +17,9 @@ TARG=\ disksim\ getflags\ icanhasmsi\ - kbdfs\ lines\ listen\ listen1\ - mklatinkbd\ ms2\ msexceltables\ mswordstrings\ @@ -57,6 +55,7 @@ UPDATE=\ DIRS=mnihongo\ flashfs\ gps\ + kbdfs\ na\ vga\ realemu diff --git a/sys/src/cmd/aux/mklatinkbd.c b/sys/src/cmd/aux/mklatinkbd.c deleted file mode 100644 index 64787f00f..000000000 --- a/sys/src/cmd/aux/mklatinkbd.c +++ /dev/null @@ -1,232 +0,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 -#include -#include -#include - -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); -} diff --git a/sys/src/cmd/rio/rio.c b/sys/src/cmd/rio/rio.c index 1550213ef..a101ee256 100644 --- a/sys/src/cmd/rio/rio.c +++ b/sys/src/cmd/rio/rio.c @@ -1234,10 +1234,8 @@ kbdproc(void *arg) 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); diff --git a/sys/src/cmd/rio/wind.c b/sys/src/cmd/rio/wind.c index 104c19e93..92b63c177 100644 --- a/sys/src/cmd/rio/wind.c +++ b/sys/src/cmd/rio/wind.c @@ -292,20 +292,16 @@ winctl(void *arg) } 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 @@ winctl(void *arg) sendp(krm.ck, kbdq[i]); kbdq[i] = nil; }else - sendp(krm.ck, strdup("")); + sendp(krm.ck, strdup("K")); continue; case WMouse: diff --git a/sys/src/games/doom/i_video.c b/sys/src/games/doom/i_video.c index dcf31a993..34543bc96 100644 --- a/sys/src/games/doom/i_video.c +++ b/sys/src/games/doom/i_video.c @@ -217,32 +217,40 @@ kbdproc(void *) 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); } -- cgit v1.2.3