]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/bitsy/keyboard.c
9bootfat: rename open() to fileinit and make it static as its really a internal funct...
[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 r, 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         int fd;
186         char buf[61];
187
188
189         if(getwindow(display, Refnone) < 0)
190                 ctlerror("resize failed: %r");
191
192         if (hidden()) {
193                 if (debug) fprint(2, "resizecontrolset: hidden\n");
194                 return;
195         }
196
197         fd = open("/dev/screen", OREAD);
198         if (fd < 0) {
199                 r = display->image->r;
200                 if (debug) fprint(2, "display->imgae->r: %R\n", r);
201         } else {
202                 if (read(fd, buf, 60) != 60)
203                         sysfatal("resizecontrolset: read: /dev/screen: %r");
204                 close(fd);
205                 buf[60] = '\0';
206                 r.min.x = atoi(buf+1+1*12);
207                 r.min.y = atoi(buf+1+2*12);
208                 r.max.x = atoi(buf+1+3*12);
209                 r.max.y = atoi(buf+1+4*12);
210                 if (debug) fprint(2, "/dev/screen: %R\n", r);
211         }
212         r = insetrect(r, 4);
213         r.min.y = r.max.y - kbdheight - 2*Borderwidth;
214         if (debug) fprint(2, "before eqrect: %R\n", r);
215         if (eqrect(r, screen->r) == 0) {
216                 if (debug) fprint(2, "resizecontrolset: resize %R\n", r);
217                 if (fprint(wctl, "resize -r %R", insetrect(r, -4)) <= 0) {
218                         fprint(2, "resizecontrolset: resize failed\n");
219                 }
220                 return;
221         }
222
223         if (debug) fprint(2, "after eqrect: %R\n", r);
224         rk = r;
225         if (winshow){
226                 rw = rk;
227                 rw.min.x = (3*rk.max.x + rk.min.x)/4;
228                 rk.max.x = rw.min.x;
229                 if (debug) fprint(2, "rw: rect %R\n", rw);
230                 chanprint(cs->ctl, "cols rect %R\ncols show", rw);
231         }
232         if (kbdonly) {
233                 chanprint(cs->ctl, "keyboard rect %R\nkeyboard show", rk);
234         } else {
235                 rs = rk;
236                 if (scribbleleft){
237                         rk.min.x = (rk.max.x + 3*rk.min.x)/4;
238                         rs.max.x = rk.min.x;
239                 }else{
240                         rk.max.x = (3*rk.max.x + rk.min.x)/4;
241                         rs.min.x = rk.max.x;
242                 }
243                 chanprint(cs->ctl, "keyboard rect %R\nkeyboard show", rk);
244                 if (debug) fprint(2, "rk: rect %R\nkeyboard show\n", rk);
245                 chanprint(cs->ctl, "scribble rect %R\nscribble show", rs);
246                 if (debug) fprint(2, "rs: rect %R\nscribble show\n", rs);
247         }
248 }
249
250 void
251 usage(void)
252 {
253         fprint(2, "usage: keyboard\n");
254         threadexitsall("usage");
255 }
256
257 void
258 timerproc(void*v)
259 {
260         Channel *c;
261
262         c = v;
263         for(;;){
264                 sleep(5000);
265                 sendul(c, 1);
266         }
267 }
268
269 void
270 watchproc(void*)
271 {
272
273         for(;;){}
274 }
275
276 void
277 threadmain(int argc, char *argv[])
278 {
279         int i, n, kbdfd;
280         char str[UTFmax+1];
281         Rune r;
282         Mousectl        *mousectl;
283         Channel *mtok;
284         char *e, buf[128], *args[8];
285         int fd;
286
287         ARGBEGIN{
288         case 'w':
289                 winshow++;
290                 break;
291         case 'l':
292                 scribbleleft++;
293                 break;
294         case 'n':
295                 kbdonly++;
296                 break;
297         case 'd':
298                 ScribbleDebug++;
299                 debug++;
300                 break;
301         default:
302                 usage();
303         }ARGEND
304
305         if(argc != 0)
306                 usage();
307
308         kbdfd = open("/dev/kbdin", OWRITE);
309         if (kbdfd < 0 && (kbdfd = open("#r/kbdin", OWRITE)) < 0) {
310                 if (debug) fprint(2, "open %s: %r\n", "#r/kbdin");
311                 kbdfd = 1;
312         }
313
314         initdraw(0, 0, "keyboard");
315         mousectl = initmouse(nil, screen);
316
317         wctl = open("/dev/wctl", ORDWR);
318         if (wctl < 0) {
319                 fprint(2, "open %s: %r\n", "/dev/wctl");
320                 wctl = 2;       /* for debugging */
321         }
322
323         mtok = chancreate(sizeof(Mouse), 0);
324
325         initcontrols();
326
327         cs = newcontrolset(screen, nil, mtok, mousectl->resizec);
328
329         threadcreate(mousemux, mousectl->c, 4096);
330
331         kc = chancreate(sizeof(char*), 0);
332         tc = chancreate(sizeof(int), 1);
333         ec = chancreate(sizeof(char*), 1);
334
335         colors[Back] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyback);
336         namectlimage(colors[Back], "keyback");
337         colors[Light] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keylight);
338         namectlimage(colors[Light], "keylight");
339         colors[Shade] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyshade);
340         namectlimage(colors[Shade], "keyshade");
341         colors[Mask] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, Keymask);
342         namectlimage(colors[Shade], "keymask");
343         keyfont = openfont(display, "/lib/font/bit/lucidasans/boldlatin1.6.font");
344         namectlfont(keyfont, "keyfont");
345         keyctlfont = openfont(display, "/lib/font/bit/lucidasans/unicode.6.font");
346         namectlfont(keyctlfont, "keyctlfont");
347
348         kbd = createkeyboard(cs, "keyboard");
349         chanprint(cs->ctl, "keyboard font keyfont keyctlfont");
350         chanprint(cs->ctl, "keyboard image keyback");
351         chanprint(cs->ctl, "keyboard light keylight");
352         chanprint(cs->ctl, "keyboard mask keymask");
353         chanprint(cs->ctl, "keyboard border 1");
354         chanprint(cs->ctl, "keyboard size %d %d %d %d", 246, 2 + 5 * (keyfont->height + 1), 512, 256);
355         controlwire(kbd, "event", kc);
356
357         if (kbdonly == 0){
358                 scrib = createscribble(cs, "scribble");
359                 if (scrib == nil)
360                         sysfatal("createscribble");
361                 chanprint(cs->ctl, "scribble font keyfont");
362                 chanprint(cs->ctl, "scribble image keyback");
363                 chanprint(cs->ctl, "scribble border 1");
364                 controlwire(scrib, "event", kc);
365         }
366
367         if (winshow){
368                 boxbox = createboxbox(cs, "cols");
369         
370                 chanprint(cs->ctl, "cols border 2");
371                 chanprint(cs->ctl, "cols bordercolor keyback");
372         }
373
374         resizecontrolset(nil);
375
376         activate(kbd);
377         if (kbdonly == 0)
378                 activate(scrib);
379         if (winshow){
380                 refreshwin();
381                 proccreate(timerproc, tc, 2048);
382         }
383
384         for(;;){
385                 Alt a[] = {
386                         { kc, &e, CHANRCV },
387                         { ec, &e, CHANRCV },
388                         { tc, &n, CHANRCV },
389                         { nil, nil, CHANEND }
390                 };
391                 switch(alt(a)){
392                 case 0: /* Keyboard */
393                         n = tokenize(e, args, nelem(args));
394                         if(n == 3)
395                         if(strcmp(args[0], "keyboard:")==0 || strcmp(args[0], "scribble:")==0)
396                         if(strcmp(args[1], "value") == 0){
397                                 n = atoi(args[2]);
398                                 if(n <= 0xFFFF){
399                                         r = n;
400                                         i = runetochar(str, &r);
401                                         write(kbdfd, str, i);
402                                 }
403                         }
404                         break;
405                 case 1: /* Button event */
406                         n = tokenize(e, args, nelem(args));
407                         if (n != 3 || strcmp(args[1], "value"))
408                                 sysfatal("event string");
409                         i = atoi(args[0]);
410                         if (i < 0 || i >= nwin)
411                                 sysfatal("win out of range: %d of %d", i, nwin);
412                         n = atoi(args[2]);
413                         if (n){
414                                 sprint(buf, "/dev/wsys/%d/wctl", win[i].n);
415                                 if((fd = open(buf, OWRITE)) >= 0){
416                                         while (write(fd, "top\n", 4) < 0) {
417                                                 /* wait until mouse comes up */
418                                                 rerrstr(buf, sizeof buf);
419                                                 if (strncmp(buf, "action disallowed when mouse active", sizeof buf)){
420                                                         fprint(2, "write top: %s\n", buf);
421                                                         break;
422                                                 }
423                                                 sleep(100);
424                                         }
425                                         if (write(fd, "current\n", 8) < 0)
426                                                 fprint(2, "write current: %r\n");
427                                         close(fd);
428                                 }
429                                 chanprint(cs->ctl, "%q value 0", win[i].button->name);
430                         }
431                         break;
432                 case 2:
433                         refreshwin();
434                         break;
435                 }
436         }
437 }