xref: /plan9-contrib/sys/src/cmd/vnc/kbdv.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
1f8e525acSDavid du Colombier #include "vnc.h"
2f8e525acSDavid du Colombier #include <keyboard.h>
3ebe1d0a8SDavid du Colombier #include "utf2ksym.h"
4f8e525acSDavid du Colombier 
5f8e525acSDavid du Colombier enum {
6f8e525acSDavid du Colombier 	Xshift = 0xFFE1,
7f8e525acSDavid du Colombier 	Xctl = 0xFFE3,
8f8e525acSDavid du Colombier 	Xmeta = 0xFFE7,
9f8e525acSDavid du Colombier 	Xalt = 0xFFE9
10f8e525acSDavid du Colombier };
11f8e525acSDavid du Colombier 
12f8e525acSDavid du Colombier static struct {
13f8e525acSDavid du Colombier 	Rune kbdc;
14f8e525acSDavid du Colombier 	ulong keysym;
15f8e525acSDavid du Colombier } ktab[] = {
16f8e525acSDavid du Colombier 	{'\b',		0xff08},
17f8e525acSDavid du Colombier 	{'\t',		0xff09},
18f8e525acSDavid du Colombier 	{'\n',		0xff0d},
19f8e525acSDavid du Colombier 	/* {0x0b, 0xff0b}, */
20f8e525acSDavid du Colombier 	{'\r',		0xff0d},
21f8e525acSDavid du Colombier 	{0x1b,	0xff1b},	/* escape */
22f8e525acSDavid du Colombier 	{Kins,	0xff63},
23f8e525acSDavid du Colombier 	{0x7F,	0xffff},
24f8e525acSDavid du Colombier 	{Khome,	0xff50},
25f8e525acSDavid du Colombier 	{Kend,	0xff57},
26f8e525acSDavid du Colombier 	{Kpgup,	0xff55},
27f8e525acSDavid du Colombier 	{Kpgdown,	0xff56},
28f8e525acSDavid du Colombier 	{Kleft,	0xff51},
29f8e525acSDavid du Colombier 	{Kup,	0xff52},
30f8e525acSDavid du Colombier 	{Kright,	0xff53},
31f8e525acSDavid du Colombier 	{Kdown,	0xff54},
32f8e525acSDavid du Colombier 	{KF|1,	0xffbe},
33f8e525acSDavid du Colombier 	{KF|2,	0xffbf},
34f8e525acSDavid du Colombier 	{KF|3,	0xffc0},
35f8e525acSDavid du Colombier 	{KF|4,	0xffc1},
36f8e525acSDavid du Colombier 	{KF|5,	0xffc2},
37f8e525acSDavid du Colombier 	{KF|6,	0xffc3},
38f8e525acSDavid du Colombier 	{KF|7,	0xffc4},
39f8e525acSDavid du Colombier 	{KF|8,	0xffc5},
40f8e525acSDavid du Colombier 	{KF|9,	0xffc6},
41f8e525acSDavid du Colombier 	{KF|10,	0xffc7},
42f8e525acSDavid du Colombier 	{KF|11,	0xffc8},
43f8e525acSDavid du Colombier 	{KF|12,	0xffc9},
44f8e525acSDavid du Colombier };
45f8e525acSDavid du Colombier 
467a02f3c0SDavid du Colombier static char shiftkey[128] = {
477a02f3c0SDavid du Colombier 	0, 0, 0, 0, 0, 0, 0, 0, /* nul soh stx etx eot enq ack bel */
487a02f3c0SDavid du Colombier 	0, 0, 0, 0, 0, 0, 0, 0, /* bs ht nl vt np cr so si */
497a02f3c0SDavid du Colombier 	0, 0, 0, 0, 0, 0, 0, 0, /* dle dc1 dc2 dc3 dc4 nak syn etb */
507a02f3c0SDavid du Colombier 	0, 0, 0, 0, 0, 0, 0, 0, /* can em sub esc fs gs rs us */
517a02f3c0SDavid du Colombier 	0, 1, 1, 1, 1, 1, 1, 0, /* sp ! " # $ % & ' */
527a02f3c0SDavid du Colombier 	1, 1, 1, 1, 0, 0, 0, 0, /* ( ) * + , - . / */
537a02f3c0SDavid du Colombier 	0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
547a02f3c0SDavid du Colombier 	0, 0, 1, 0, 1, 0, 1, 1, /* 8 9 : ; < = > ? */
557a02f3c0SDavid du Colombier 	1, 1, 1, 1, 1, 1, 1, 1, /* @ A B C D E F G */
567a02f3c0SDavid du Colombier 	1, 1, 1, 1, 1, 1, 1, 1, /* H I J K L M N O */
577a02f3c0SDavid du Colombier 	1, 1, 1, 1, 1, 1, 1, 1, /* P Q R S T U V W */
587a02f3c0SDavid du Colombier 	1, 1, 1, 0, 0, 0, 1, 1, /* X Y Z [ \ ] ^ _ */
597a02f3c0SDavid du Colombier 	0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
607a02f3c0SDavid du Colombier 	0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
617a02f3c0SDavid du Colombier 	0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
627a02f3c0SDavid du Colombier 	0, 0, 0, 1, 1, 1, 1, 0, /* x y z { | } ~ del  */
637a02f3c0SDavid du Colombier };
647a02f3c0SDavid du Colombier 
65f8e525acSDavid du Colombier ulong
runetoksym(Rune r)66f8e525acSDavid du Colombier runetoksym(Rune r)
67f8e525acSDavid du Colombier {
68f8e525acSDavid du Colombier 	int i;
69f8e525acSDavid du Colombier 
70f8e525acSDavid du Colombier 	for(i=0; i<nelem(ktab); i++)
71f8e525acSDavid du Colombier 		if(ktab[i].kbdc == r)
72f8e525acSDavid du Colombier 			return ktab[i].keysym;
73f8e525acSDavid du Colombier 	return r;
74f8e525acSDavid du Colombier }
75f8e525acSDavid du Colombier 
76f8e525acSDavid du Colombier static void
keyevent(Vnc * v,ulong ksym,int down)77f8e525acSDavid du Colombier keyevent(Vnc *v, ulong ksym, int down)
78f8e525acSDavid du Colombier {
79f8e525acSDavid du Colombier 	vnclock(v);
80f8e525acSDavid du Colombier 	vncwrchar(v, MKey);
81f8e525acSDavid du Colombier 	vncwrchar(v, down);
82f8e525acSDavid du Colombier 	vncwrshort(v, 0);
83f8e525acSDavid du Colombier 	vncwrlong(v, ksym);
84f8e525acSDavid du Colombier 	vncflush(v);
85f8e525acSDavid du Colombier 	vncunlock(v);
86f8e525acSDavid du Colombier }
87f8e525acSDavid du Colombier 
88f8e525acSDavid du Colombier void
readkbd(Vnc * v)89f8e525acSDavid du Colombier readkbd(Vnc *v)
90f8e525acSDavid du Colombier {
91f8e525acSDavid du Colombier 	char buf[256], k[10];
92ebe1d0a8SDavid du Colombier 	ulong ks;
93ebe1d0a8SDavid du Colombier 	int ctlfd, fd, kr, kn, w, shift, ctl, alt;
94f8e525acSDavid du Colombier 	Rune r;
95f8e525acSDavid du Colombier 
96f8e525acSDavid du Colombier 	snprint(buf, sizeof buf, "%s/cons", display->devdir);
97f8e525acSDavid du Colombier 	if((fd = open(buf, OREAD)) < 0)
98f8e525acSDavid du Colombier 		sysfatal("open %s: %r", buf);
99f8e525acSDavid du Colombier 
100f8e525acSDavid du Colombier 	snprint(buf, sizeof buf, "%s/consctl", display->devdir);
101f8e525acSDavid du Colombier 	if((ctlfd = open(buf, OWRITE)) < 0)
102f8e525acSDavid du Colombier 		sysfatal("open %s: %r", buf);
103f8e525acSDavid du Colombier 	write(ctlfd, "rawon", 5);
104f8e525acSDavid du Colombier 
105f8e525acSDavid du Colombier 	kn = 0;
106f8e525acSDavid du Colombier 	shift = alt = ctl = 0;
107f8e525acSDavid du Colombier 	for(;;){
108f8e525acSDavid du Colombier 		while(!fullrune(k, kn)){
109f8e525acSDavid du Colombier 			kr = read(fd, k+kn, sizeof k - kn);
110f8e525acSDavid du Colombier 			if(kr <= 0)
111*14cc0f53SDavid du Colombier 				sysfatal("bad read from kbd");
112f8e525acSDavid du Colombier 			kn += kr;
113f8e525acSDavid du Colombier 		}
114f8e525acSDavid du Colombier 		w = chartorune(&r, k);
115f8e525acSDavid du Colombier 		kn -= w;
116f8e525acSDavid du Colombier 		memmove(k, &k[w], kn);
117f8e525acSDavid du Colombier 		ks = runetoksym(r);
118f8e525acSDavid du Colombier 
119f8e525acSDavid du Colombier 		switch(r){
120f8e525acSDavid du Colombier 		case Kalt:
121f8e525acSDavid du Colombier 			alt = !alt;
122f8e525acSDavid du Colombier 			keyevent(v, Xalt, alt);
123f8e525acSDavid du Colombier 			break;
124f8e525acSDavid du Colombier 		case Kctl:
125f8e525acSDavid du Colombier 			ctl = !ctl;
126f8e525acSDavid du Colombier 			keyevent(v, Xctl, ctl);
127f8e525acSDavid du Colombier 			break;
128f8e525acSDavid du Colombier 		case Kshift:
129f8e525acSDavid du Colombier 			shift = !shift;
130f8e525acSDavid du Colombier 			keyevent(v, Xshift, shift);
131f8e525acSDavid du Colombier 			break;
132f8e525acSDavid du Colombier 		default:
133f8e525acSDavid du Colombier 			if(r == ks && r < 0x1A){	/* control key */
134f8e525acSDavid du Colombier 				keyevent(v, Xctl, 1);
135f8e525acSDavid du Colombier 				keyevent(v, r+0x60, 1);	/* 0x60: make capital letter */
136f8e525acSDavid du Colombier 				keyevent(v, r+0x60, 0);
137f8e525acSDavid du Colombier 				keyevent(v, Xctl, 0);
138f8e525acSDavid du Colombier 			}else{
1397a02f3c0SDavid du Colombier 				/*
1407a02f3c0SDavid du Colombier 				 * to send an upper case letter or shifted
1417a02f3c0SDavid du Colombier 				 * punctuation, mac os x vnc server,
1427a02f3c0SDavid du Colombier 				 * at least, needs a `shift' sent first.
143f8e525acSDavid du Colombier 				 */
1447a02f3c0SDavid du Colombier 				if(!shift && r == ks && r < sizeof shiftkey && shiftkey[r]){
1457a02f3c0SDavid du Colombier 					shift = 1;
1467a02f3c0SDavid du Colombier 					keyevent(v, Xshift, 1);
1477a02f3c0SDavid du Colombier 				}
148ebe1d0a8SDavid du Colombier 				/*
149ebe1d0a8SDavid du Colombier 				 * map an xkeysym onto a utf-8 char.
150ebe1d0a8SDavid du Colombier 				 * allows Xvnc to read us, see utf2ksym.h
151ebe1d0a8SDavid du Colombier 				 */
152ebe1d0a8SDavid du Colombier 				if((ks & 0xff00) && ks < nelem(utf2ksym) && utf2ksym[ks] != 0)
153ebe1d0a8SDavid du Colombier 					ks = utf2ksym[ks];
1547a02f3c0SDavid du Colombier 				keyevent(v, ks, 1);
1557a02f3c0SDavid du Colombier 				/*
1567a02f3c0SDavid du Colombier 				 * up event needed by vmware inside linux vnc server,
1577a02f3c0SDavid du Colombier 				 * perhaps others.
1587a02f3c0SDavid du Colombier 				 */
1597a02f3c0SDavid du Colombier 				keyevent(v, ks, 0);
160f8e525acSDavid du Colombier 			}
161f8e525acSDavid du Colombier 
162f8e525acSDavid du Colombier 			if(alt){
163f8e525acSDavid du Colombier 				keyevent(v, Xalt, 0);
164f8e525acSDavid du Colombier 				alt = 0;
165f8e525acSDavid du Colombier 			}
166f8e525acSDavid du Colombier 			if(ctl){
167f8e525acSDavid du Colombier 				keyevent(v, Xctl, 0);
168f8e525acSDavid du Colombier 				ctl = 0;
169f8e525acSDavid du Colombier 			}
170f8e525acSDavid du Colombier 			if(shift){
171f8e525acSDavid du Colombier 				keyevent(v, Xshift, 0);
172f8e525acSDavid du Colombier 				shift = 0;
173f8e525acSDavid du Colombier 			}
174f8e525acSDavid du Colombier 			break;
175f8e525acSDavid du Colombier 		}
176f8e525acSDavid du Colombier 	}
177f8e525acSDavid du Colombier }
178f8e525acSDavid du Colombier 
179