ref: 00f7f2ceb6a1818e2975baf6f5c55c1d2d4ecb6e
dir: /sys/src/cmd/vnc/kbdv.c/
#include "vnc.h"
#include <keyboard.h>
#include "utf2ksym.h"
enum {
Xshift = 0xFFE1,
Xctl = 0xFFE3,
Xmeta = 0xFFE7,
Xalt = 0xFFE9
};
static struct {
Rune kbdc;
ulong keysym;
} ktab[] = {
{'\b', 0xff08},
{'\t', 0xff09},
{'\n', 0xff0d},
/* {0x0b, 0xff0b}, */
{'\r', 0xff0d},
{Kesc, 0xff1b},
{Kins, 0xff63},
{Kdel, 0xffff},
{Khome, 0xff50},
{Kend, 0xff57},
{Kpgup, 0xff55},
{Kpgdown, 0xff56},
{Kleft, 0xff51},
{Kup, 0xff52},
{Kright, 0xff53},
{Kdown, 0xff54},
{KF|1, 0xffbe},
{KF|2, 0xffbf},
{KF|3, 0xffc0},
{KF|4, 0xffc1},
{KF|5, 0xffc2},
{KF|6, 0xffc3},
{KF|7, 0xffc4},
{KF|8, 0xffc5},
{KF|9, 0xffc6},
{KF|10, 0xffc7},
{KF|11, 0xffc8},
{KF|12, 0xffc9},
{Kshift, Xshift},
{Kalt, Xalt},
{Kaltgr, Xmeta},
{Kctl, Xctl},
};
static char shiftkey[128] = {
0, 0, 0, 0, 0, 0, 0, 0, /* nul soh stx etx eot enq ack bel */
0, 0, 0, 0, 0, 0, 0, 0, /* bs ht nl vt np cr so si */
0, 0, 0, 0, 0, 0, 0, 0, /* dle dc1 dc2 dc3 dc4 nak syn etb */
0, 0, 0, 0, 0, 0, 0, 0, /* can em sub esc fs gs rs us */
0, 1, 1, 1, 1, 1, 1, 0, /* sp ! " # $ % & ' */
1, 1, 1, 1, 0, 0, 0, 0, /* ( ) * + , - . / */
0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
0, 0, 1, 0, 1, 0, 1, 1, /* 8 9 : ; < = > ? */
1, 1, 1, 1, 1, 1, 1, 1, /* @ A B C D E F G */
1, 1, 1, 1, 1, 1, 1, 1, /* H I J K L M N O */
1, 1, 1, 1, 1, 1, 1, 1, /* P Q R S T U V W */
1, 1, 1, 0, 0, 0, 1, 1, /* X Y Z [ \ ] ^ _ */
0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
0, 0, 0, 1, 1, 1, 1, 0, /* x y z { | } ~ del */
};
ulong
runetoksym(Rune r)
{
int i;
for(i=0; i<nelem(ktab); i++)
if(ktab[i].kbdc == r)
return ktab[i].keysym;
return r;
}
static void
keyevent(Vnc *v, ulong ksym, int down)
{
vnclock(v);
vncwrchar(v, MKey);
vncwrchar(v, down);
vncwrshort(v, 0);
vncwrlong(v, ksym);
vncflush(v);
vncunlock(v);
}
static void
readcons(Vnc *v)
{
char buf[256], k[10];
ulong ks;
int ctlfd, fd, kr, kn, w, shift, ctl, alt;
Rune r;
snprint(buf, sizeof buf, "%s/cons", display->devdir);
if((fd = open(buf, OREAD)) < 0)
sysfatal("open %s: %r", buf);
snprint(buf, sizeof buf, "%s/consctl", display->devdir);
if((ctlfd = open(buf, OWRITE)) < 0)
sysfatal("open %s: %r", buf);
write(ctlfd, "rawon", 5);
kn = 0;
shift = alt = ctl = 0;
for(;;){
while(!fullrune(k, kn)){
kr = read(fd, k+kn, sizeof k - kn);
if(kr <= 0)
sysfatal("bad read from kbd");
kn += kr;
}
w = chartorune(&r, k);
kn -= w;
memmove(k, &k[w], kn);
ks = runetoksym(r);
switch(r){
case Kalt:
alt = !alt;
keyevent(v, Xalt, alt);
break;
case Kctl:
ctl = !ctl;
keyevent(v, Xctl, ctl);
break;
case Kshift:
shift = !shift;
keyevent(v, Xshift, shift);
break;
default:
if(r == ks && r < 0x1A){ /* control key */
keyevent(v, Xctl, 1);
keyevent(v, r+0x60, 1); /* 0x60: make capital letter */
keyevent(v, r+0x60, 0);
keyevent(v, Xctl, 0);
}else{
/*
* to send an upper case letter or shifted
* punctuation, mac os x vnc server,
* at least, needs a `shift' sent first.
*/
if(!shift && r == ks && r < sizeof shiftkey && shiftkey[r]){
shift = 1;
keyevent(v, Xshift, 1);
}
/*
* map an xkeysym onto a utf-8 char.
* allows Xvnc to read us, see utf2ksym.h
*/
if((ks & 0xff00) && ks < nelem(utf2ksym) && utf2ksym[ks] != 0)
ks = utf2ksym[ks];
keyevent(v, ks, 1);
/*
* up event needed by vmware inside linux vnc server,
* perhaps others.
*/
keyevent(v, ks, 0);
}
if(alt){
keyevent(v, Xalt, 0);
alt = 0;
}
if(ctl){
keyevent(v, Xctl, 0);
ctl = 0;
}
if(shift){
keyevent(v, Xshift, 0);
shift = 0;
}
break;
}
}
}
ulong
runetovnc(Rune r)
{
ulong k;
k = runetoksym(r);
if((k & 0xff00) && k < nelem(utf2ksym) && utf2ksym[k] != 0)
k = utf2ksym[k];
return k;
}
void
readkbd(Vnc *v)
{
char buf[128], buf2[128], *s;
int fd, n;
Rune r;
if((fd = open("/dev/kbd", OREAD)) < 0){
readcons(v);
return;
}
buf2[0] = 0;
buf2[1] = 0;
buf[0] = 0;
for(;;){
if(buf[0] != 0){
n = strlen(buf)+1;
memmove(buf, buf+n, sizeof(buf)-n);
}
if(buf[0] == 0){
n = read(fd, buf, sizeof(buf)-1);
if(n <= 0)
break;
buf[n-1] = 0;
buf[n] = 0;
}
switch(buf[0]){
case 'k':
s = buf+1;
while(*s){
s += chartorune(&r, s);
if(utfrune(buf2+1, r) == nil)
if((r == Kshift) ||
utfrune(buf+1, Kctl) ||
utfrune(buf+1, Kalt) ||
utfrune(buf+1, Kaltgr))
keyevent(v, runetovnc(r), 1);
}
break;
case 'K':
s = buf2+1;
while(*s){
s += chartorune(&r, s);
if(utfrune(buf+1, r) == nil)
keyevent(v, runetovnc(r), 0);
}
break;
case 'c':
if(utfrune(buf2+1, Kctl) || utfrune(buf2+1, Kalt) || utfrune(buf2+1, Kaltgr))
continue;
chartorune(&r, buf+1);
keyevent(v, runetovnc(r), 1);
if(utfrune(buf2+1, r) == nil)
keyevent(v, runetovnc(r), 0);
default:
continue;
}
strcpy(buf2, buf);
}
}