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