]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/bitsy/keyboard.c
sshfs: usage
[plan9front.git] / sys / src / cmd / bitsy / keyboard.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <draw.h>
5 #include <mouse.h>
6 #include <keyboard.h>
7 #include <control.h>
8 #include <scribble.h>
9
10 int debug = 0;
11 typedef struct Win Win;
12 struct Win {
13         int n;
14         int dirty;
15         char *label;
16         Control *button;
17 };
18
19 Win *win;
20 int nwin;
21 int mwin;
22 int onwin;
23 int rows, cols;
24 int kbdonly;
25 int scribbleleft;
26 int winshow;
27
28 Channel *kc;
29 Channel *ec;
30 Channel *tc;
31 Rectangle rk, rs, rw;
32 Font *keyfont, *keyctlfont;
33
34 enum{
35         Back,
36         Shade,
37         Light,
38         Mask,
39         Ncol
40 };
41
42 enum {
43         kbdheight = 2 + 5*13,
44 };
45
46 enum {
47         Keyback         = 0xeeee9eff,
48         Keyshade                = 0xaaaa55ff,
49         Keylight                = DWhite,
50         Keymask         = 0x0C0C0C0C,
51 };
52
53 Image   *colors[Ncol];
54
55 Control *kbd;
56 Control *scrib;
57 Control *boxbox;
58 Controlset *cs;
59
60 int     ctldeletequits = 1;
61 int     wctl;
62
63 int
64 hidden(void)
65 {
66         char buf[128];
67         int n;
68
69         close(wctl);
70         if ((wctl = open("/dev/wctl", ORDWR)) < 0)
71                 return 0;
72         n = read(wctl, buf, sizeof buf-1);
73         if (n <= 0)
74                 sysfatal("wctl read: %r");
75         buf[n] = 0;
76         return strstr(buf, "visible") == nil;
77 }
78
79 void
80 mousemux(void *v)
81 {
82         Mouse m;
83         Channel *c;
84         int ob;
85
86         c = v;
87
88         for(ob = 0;;ob = m.buttons){
89                 if(recv(c, &m) < 0)
90                         break;
91                 if ((m.buttons & 0x20) == 0) {
92                         if (ob & 0x20) {
93                                 /* hide button just came up */
94                                 if (hidden()) {
95                                         if (debug) fprint(2, "unhide");
96                                         if (fprint(wctl, "unhide") <= 0)
97                                                 fprint(2, "unhide failed: %r\n");
98                                 } else {
99                                         if (debug) fprint(2, "hide");
100                                         if (fprint(wctl, "hide") <= 0)
101                                                 fprint(2, "hide failed: %r\n");
102                                 }
103                         } else
104                                 send(cs->mousec, &m);
105                 }
106         }
107 }
108
109 void
110 refreshwin(void)
111 {
112         char label[128];
113         int i, fd, lfd, n, nr, nw, m;
114         Dir *pd;
115
116         if((fd = open("/dev/wsys", OREAD)) < 0)
117                 return;
118
119         nw = 0;
120 /* i'd rather read one at a time but rio won't let me */
121         while((nr=dirread(fd, &pd)) > 0){
122                 for(i=0; i<nr; i++){
123                         n = atoi(pd[i].name);
124                         sprint(label, "/dev/wsys/%d/label", n);
125                         if((lfd = open(label, OREAD)) < 0)
126                                 continue;
127                         m = read(lfd, label, sizeof(label)-1);
128                         close(lfd);
129                         if(m < 0)
130                                 continue;
131                         label[m] = '\0';
132                         if(nw < nwin && win[nw].n == n && strcmp(win[nw].label, label)==0){
133                                 nw++;
134                                 continue;
135                         }
136
137                         if(nw < nwin){
138                                 free(win[nw].label);
139                                 win[nw].label = nil;
140                         }
141                         if(nw >= mwin){
142                                 mwin += 8;
143                                 win = ctlrealloc(win, mwin*sizeof(win[0]));
144                                 memset(&win[mwin-8], 0, 8*sizeof(win[0]));
145                         }
146                         win[nw].n = n;
147                         win[nw].label = ctlstrdup(label);
148                         win[nw].dirty = 1;
149                         sprint(label, "%d", nw);
150                         if (win[nw].button == nil){
151                                 win[nw].button = createtextbutton(cs, label);
152                                 chanprint(cs->ctl, "%q font keyfont", label);
153                                 chanprint(cs->ctl, "%q image keyback", label);
154                                 chanprint(cs->ctl, "%q pressedtextcolor red", label);
155                                 chanprint(cs->ctl, "%q mask transparent", label);
156                                 chanprint(cs->ctl, "%q border 1", label);
157                                 chanprint(cs->ctl, "%q bordercolor black", label);
158                                 chanprint(cs->ctl, "%q align centerleft", label);
159                                 chanprint(cs->ctl, "%q size 16 %d 512 %d", label, keyfont->height+2, keyfont->height+2);
160                                 controlwire(win[nw].button, "event", ec);
161                         }
162                         if (nw >= nwin){
163                                 activate(win[nw].button);
164                                 chanprint(cs->ctl, "cols add %q", label);
165                         }
166                         chanprint(cs->ctl, "%q text %q", win[nw].button->name, win[nw].label);
167                         nw++;
168                 }
169         }
170         for(i = nw; i < nwin; i++){
171                 free(win[i].label);
172                 win[i].label = nil;
173                 deactivate(win[i].button);
174                 chanprint(cs->ctl, "cols remove %q", win[i].button->name);
175         }
176         nwin = nw;
177         close(fd);
178         if (rw.max.x)
179                 chanprint(cs->ctl, "cols rect %R\ncols show", rw);
180 }
181
182 void
183 resizecontrolset(Controlset*)
184 {
185         if(getwindow(display, Refnone) < 0)
186                 ctlerror("resize failed: %r");
187
188         if (hidden()) {
189                 if (debug) fprint(2, "resizecontrolset: hidden\n");
190                 return;
191         }
192
193         rk = screen->r;
194         if (winshow){
195                 rw = rk;
196                 rw.min.x = (3*rk.max.x + rk.min.x)/4;
197                 rk.max.x = rw.min.x;
198                 if (debug) fprint(2, "rw: rect %R\n", rw);
199                 chanprint(cs->ctl, "cols rect %R\ncols show", rw);
200         }
201         if (kbdonly) {
202                 chanprint(cs->ctl, "keyboard rect %R\nkeyboard show", rk);
203         } else {
204                 rs = rk;
205                 if (scribbleleft){
206                         rk.min.x = (rk.max.x + 3*rk.min.x)/4;
207                         rs.max.x = rk.min.x;
208                 }else{
209                         rk.max.x = (3*rk.max.x + rk.min.x)/4;
210                         rs.min.x = rk.max.x;
211                 }
212                 chanprint(cs->ctl, "keyboard rect %R\nkeyboard show", rk);
213                 if (debug) fprint(2, "rk: rect %R\nkeyboard show\n", rk);
214                 chanprint(cs->ctl, "scribble rect %R\nscribble show", rs);
215                 if (debug) fprint(2, "rs: rect %R\nscribble show\n", rs);
216         }
217 }
218
219 void
220 usage(void)
221 {
222         fprint(2, "usage: keyboard\n");
223         threadexitsall("usage");
224 }
225
226 void
227 timerproc(void*v)
228 {
229         Channel *c;
230
231         c = v;
232         for(;;){
233                 sleep(5000);
234                 sendul(c, 1);
235         }
236 }
237
238 void
239 watchproc(void*)
240 {
241
242         for(;;){}
243 }
244
245 void
246 threadmain(int argc, char *argv[])
247 {
248         int i, n, kbdfd;
249         char str[UTFmax+1];
250         Rune r;
251         Mousectl        *mousectl;
252         Channel *mtok;
253         char *e, buf[128], *args[8];
254         int fd;
255
256         ARGBEGIN{
257         case 'w':
258                 winshow++;
259                 break;
260         case 'l':
261                 scribbleleft++;
262                 break;
263         case 'n':
264                 kbdonly++;
265                 break;
266         case 'd':
267                 ScribbleDebug++;
268                 debug++;
269                 break;
270         default:
271                 usage();
272         }ARGEND
273
274         if(argc != 0)
275                 usage();
276
277         kbdfd = open("/dev/kbdin", OWRITE);
278         if (kbdfd < 0 && (kbdfd = open("#r/kbdin", OWRITE)) < 0) {
279                 if (debug) fprint(2, "open %s: %r\n", "#r/kbdin");
280                 kbdfd = 1;
281         }
282
283         initdraw(0, 0, "keyboard");
284         mousectl = initmouse(nil, screen);
285
286         wctl = open("/dev/wctl", ORDWR);
287         if (wctl < 0) {
288                 fprint(2, "open %s: %r\n", "/dev/wctl");
289                 wctl = 2;       /* for debugging */
290         }
291
292         mtok = chancreate(sizeof(Mouse), 0);
293
294         initcontrols();
295
296         cs = newcontrolset(screen, nil, mtok, mousectl->resizec);
297
298         threadcreate(mousemux, mousectl->c, 4096);
299
300         kc = chancreate(sizeof(char*), 0);
301         tc = chancreate(sizeof(int), 1);
302         ec = chancreate(sizeof(char*), 1);
303
304         colors[Back] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyback);
305         namectlimage(colors[Back], "keyback");
306         colors[Light] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keylight);
307         namectlimage(colors[Light], "keylight");
308         colors[Shade] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyshade);
309         namectlimage(colors[Shade], "keyshade");
310         colors[Mask] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, Keymask);
311         namectlimage(colors[Shade], "keymask");
312         keyfont = openfont(display, "/lib/font/bit/lucidasans/boldlatin1.6.font");
313         namectlfont(keyfont, "keyfont");
314         keyctlfont = openfont(display, "/lib/font/bit/lucidasans/unicode.6.font");
315         namectlfont(keyctlfont, "keyctlfont");
316
317         kbd = createkeyboard(cs, "keyboard");
318         chanprint(cs->ctl, "keyboard font keyfont keyctlfont");
319         chanprint(cs->ctl, "keyboard image keyback");
320         chanprint(cs->ctl, "keyboard light keylight");
321         chanprint(cs->ctl, "keyboard mask keymask");
322         chanprint(cs->ctl, "keyboard border 1");
323         chanprint(cs->ctl, "keyboard size %d %d %d %d", 246, 2 + 5 * (keyfont->height + 1), 512, 256);
324         controlwire(kbd, "event", kc);
325
326         if (kbdonly == 0){
327                 scrib = createscribble(cs, "scribble");
328                 if (scrib == nil)
329                         sysfatal("createscribble");
330                 chanprint(cs->ctl, "scribble font keyfont");
331                 chanprint(cs->ctl, "scribble image keyback");
332                 chanprint(cs->ctl, "scribble border 1");
333                 controlwire(scrib, "event", kc);
334         }
335
336         if (winshow){
337                 boxbox = createboxbox(cs, "cols");
338         
339                 chanprint(cs->ctl, "cols border 2");
340                 chanprint(cs->ctl, "cols bordercolor keyback");
341         }
342
343         resizecontrolset(nil);
344
345         activate(kbd);
346         if (kbdonly == 0)
347                 activate(scrib);
348         if (winshow){
349                 refreshwin();
350                 proccreate(timerproc, tc, 2048);
351         }
352
353         for(;;){
354                 Alt a[] = {
355                         { kc, &e, CHANRCV },
356                         { ec, &e, CHANRCV },
357                         { tc, &n, CHANRCV },
358                         { nil, nil, CHANEND }
359                 };
360                 switch(alt(a)){
361                 case 0: /* Keyboard */
362                         n = tokenize(e, args, nelem(args));
363                         if(n == 3)
364                         if(strcmp(args[0], "keyboard:")==0 || strcmp(args[0], "scribble:")==0)
365                         if(strcmp(args[1], "value") == 0){
366                                 n = strtol(args[2], 0, 0);
367                                 if(n <= Runemax){
368                                         r = n;
369                                         i = runetochar(str, &r);
370                                         write(kbdfd, str, i);
371                                 }
372                         }
373                         break;
374                 case 1: /* Button event */
375                         n = tokenize(e, args, nelem(args));
376                         if (n != 3 || strcmp(args[1], "value"))
377                                 sysfatal("event string");
378                         i = atoi(args[0]);
379                         if (i < 0 || i >= nwin)
380                                 sysfatal("win out of range: %d of %d", i, nwin);
381                         n = atoi(args[2]);
382                         if (n){
383                                 sprint(buf, "/dev/wsys/%d/wctl", win[i].n);
384                                 if((fd = open(buf, OWRITE)) >= 0){
385                                         while (write(fd, "top\n", 4) < 0) {
386                                                 /* wait until mouse comes up */
387                                                 rerrstr(buf, sizeof buf);
388                                                 if (strncmp(buf, "action disallowed when mouse active", sizeof buf)){
389                                                         fprint(2, "write top: %s\n", buf);
390                                                         break;
391                                                 }
392                                                 sleep(100);
393                                         }
394                                         if (write(fd, "current\n", 8) < 0)
395                                                 fprint(2, "write current: %r\n");
396                                         close(fd);
397                                 }
398                                 chanprint(cs->ctl, "%q value 0", win[i].button->name);
399                         }
400                         break;
401                 case 2:
402                         refreshwin();
403                         break;
404                 }
405         }
406 }