vncs: /dev/kbd support by running kbdfs and forwarding keycodes thru kbdin

This commit is contained in:
cinap_lenrek 2012-02-25 23:47:09 +01:00
parent f2b6ec3140
commit ce6b942ff1
10 changed files with 190 additions and 603 deletions

View file

@ -20,6 +20,7 @@ kbdfs \- keyboard and console filesystem
.B /dev/cons
.B /dev/consctl
.B /dev/kbd
.B /dev/kbdin
.B /dev/kbin
.B /dev/kbmap
.fi
@ -34,6 +35,8 @@ translates raw keyboard scancodes from
.IR kbd (3))
and its
.BR kbin
and
.BR kbdin
file and optionaly reads console input from
.I consfile
to provide initial keyboard and console input.
@ -42,6 +45,7 @@ It serves a one-level directory containing the files
.BR cons,
.BR consctl,
.BR kbd,
.BR kbdin,
.BR kbin
and
.BR kbmap.
@ -171,17 +175,9 @@ 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.
of the keys that are currently pressed down in unshifted 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
The string following the
.B c
message contains the single character that would have been returned
on the
@ -198,6 +194,25 @@ file disables input processing on the
.BR cons
file until it is closed again.
.PP
.B K,
.B k
and
.B c
messages can be written to
.BR kbdin
and will forwarded to the reader of
.BR cons
or
.BR kbd.
Writing a
.B r
or
.B R
message followed by a
.SM UTF
encoded rune will simulate the press or
release of that particular rune.
.PP
Raw scancodes can be written to the
.BR kbin
file for external keyboard input (used for USB keyboards).
@ -241,6 +256,6 @@ to represent a control character.
.IR utf (6),
.IR kbd (3)
.SH FILES
.B /dev/lib/kbmap/*
.B /sys/lib/kbmap/*
.SH SOURCE
.B /sys/src/cmd/aux/kbdfs

View file

@ -11,6 +11,7 @@ enum {
Qroot= 0,
Qkbd,
Qkbdin,
Qkbin,
Qkbmap,
Qcons,
@ -58,6 +59,10 @@ struct Qtab {
0600,
0,
"kbdin",
0200,
0,
"kbin",
0200,
0,
@ -353,8 +358,7 @@ utfconv(Rune *r, int n)
/*
* 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.
* rawchan and keystate in kbdchan.
*/
void
keyproc(void *)
@ -369,9 +373,6 @@ keyproc(void *)
nb = 0;
while(recv(keychan, &key) > 0){
if(key.down && key.r)
send(rawchan, &key.r);
rb[0] = 0;
for(i=0; i<nb && cb[i] != key.c; i++)
;
@ -386,14 +387,14 @@ keyproc(void *)
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]){
if(kbdopen){
s = utfconv(rb, nb+1);
if(nbsendp(kbdchan, s) <= 0)
free(s);
}
if(mctlfd >= 0){
if(key.r == Kshift){
if(key.down){
@ -405,12 +406,9 @@ keyproc(void *)
}
fprint(mctlfd, "twitch");
}
if(kbdopen){
s = utfconv(rb, nb+1);
if(nbsendp(kbdchan, s) <= 0)
free(s);
}
}
if(key.down && key.r)
send(rawchan, &key.r);
}
}
@ -1084,8 +1082,10 @@ static void
fswrite(Req *r)
{
Fid *f;
char *p;
Scan *a;
char *p, *s;
int n, i;
Key k;
f = r->fid;
switch((ulong)f->qid.path){
@ -1116,6 +1116,80 @@ fswrite(Req *r)
r->ofcall.count = n;
break;
case Qkbdin:
p = r->ifcall.data;
n = r->ifcall.count;
if(n <= 0)
n = 0;
r->ofcall.count = n;
if(p[n-1] != 0){
/*
* old format as used by bitsy keyboard:
* just a string of characters, no keyup
* information.
*/
s = emalloc9p(n+1);
memmove(s, p, n);
s[n] = 0;
p = s;
while(*p){
p += chartorune(&k.r, p);
if(k.r)
send(rawchan, &k.r);
}
free(s);
break;
}
switch(p[0]){
case 'R':
case 'r':
/* rune up/down */
chartorune(&k.r, p+1);
if(k.r == 0)
break;
k.b = k.r;
k.c = 0x100 + k.r; /* fake */
k.down = (p[0] == 'r');
if(f->aux == nil){
f->aux = emalloc9p(sizeof(Scan));
memset(f->aux, 0, sizeof(Scan));
}
a = f->aux;
/*
* handle ^X forms according to keymap,
* assign base and scancode if any
*/
for(i=0; i<Nscan; i++){
if((a->shift && kbtabshift[i] == k.r) || (kbtab[i] == k.r)){
k.c = i;
k.b = kbtab[i];
if(a->shift)
k.r = kbtabshift[i];
else if(a->altgr)
k.r = kbtabaltgr[i];
else if(a->ctl)
k.r = kbtabctl[i];
break;
}
}
send(keychan, &k);
if(k.r == Kshift)
a->shift = k.down;
else if(k.r == Kaltgr)
a->altgr = k.down;
else if(k.r == Kctl)
a->ctl = k.down;
break;
default:
if(!kbdopen)
break;
s = emalloc9p(n);
memmove(s, p, n);
if(nbsendp(kbdchan, s) <= 0)
free(s);
}
break;
case Qkbin:
if(f->aux == nil){
f->aux = emalloc9p(sizeof(Scan));
@ -1155,6 +1229,7 @@ fsdestroyfid(Fid *f)
if(f->omode != -1)
switch((ulong)f->qid.path){
case Qkbdin:
case Qkbin:
case Qkbmap:
if(p = f->aux){

View file

@ -4,180 +4,10 @@
#include "kbd.h"
#include "error.h"
typedef struct Queue Queue;
struct Queue
{
QLock qwait;
Rendez rwait;
Lock lock;
int notempty;
char buf[1024];
char *w;
char *r;
char *e;
};
Queue* kbdq; /* unprocessed console input */
Queue* lineq; /* processed console input */
Snarf snarf = {
.vers = 1
};
static struct
{
QLock;
int raw; /* true if we shouldn't process input */
int ctl; /* number of opens to the control file */
int x; /* index into line */
char line[1024]; /* current input line */
} kbd;
/*
* cheapo fixed-length queues
*/
static void
qwrite(Queue *q, void *v, int n)
{
char *buf, *next;
int i;
buf = v;
lock(&q->lock);
for(i = 0; i < n; i++){
next = q->w+1;
if(next >= q->e)
next = q->buf;
if(next == q->r)
break;
*q->w = buf[i];
q->w = next;
}
q->notempty = 1;
unlock(&q->lock);
rendwakeup(&q->rwait);
}
static int
qcanread(void *vq)
{
Queue *q;
int ne;
q = vq;
lock(&q->lock);
ne = q->notempty;
unlock(&q->lock);
return ne;
}
static int
qread(Queue *q, void *v, int n)
{
char *a;
int nn, notempty;
if(n == 0)
return 0;
a = v;
nn = 0;
for(;;){
lock(&q->lock);
while(nn < n && q->r != q->w){
a[nn++] = *q->r++;
if(q->r >= q->e)
q->r = q->buf;
}
notempty = q->notempty;
q->notempty = q->r != q->w;
unlock(&q->lock);
if(notempty)
break;
/*
* wait for something to show up in the kbd buffer.
*/
qlock(&q->qwait);
if(waserror()){
qunlock(&q->qwait);
nexterror();
}
rendsleep(&q->rwait, qcanread, q);
qunlock(&q->qwait);
poperror();
}
return nn;
}
static Queue *
mkqueue(void)
{
Queue *q;
q = smalloc(sizeof(Queue));
q->r = q->buf;
q->w = q->r;
q->e = &q->buf[sizeof q->buf];
q->notempty = 0;
return q;
}
static void
echoscreen(char *buf, int n)
{
char *e, *p;
char ebuf[128];
int x;
p = ebuf;
e = ebuf + sizeof(ebuf) - 4;
while(n-- > 0){
if(p >= e){
screenputs(ebuf, p - ebuf);
p = ebuf;
}
x = *buf++;
if(x == 0x15){
*p++ = '^';
*p++ = 'U';
*p++ = '\n';
} else
*p++ = x;
}
if(p != ebuf)
screenputs(ebuf, p - ebuf);
}
/*
* Put character, possibly a rune, into read queue at interrupt time.
* Called at interrupt time to process a character.
*/
void
kbdputc(int ch)
{
int n;
char buf[3];
Rune r;
r = ch;
n = runetochar(buf, &r);
qwrite(kbdq, buf, n);
if(!kbd.raw)
echoscreen(buf, n);
}
static void
kbdputcinit(void)
{
kbdq = mkqueue();
lineq = mkqueue();
kbd.raw = 0;
kbd.ctl = 0;
kbd.x = 0;
}
enum{
Qdir,
Qcons,
@ -194,12 +24,6 @@ static Dirtab consdir[]={
"winname", {Qwinname}, 0, 0000,
};
static void
consinit(void)
{
kbdputcinit();
}
static Chan*
consattach(char *spec)
{
@ -225,9 +49,6 @@ consopen(Chan *c, int omode)
c = devopen(c, omode, consdir, nelem(consdir), devgen);
switch((ulong)c->qid.path){
case Qconsctl:
qlock(&kbd);
kbd.ctl++;
qunlock(&kbd);
break;
case Qsnarf:
if((c->mode&3) == OWRITE || (c->mode&3) == ORDWR)
@ -266,12 +87,6 @@ consclose(Chan *c)
switch((ulong)c->qid.path){
/* last close of control file turns off raw */
case Qconsctl:
if(c->flag&COPEN){
qlock(&kbd);
if(--kbd.ctl == 0)
kbd.raw = 0;
qunlock(&kbd);
}
break;
/* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
case Qsnarf:
@ -289,9 +104,6 @@ consclose(Chan *c)
static long
consread(Chan *c, void *buf, long n, vlong off)
{
char ch;
int send;
if(n <= 0)
return n;
switch((ulong)c->qid.path){
@ -310,48 +122,8 @@ consread(Chan *c, void *buf, long n, vlong off)
return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
case Qcons:
qlock(&kbd);
if(waserror()){
qunlock(&kbd);
nexterror();
}
while(!qcanread(lineq)){
qread(kbdq, &ch, 1);
send = 0;
if(ch == 0){
/* flush output on rawoff -> rawon */
if(kbd.x > 0)
send = !qcanread(kbdq);
}else if(kbd.raw){
kbd.line[kbd.x++] = ch;
send = !qcanread(kbdq);
}else{
switch(ch){
case '\b':
if(kbd.x > 0)
kbd.x--;
break;
case 0x15: /* ^U */
kbd.x = 0;
break;
case '\n':
case 0x04: /* ^D */
send = 1;
default:
if(ch != 0x04)
kbd.line[kbd.x++] = ch;
break;
}
}
if(send || kbd.x == sizeof kbd.line){
qwrite(lineq, kbd.line, kbd.x);
kbd.x = 0;
}
}
n = qread(lineq, buf, n);
qunlock(&kbd);
poperror();
return n;
error(Egreg);
return -1;
default:
print("consread 0x%llux\n", c->qid.path);
@ -364,8 +136,7 @@ static long
conswrite(Chan *c, void *va, long n, vlong)
{
Snarf *t;
char buf[256], *a;
char ch;
char *a;
switch((ulong)c->qid.path){
case Qcons:
@ -373,22 +144,7 @@ conswrite(Chan *c, void *va, long n, vlong)
break;
case Qconsctl:
if(n >= sizeof(buf))
n = sizeof(buf)-1;
strncpy(buf, va, n);
buf[n] = 0;
for(a = buf; a;){
if(strncmp(a, "rawon", 5) == 0){
kbd.raw = 1;
/* clumsy hack - wake up reader */
ch = 0;
qwrite(kbdq, &ch, 1);
} else if(strncmp(a, "rawoff", 6) == 0){
kbd.raw = 0;
}
if(a = strchr(a, ' '))
a++;
}
error(Egreg);
break;
case Qsnarf:
@ -416,7 +172,7 @@ Dev consdevtab = {
"cons",
devreset,
consinit,
devinit,
consattach,
conswalk,
consstat,

View file

@ -14,9 +14,8 @@ enum
};
extern Snarf snarf;
extern int kbdin;
long latin1(Rune *k, int n);
void kbdputc(int c);
void screenputs(char*, int);
void vncputc(int, int);
void setsnarf(char *buf, int n, int *vers);

View file

@ -1,81 +1,48 @@
#include <u.h>
#include <libc.h>
#include <keyboard.h>
#include "compat.h"
#include "kbd.h"
#include "ksym2utf.h"
enum
{
enum {
VKSpecial = 0xff00,
/*
* plan 9 key mappings
*/
Spec= 0xF800,
PF= Spec|0x20, /* num pad function key */
View= Spec|0x00, /* view (shift window up) */
KF= 0xF000, /* function key (begin Unicode private space) */
Shift= Spec|0x60,
Break= Spec|0x61,
Ctrl= Spec|0x62,
Latin= Spec|0x63,
Caps= Spec|0x64,
Num= Spec|0x65,
Middle= Spec|0x66,
No= 0x00, /* peter */
Home= KF|13,
Up= KF|14,
Pgup= KF|15,
Print= KF|16,
Left= KF|17,
Right= KF|18,
End= '\r',
Down= View,
Pgdown= KF|19,
Ins= KF|20,
Del= 0x7F,
Scroll= KF|21,
Esc = 0x1b,
Delete = 0x7f,
};
static Rune vnckeys[] =
{
[0x00] No, No, No, No, No, No, No, No,
[0x08] '\b', '\t', '\r', No, No, '\n', No, No,
[0x10] No, No, No, No, Scroll, No, No, No,
[0x18] No, No, No, Esc, No, No, No, No,
[0x20] No, No, No, No, No, No, No, No,
[0x28] No, No, No, No, No, No, No, No,
[0x30] No, No, No, No, No, No, No, No,
[0x38] No, No, No, No, No, No, No, No,
[0x40] No, No, No, No, No, No, No, No,
[0x48] No, No, No, No, No, No, No, No,
[0x50] Home, Left, Up, Right, Down, Pgup, Pgdown, No,
[0x58] No, No, No, No, No, No, No, No,
[0x60] No, Print, No, Ins, No, No, No, No,
[0x68] No, No, No, Break, No, No, No, No,
[0x70] No, No, No, No, No, No, No, No,
[0x78] No, No, No, No, No, No, No, Num,
[0x80] No, No, No, No, No, No, No, No,
[0x88] No, No, No, No, No, No, No, No,
[0x90] No, No, No, No, No, No, No, No,
[0x98] No, No, No, No, No, No, No, No,
[0xa0] No, No, No, No, No, No, No, No,
[0xa8] No, No, '*', '+', No, '-', '.', '/',
[0x00] 0, 0, 0, 0, 0, 0, 0, 0,
[0x08] '\b', '\t', '\r', 0, 0, '\n', 0, 0,
[0x10] 0, 0, 0, 0, Kscroll,0, 0, 0,
[0x18] 0, 0, 0, Kesc, 0, 0, 0, 0,
[0x20] 0, 0, 0, 0, 0, 0, 0, 0,
[0x28] 0, 0, 0, 0, 0, 0, 0, 0,
[0x30] 0, 0, 0, 0, 0, 0, 0, 0,
[0x38] 0, 0, 0, 0, 0, 0, 0, 0,
[0x40] 0, 0, 0, 0, 0, 0, 0, 0,
[0x48] 0, 0, 0, 0, 0, 0, 0, 0,
[0x50] Khome, Kleft, Kup, Kright, Kdown, Kpgup, Kpgdown,0,
[0x58] 0, 0, 0, 0, 0, 0, 0, 0,
[0x60] 0, Kprint, 0, Kins, 0, 0, 0, 0,
[0x68] 0, 0, 0, Kbreak, 0, 0, 0, 0,
[0x70] 0, 0, 0, 0, 0, 0, 0, 0,
[0x78] 0, 0, 0, 0, 0, 0, 0, Knum,
[0x80] 0, 0, 0, 0, 0, 0, 0, 0,
[0x88] 0, 0, 0, 0, 0, 0, 0, 0,
[0x90] 0, 0, 0, 0, 0, 0, 0, 0,
[0x98] 0, 0, 0, 0, 0, 0, 0, 0,
[0xa0] 0, 0, 0, 0, 0, 0, 0, 0,
[0xa8] 0, 0, '*', '+', 0, '-', '.', '/',
[0xb0] '0', '1', '2', '3', '4', '5', '6', '7',
[0xb8] '8', '9', No, No, No, '=', No, No,
[0xc0] No, No, No, No, No, No, No, No,
[0xc8] No, No, No, No, No, No, No, No,
[0xd0] No, No, No, No, No, No, No, No,
[0xd8] No, No, No, No, No, No, No, No,
[0xe0] No, Shift, Shift, Ctrl, Ctrl, Caps, Caps, No,
[0xe8] No, Latin, Latin, No, No, No, No, No,
[0xf0] No, No, No, No, No, No, No, No,
[0xf8] No, No, No, No, No, No, No, Delete,
[0xb8] '8', '9', 0, 0, 0, '=', 0, 0,
[0xc0] 0, 0, 0, 0, 0, 0, 0, 0,
[0xc8] 0, 0, 0, 0, 0, 0, 0, 0,
[0xd0] 0, 0, 0, 0, 0, 0, 0, 0,
[0xd8] 0, 0, 0, 0, 0, 0, 0, 0,
[0xe0] 0, Kshift, Kshift, Kctl, Kctl, Kcaps, Kcaps, 0,
[0xe8] 0, Kalt, Kalt, 0, 0, 0, 0, 0,
[0xf0] 0, 0, 0, 0, 0, 0, 0, 0,
[0xf8] 0, 0, 0, 0, 0, 0, 0, Kdel,
};
/*
@ -84,90 +51,24 @@ static Rune vnckeys[] =
void
vncputc(int keyup, int c)
{
int i;
static int esc1, esc2;
static int alt, caps, ctl, num, shift;
static int collecting, nk;
static Rune kc[5];
if(caps && c<='z' && c>='a')
c += 'A' - 'a';
char buf[16];
/*
* character mapping
*/
if((c & VKSpecial) == VKSpecial){
c = vnckeys[c & 0xff];
if(c == No)
if(c == 0)
return;
}
/*
* map an xkeysym onto a utf-8 char
*/
if((c & 0xff00) && c < nelem(ksym2utf) && ksym2utf[c] != 0)
c = ksym2utf[c];
/*
* keyup only important for shifts
*/
if(keyup){
switch(c){
case Latin:
alt = 0;
break;
case Shift:
shift = 0;
break;
case Ctrl:
ctl = 0;
break;
}
return;
}
/*
* normal character
*/
if(!(c & (Spec|KF))){
if(ctl){
c &= 0x1f;
}
if(!collecting){
kbdputc(c);
return;
}
kc[nk++] = c;
c = latin1(kc, nk);
if(c < -1) /* need more keystrokes */
return;
if(c != -1) /* valid sequence */
kbdputc(c);
else /* dump characters */
for(i=0; i<nk; i++)
kbdputc(kc[i]);
nk = 0;
collecting = 0;
return;
}else{
switch(c){
case Caps:
caps ^= 1;
return;
case Num:
num ^= 1;
return;
case Shift:
shift = 1;
return;
case Latin:
alt = 1;
collecting = 1;
nk = 0;
return;
case Ctrl:
ctl = 1;
return;
}
}
kbdputc(c);
c = ksym2utf[c];
snprint(buf, sizeof(buf), "r%C", c);
if(keyup)
buf[0] = 'R';
if(kbdin >= 0)
write(kbdin, buf, strlen(buf)+1);
}

View file

@ -229,11 +229,12 @@ readkbd(Vnc *v)
}
break;
case 'c':
chartorune(&r, buf+1);
if(utfrune(buf2+1, Kctl) || utfrune(buf2+1, Kalt) || utfrune(buf2+1, Kaltgr))
continue;
if(utfrune(buf2+1, r))
keyevent(v, runetovnc(r), 1);
chartorune(&r, buf+1);
keyevent(v, runetovnc(r), 1);
if(utfrune(buf2+1, r) == nil)
keyevent(v, runetovnc(r), 0);
default:
continue;
}

View file

@ -1,76 +0,0 @@
#include <u.h>
/*
* The code makes two assumptions: strlen(ld) is 1 or 2; latintab[i].ld can be a
* prefix of latintab[j].ld only when j<i.
*/
struct cvlist
{
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 */
} latintab[] = {
#include "latin1.h"
0, 0, 0
};
/*
* Given 5 characters k[0]..k[4], find the rune or return -1 for failure.
*/
long
unicode(Rune *k)
{
long i, c;
k++; /* skip 'X' */
c = 0;
for(i=0; i<4; i++,k++){
c <<= 4;
if('0'<=*k && *k<='9')
c += *k-'0';
else if('a'<=*k && *k<='f')
c += 10 + *k-'a';
else if('A'<=*k && *k<='F')
c += 10 + *k-'A';
else
return -1;
}
return c;
}
/*
* Given n characters k[0]..k[n-1], find the corresponding rune or return -1 for
* failure, or something < -1 if n is too small. In the latter case, the result
* is minus the required n.
*/
long
latin1(Rune *k, int n)
{
struct cvlist *l;
int c;
char* p;
if(k[0] == 'X')
if(n>=5)
return unicode(k);
else
return -5;
for(l=latintab; l->ld!=0; l++)
if(k[0] == l->ld[0]){
if(n == 1)
return -2;
if(l->ld[1] == 0)
c = k[1];
else if(l->ld[1] != k[1])
continue;
else if(n == 2)
return -3;
else
c = k[2];
for(p=l->si; *p!=0; p++)
if(*p == c)
return l->so[p - l->si];
return -1;
}
return -1;
}

View file

@ -1,100 +0,0 @@
" ", " i", L"␣ı",
"!~", "-=~", L"≄≇≉",
"!", "!<=>?bmp", L"¡≮≠≯‽⊄∉⊅",
"\"*", "IUiu", L"ΪΫϊϋ",
"\"", "\"AEIOUYaeiouy", L"¨ÄËÏÖÜŸäëïöüÿ",
"$*", "fhk", L"ϕϑϰ",
"$", "BEFHILMRVaefglopv", L"ℬℰℱℋℐℒℳℛƲɑℯƒℊℓℴ℘ʋ",
"\'\"", "Uu", L"Ǘǘ",
"\'", "\'ACEILNORSUYZacegilnorsuyz", L"´ÁĆÉÍĹŃÓŔŚÚÝŹáćéģíĺńóŕśúýź",
"*", "*ABCDEFGHIKLMNOPQRSTUWXYZabcdefghiklmnopqrstuwxyz", L"∗ΑΒΞΔΕΦΓΘΙΚΛΜΝΟΠΨΡΣΤΥΩΧΗΖαβξδεφγθικλμνοπψρστυωχηζ",
"+", "-O", L"±⊕",
",", ",ACEGIKLNORSTUacegiklnorstu", L"¸ĄÇĘĢĮĶĻŅǪŖŞŢŲąçęģįķļņǫŗşţų",
"-*", "l", L"ƛ",
"-", "+-2:>DGHILOTZbdghiltuz~", L"∓­ƻ÷→ÐǤĦƗŁ⊖ŦƵƀðǥℏɨłŧʉƶ≂",
".", ".CEGILOZceglz", L"·ĊĖĠİĿ⊙Żċėġŀż",
"/", "Oo", L"Øø",
"1", ".234568", L"․½⅓¼⅕⅙⅛",
"2", "-.35", L"ƻ‥⅔⅖",
"3", ".458", L"…¾⅗⅜",
"4", "5", L"",
"5", "68", L"⅚⅝",
"7", "8", L"",
":", "()-=", L"☹☺÷≔",
"<!", "=~", L"≨⋦",
"<", "-<=>~", L"←«≤≶≲",
"=", ":<=>OV", L"≕⋜≡⋝⊜⇒",
">!", "=~", L"≩⋧",
">", "<=>~", L"≷≥»≳",
"?", "!?", L"‽¿",
"@\'", "\'", L"ъ",
"@@", "\'EKSTYZekstyz", L"ьЕКСТЫЗекстыз",
"@C", "Hh", L"ЧЧ",
"@E", "Hh", L"ЭЭ",
"@K", "Hh", L"ХХ",
"@S", "CHch", L"ЩШЩШ",
"@T", "Ss", L"ЦЦ",
"@Y", "AEOUaeou", L"ЯЕЁЮЯЕЁЮ",
"@Z", "Hh", L"ЖЖ",
"@c", "h", L"ч",
"@e", "h", L"э",
"@k", "h", L"х",
"@s", "ch", L"щш",
"@t", "s", L"ц",
"@y", "aeou", L"яеёю",
"@z", "h", L"ж",
"@", "ABDFGIJLMNOPRUVXabdfgijlmnopruvx", L"АБДФГИЙЛМНОПРУВХабдфгийлмнопрувх",
"A", "E", L"Æ",
"C", "ACU", L"⋂ℂ⋃",
"Dv", "Zz", L"DŽDž",
"D", "-e", L"Ð∆",
"G", "-", L"Ǥ",
"H", "-H", L"Ħℍ",
"I", "-J", L"ƗIJ",
"L", "&-Jj|", L"⋀ŁLJLj⋁",
"M", "#48bs", L"♮♩♪♭♯",
"N", "JNj", L"NJℕNj",
"O", "*+-./=EIcoprx", L"⊛⊕⊖⊙⊘⊜ŒƢ©⊚℗®⊗",
"P", "P", L"",
"Q", "Q", L"",
"R", "R", L"",
"S", "S", L"§",
"T", "-u", L"Ŧ⊨",
"V", "=", L"",
"Y", "R", L"Ʀ",
"Z", "-ACSZ", L"Ƶℤ",
"^", "ACEGHIJOSUWYaceghijosuwy", L"ÂĈÊĜĤÎĴÔŜÛŴŶâĉêĝĥîĵôŝûŵŷ",
"_\"", "AUau", L"ǞǕǟǖ",
"_,", "Oo", L"Ǭǭ",
"_.", "Aa", L"Ǡǡ",
"_", "AEIOU_aeiou", L"ĀĒĪŌŪ¯āēīōū",
"`\"", "Uu", L"Ǜǜ",
"`", "AEIOUaeiou", L"ÀÈÌÒÙàèìòù",
"a", "ben", L"↔æ∠",
"b", "()+-0123456789=bknpqru", L"₍₎₊₋₀₁₂₃₄₅₆₇₈₉₌♝♚♞♟♛♜•",
"c", "$Oagu", L"¢©∩≅∪",
"dv", "z", L"dž",
"d", "-adegz", L"ð↓‡°†ʣ",
"e", "$lmns", L"€⋯—–∅",
"f", "a", L"",
"g", "$-r", L"¤ǥ∇",
"h", "-v", L"ℏƕ",
"i", "-bfjps", L"ɨ⊆∞ij⊇∫",
"l", "\"$&\'-jz|", L"“£∧‘łlj⋄∨",
"m", "iou", L"µ∈×",
"n", "jo", L"nj¬",
"o", "AOUaeiu", L"Å⊚Ůåœƣů",
"p", "Odgrt", L"℗∂¶∏∝",
"r", "\"\'O", L"”’®",
"s", "()+-0123456789=abnoprstu", L"⁽⁾⁺⁻⁰¹²³⁴⁵⁶⁷⁸⁹⁼ª⊂ⁿº⊃√ß∍∑",
"t", "-efmsu", L"ŧ∃∴™ς⊢",
"u", "-AEGIOUaegiou", L"ʉĂĔĞĬŎŬ↑ĕğĭŏŭ",
"v\"", "Uu", L"Ǚǚ",
"v", "ACDEGIKLNORSTUZacdegijklnorstuz", L"ǍČĎĚǦǏǨĽŇǑŘŠŤǓŽǎčďěǧǐǰǩľňǒřšťǔž",
"w", "bknpqr", L"♗♔♘♙♕♖",
"x", "O", L"",
"y", "$", L"¥",
"z", "-", L"ƶ",
"|", "Pp|", L"Þþ¦",
"~!", "=", L"",
"~", "-=AINOUainou~", L"≃≅ÃĨÑÕŨãĩñõũ≈",

View file

@ -18,7 +18,6 @@ SOFILES=\
compat.$O\
exportfs.$O\
kbds.$O\
latin1.$O\
rre.$O\
rlist.$O\
@ -34,7 +33,6 @@ HFILES=\
compat.h\
errstr.h\
kbd.h\
latin1.h\
vncv.h\
vncs.h\

View file

@ -55,6 +55,8 @@ struct {
int shared;
int sleeptime = 5;
int verbose = 0;
int kbdin = -1;
char *cert;
char *pixchan = "r5g6b5";
static int cmdpid;
@ -88,6 +90,7 @@ main(int argc, char **argv)
int altnet, baseport, cfd, display, exnum, fd, h, killing, w;
char adir[NETPATHLEN], ldir[NETPATHLEN];
char net[NETPATHLEN], *p;
char *kbdfs[] = { "/bin/aux/kbdfs", "-dq", nil };
char *rc[] = { "/bin/rc", "-i", nil };
Vncs *v;
@ -190,7 +193,7 @@ main(int argc, char **argv)
bind("#c", "/dev", MREPL);
/* run the command */
switch(cmdpid = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG|RFREND)){
switch(cmdpid = rfork(RFPROC|RFFDG|RFNOTEG)){
case -1:
sysfatal("rfork: %r");
break;
@ -198,12 +201,20 @@ main(int argc, char **argv)
if(mounter("/dev", MBEFORE, fd, exnum) < 0)
sysfatal("mounter: %r");
close(exportfd);
close(0);
close(1);
close(2);
open("/dev/cons", OWRITE);
open("/dev/cons", OWRITE);
if(rfork(RFPROC|RFMEM|RFFDG) == 0){
exec(kbdfs[0], kbdfs);
_exits("kbdfs");
}
waitpid();
rfork(RFNAMEG);
rendezvous(&cmdpid, 0);
rfork(RFREND);
close(0);
open("/dev/cons", OREAD);
open("/dev/cons", OWRITE);
open("/dev/cons", OWRITE);
exec(argv[0], argv);
fprint(2, "exec %s: %r\n", argv[0]);
_exits(nil);
@ -212,6 +223,11 @@ main(int argc, char **argv)
break;
}
rendezvous(&cmdpid, 0);
kbdin = open("/dev/kbdin", OWRITE);
unmount(nil, "/dev");
bind("#c", "/dev", MREPL);
/* run the service */
srvfd = vncannounce(net, display, adir, baseport);
if(srvfd < 0)
@ -385,6 +401,8 @@ killall(void)
srvfd = -1;
close(exportfd);
exportfd = -1;
close(kbdin);
kbdin = -1;
postnote(PNGROUP, getpid(), killkin);
}