]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/kbdv.c
vncs: /dev/kbd support by running kbdfs and forwarding keycodes thru kbdin
[plan9front.git] / sys / src / cmd / vnc / kbdv.c
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         {Kshift, Xshift},
46         {Kalt, Xalt},
47         {Kaltgr, Xmeta},
48         {Kctl, Xctl},
49 };
50
51 static char shiftkey[128] = {
52         0, 0, 0, 0, 0, 0, 0, 0, /* nul soh stx etx eot enq ack bel */
53         0, 0, 0, 0, 0, 0, 0, 0, /* bs ht nl vt np cr so si */
54         0, 0, 0, 0, 0, 0, 0, 0, /* dle dc1 dc2 dc3 dc4 nak syn etb */
55         0, 0, 0, 0, 0, 0, 0, 0, /* can em sub esc fs gs rs us */
56         0, 1, 1, 1, 1, 1, 1, 0, /* sp ! " # $ % & ' */
57         1, 1, 1, 1, 0, 0, 0, 0, /* ( ) * + , - . / */
58         0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
59         0, 0, 1, 0, 1, 0, 1, 1, /* 8 9 : ; < = > ? */
60         1, 1, 1, 1, 1, 1, 1, 1, /* @ A B C D E F G */
61         1, 1, 1, 1, 1, 1, 1, 1, /* H I J K L M N O */
62         1, 1, 1, 1, 1, 1, 1, 1, /* P Q R S T U V W */
63         1, 1, 1, 0, 0, 0, 1, 1, /* X Y Z [ \ ] ^ _ */
64         0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
65         0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
66         0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
67         0, 0, 0, 1, 1, 1, 1, 0, /* x y z { | } ~ del  */
68 };
69
70 ulong
71 runetoksym(Rune r)
72 {
73         int i;
74
75         for(i=0; i<nelem(ktab); i++)
76                 if(ktab[i].kbdc == r)
77                         return ktab[i].keysym;
78         return r;
79 }
80
81 static void
82 keyevent(Vnc *v, ulong ksym, int down)
83 {
84         vnclock(v);
85         vncwrchar(v, MKey);
86         vncwrchar(v, down);
87         vncwrshort(v, 0);
88         vncwrlong(v, ksym);
89         vncflush(v);
90         vncunlock(v);
91 }
92
93 static void
94 readcons(Vnc *v)
95 {
96         char buf[256], k[10];
97         ulong ks;
98         int ctlfd, fd, kr, kn, w, shift, ctl, alt;
99         Rune r;
100
101         snprint(buf, sizeof buf, "%s/cons", display->devdir);
102         if((fd = open(buf, OREAD)) < 0)
103                 sysfatal("open %s: %r", buf);
104
105         snprint(buf, sizeof buf, "%s/consctl", display->devdir);
106         if((ctlfd = open(buf, OWRITE)) < 0)
107                 sysfatal("open %s: %r", buf);
108         write(ctlfd, "rawon", 5);
109
110         kn = 0;
111         shift = alt = ctl = 0;
112         for(;;){
113                 while(!fullrune(k, kn)){
114                         kr = read(fd, k+kn, sizeof k - kn);
115                         if(kr <= 0)
116                                 sysfatal("bad read from kbd");
117                         kn += kr;
118                 }
119                 w = chartorune(&r, k);
120                 kn -= w;
121                 memmove(k, &k[w], kn);
122                 ks = runetoksym(r);
123
124                 switch(r){
125                 case Kalt:
126                         alt = !alt;
127                         keyevent(v, Xalt, alt);
128                         break;
129                 case Kctl:
130                         ctl = !ctl;
131                         keyevent(v, Xctl, ctl);
132                         break;
133                 case Kshift:
134                         shift = !shift;
135                         keyevent(v, Xshift, shift);
136                         break;
137                 default:
138                         if(r == ks && r < 0x1A){        /* control key */
139                                 keyevent(v, Xctl, 1);
140                                 keyevent(v, r+0x60, 1); /* 0x60: make capital letter */
141                                 keyevent(v, r+0x60, 0);
142                                 keyevent(v, Xctl, 0);
143                         }else{
144                                 /*
145                                  * to send an upper case letter or shifted
146                                  * punctuation, mac os x vnc server,
147                                  * at least, needs a `shift' sent first.
148                                  */
149                                 if(!shift && r == ks && r < sizeof shiftkey && shiftkey[r]){
150                                         shift = 1;
151                                         keyevent(v, Xshift, 1);
152                                 }
153                                 /*
154                                  * map an xkeysym onto a utf-8 char.
155                                  * allows Xvnc to read us, see utf2ksym.h
156                                  */
157                                 if((ks & 0xff00) && ks < nelem(utf2ksym) && utf2ksym[ks] != 0)
158                                         ks = utf2ksym[ks];
159                                 keyevent(v, ks, 1);
160                                 /*
161                                  * up event needed by vmware inside linux vnc server,
162                                  * perhaps others.
163                                  */
164                                 keyevent(v, ks, 0);
165                         }
166
167                         if(alt){
168                                 keyevent(v, Xalt, 0);
169                                 alt = 0;
170                         }
171                         if(ctl){
172                                 keyevent(v, Xctl, 0);
173                                 ctl = 0;
174                         }
175                         if(shift){
176                                 keyevent(v, Xshift, 0);
177                                 shift = 0;
178                         }
179                         break;
180                 }
181         }
182 }
183
184 ulong
185 runetovnc(Rune r)
186 {
187         ulong k;
188
189         k = runetoksym(r);
190         if((k & 0xff00) && k < nelem(utf2ksym) && utf2ksym[k] != 0)
191                 k = utf2ksym[k];
192         return k;
193 }
194
195 void
196 readkbd(Vnc *v)
197 {
198         char buf[128], buf2[128], *s;
199         int fd, n;
200         Rune r;
201
202         if((fd = open("/dev/kbd", OREAD)) < 0){
203                 readcons(v);
204                 return;
205         }
206         buf2[0] = 0;
207         buf2[1] = 0;
208         while((n = read(fd, buf, sizeof(buf))) > 0){
209                 buf[n-1] = 0;
210                 switch(buf[0]){
211                 case 'k':
212                         s = buf+1;
213                         while(*s){
214                                 s += chartorune(&r, s);
215                                 if(utfrune(buf2+1, r) == nil)
216                                         if((r == Kshift) ||
217                                            utfrune(buf+1, Kctl) || 
218                                            utfrune(buf+1, Kalt) ||
219                                            utfrune(buf+1, Kaltgr))
220                                                 keyevent(v, runetovnc(r), 1);
221                         }
222                         break;
223                 case 'K':
224                         s = buf2+1;
225                         while(*s){
226                                 s += chartorune(&r, s);
227                                 if(utfrune(buf+1, r) == nil)
228                                         keyevent(v, runetovnc(r), 0);
229                         }
230                         break;
231                 case 'c':
232                         if(utfrune(buf2+1, Kctl) || utfrune(buf2+1, Kalt) || utfrune(buf2+1, Kaltgr))
233                                 continue;
234                         chartorune(&r, buf+1);
235                         keyevent(v, runetovnc(r), 1);
236                         if(utfrune(buf2+1, r) == nil)
237                                 keyevent(v, runetovnc(r), 0);
238                 default:
239                         continue;
240                 }
241                 strcpy(buf2, buf);
242         }
243 }
244