big /dev/kbd change, new format, support Alt+Stuff (key composing)
This commit is contained in:
parent
98f4157b5a
commit
fbbb449cc0
9 changed files with 237 additions and 98 deletions
|
@ -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,
|
||||
.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
|
||||
.B Shift
|
||||
file returns the character
|
||||
.B k,
|
||||
.B K
|
||||
or
|
||||
.B Num
|
||||
will not change
|
||||
the characters already present in the string, but will
|
||||
take effect on newly pressed keys. Opening the
|
||||
.B c
|
||||
followed by a null terminated, variable-length,
|
||||
.SM UTF
|
||||
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
|
||||
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
|
||||
|
|
|
@ -101,6 +101,7 @@ Channel *reqchan; /* Req* */
|
|||
Channel *ctlchan; /* int */
|
||||
|
||||
Channel *rawchan; /* Rune */
|
||||
Channel *runechan; /* Rune */
|
||||
Channel *linechan; /* char * */
|
||||
Channel *kbdchan; /* char* */
|
||||
|
||||
|
@ -354,7 +355,7 @@ utfconv(Rune *r, int n)
|
|||
void
|
||||
keyproc(void *)
|
||||
{
|
||||
Rune rb[Nscan*2];
|
||||
Rune rb[Nscan*2+1];
|
||||
int cb[Nscan];
|
||||
Key key;
|
||||
int i, nb;
|
||||
|
@ -364,42 +365,35 @@ keyproc(void *)
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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, rb+i+1, (nb-i+1) * sizeof(rb[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] = key.b;
|
||||
rb[nb+1] = key.b;
|
||||
nb++;
|
||||
if(nb < nelem(cb) && key.r && key.b != key.r){
|
||||
cb[nb] = key.c;
|
||||
rb[nb] = key.r;
|
||||
rb[nb+1] = key.r;
|
||||
nb++;
|
||||
}
|
||||
rb[0] = 'k';
|
||||
}
|
||||
if(rb[0]){
|
||||
s = utfconv(rb, nb+1);
|
||||
if(nbsendp(kbdchan, s) <= 0)
|
||||
free(s);
|
||||
}
|
||||
s = utfconv(rb, nb);
|
||||
if(nbsendp(kbdchan, s) <= 0)
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,7 +423,7 @@ consproc(void *)
|
|||
}
|
||||
if(cr = (r == '\r'))
|
||||
r = '\n';
|
||||
send(rawchan, &r);
|
||||
send(runechan, &r);
|
||||
}
|
||||
}
|
||||
n = x - p;
|
||||
|
@ -438,6 +432,101 @@ consproc(void *)
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
@ -496,7 +585,7 @@ ctlproc(void *)
|
|||
Req *h;
|
||||
Req **t;
|
||||
} qcons, qkbd, *q;
|
||||
enum { Areq, Actl, Araw, Aline, Akbd, Aend };
|
||||
enum { Areq, Actl, Arune, Aline, Akbd, Aend };
|
||||
Alt a[Aend+1];
|
||||
Req *req;
|
||||
Fid *fid;
|
||||
|
@ -510,12 +599,13 @@ ctlproc(void *)
|
|||
cook = chancreate(sizeof(Rune), 0);
|
||||
|
||||
if(scanfd >= 0)
|
||||
proccreate(scanproc, nil, STACK);
|
||||
proccreate(scanproc, nil, STACK); /* scanfd -> keychan */
|
||||
if(consfd >= 0)
|
||||
proccreate(consproc, nil, STACK);
|
||||
proccreate(consproc, nil, STACK); /* consfd -> runechan */
|
||||
|
||||
threadcreate(keyproc, nil, STACK);
|
||||
threadcreate(lineproc, cook, STACK);
|
||||
threadcreate(keyproc, nil, STACK); /* keychan -> rawchan, kbdchan */
|
||||
threadcreate(runeproc, nil, STACK); /* rawchan -> runechan */
|
||||
threadcreate(lineproc, cook, STACK); /* cook -> linechan */
|
||||
|
||||
raw = 0;
|
||||
|
||||
|
@ -536,9 +626,9 @@ ctlproc(void *)
|
|||
a[Actl].v = &c;
|
||||
a[Actl].op = CHANRCV;
|
||||
|
||||
a[Araw].c = rawchan;
|
||||
a[Araw].v = &r;
|
||||
a[Araw].op = CHANRCV;
|
||||
a[Arune].c = runechan;
|
||||
a[Arune].v = &r;
|
||||
a[Arune].op = CHANRCV;
|
||||
|
||||
a[Aline].c = linechan;
|
||||
a[Aline].v = &s;
|
||||
|
@ -553,9 +643,15 @@ ctlproc(void *)
|
|||
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;
|
||||
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:
|
||||
|
@ -604,8 +700,15 @@ ctlproc(void *)
|
|||
}
|
||||
break;
|
||||
|
||||
case Araw:
|
||||
if(raw || kbdopen){
|
||||
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 {
|
||||
|
@ -620,11 +723,6 @@ ctlproc(void *)
|
|||
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;
|
||||
|
@ -643,6 +741,7 @@ ctlproc(void *)
|
|||
break;
|
||||
|
||||
case Akbd:
|
||||
Havekbd:
|
||||
if(req = qkbd.h){
|
||||
if((qkbd.h = req->aux) == nil)
|
||||
qkbd.t = &qkbd.h;
|
||||
|
@ -1166,11 +1265,12 @@ threadmain(int argc, char** argv)
|
|||
keychan = chancreate(sizeof(Key), 8);
|
||||
reqchan = chancreate(sizeof(Req*), 0);
|
||||
ctlchan = chancreate(sizeof(int), 0);
|
||||
rawchan = chancreate(sizeof(Rune), 32);
|
||||
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 && linechan && kbdchan))
|
||||
if(!(keychan && reqchan && ctlchan && rawchan && runechan && linechan && kbdchan))
|
||||
sysfatal("allocating chans");
|
||||
|
||||
elevate();
|
16
sys/src/cmd/aux/kbdfs/mkfile
Normal file
16
sys/src/cmd/aux/kbdfs/mkfile
Normal file
|
@ -0,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
|
7
sys/src/cmd/aux/kbdfs/mkfile.mklatin
Normal file
7
sys/src/cmd/aux/kbdfs/mkfile.mklatin
Normal file
|
@ -0,0 +1,7 @@
|
|||
</$objtype/mkfile
|
||||
|
||||
mklatin.$cputype: mklatin.$O
|
||||
$LD $LDFLAGS -o $target $prereq
|
||||
|
||||
</sys/src/cmd/mkone
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue