ref: 6540a9a21ae4f62f512f3e95063561d87e80701c
dir: /sys/src/cmd/bitsy/keyboard.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <draw.h> #include <mouse.h> #include <keyboard.h> #include <control.h> #include <scribble.h> int debug = 0; typedef struct Win Win; struct Win { int n; int dirty; char *label; Control *button; }; Win *win; int nwin; int mwin; int onwin; int rows, cols; int kbdonly; int scribbleleft; int winshow; Channel *kc; Channel *ec; Channel *tc; Rectangle rk, rs, rw; Font *keyfont, *keyctlfont; enum{ Back, Shade, Light, Mask, Ncol }; enum { kbdheight = 2 + 5*13, }; enum { Keyback = 0xeeee9eff, Keyshade = 0xaaaa55ff, Keylight = DWhite, Keymask = 0x0C0C0C0C, }; Image *colors[Ncol]; Control *kbd; Control *scrib; Control *boxbox; Controlset *cs; int ctldeletequits = 1; int wctl; int hidden(void) { char buf[128]; int n; close(wctl); if ((wctl = open("/dev/wctl", ORDWR)) < 0) return 0; n = read(wctl, buf, sizeof buf-1); if (n <= 0) sysfatal("wctl read: %r"); buf[n] = 0; return strstr(buf, "visible") == nil; } void mousemux(void *v) { Mouse m; Channel *c; int ob; c = v; for(ob = 0;;ob = m.buttons){ if(recv(c, &m) < 0) break; if ((m.buttons & 0x20) == 0) { if (ob & 0x20) { /* hide button just came up */ if (hidden()) { if (debug) fprint(2, "unhide"); if (fprint(wctl, "unhide") <= 0) fprint(2, "unhide failed: %r\n"); } else { if (debug) fprint(2, "hide"); if (fprint(wctl, "hide") <= 0) fprint(2, "hide failed: %r\n"); } } else send(cs->mousec, &m); } } } void refreshwin(void) { char label[128]; int i, fd, lfd, n, nr, nw, m; Dir *pd; if((fd = open("/dev/wsys", OREAD)) < 0) return; nw = 0; /* i'd rather read one at a time but rio won't let me */ while((nr=dirread(fd, &pd)) > 0){ for(i=0; i<nr; i++){ n = atoi(pd[i].name); sprint(label, "/dev/wsys/%d/label", n); if((lfd = open(label, OREAD)) < 0) continue; m = read(lfd, label, sizeof(label)-1); close(lfd); if(m < 0) continue; label[m] = '\0'; if(nw < nwin && win[nw].n == n && strcmp(win[nw].label, label)==0){ nw++; continue; } if(nw < nwin){ free(win[nw].label); win[nw].label = nil; } if(nw >= mwin){ mwin += 8; win = ctlrealloc(win, mwin*sizeof(win[0])); memset(&win[mwin-8], 0, 8*sizeof(win[0])); } win[nw].n = n; win[nw].label = ctlstrdup(label); win[nw].dirty = 1; sprint(label, "%d", nw); if (win[nw].button == nil){ win[nw].button = createtextbutton(cs, label); chanprint(cs->ctl, "%q font keyfont", label); chanprint(cs->ctl, "%q image keyback", label); chanprint(cs->ctl, "%q pressedtextcolor red", label); chanprint(cs->ctl, "%q mask transparent", label); chanprint(cs->ctl, "%q border 1", label); chanprint(cs->ctl, "%q bordercolor black", label); chanprint(cs->ctl, "%q align centerleft", label); chanprint(cs->ctl, "%q size 16 %d 512 %d", label, keyfont->height+2, keyfont->height+2); controlwire(win[nw].button, "event", ec); } if (nw >= nwin){ activate(win[nw].button); chanprint(cs->ctl, "cols add %q", label); } chanprint(cs->ctl, "%q text %q", win[nw].button->name, win[nw].label); nw++; } } for(i = nw; i < nwin; i++){ free(win[i].label); win[i].label = nil; deactivate(win[i].button); chanprint(cs->ctl, "cols remove %q", win[i].button->name); } nwin = nw; close(fd); if (rw.max.x) chanprint(cs->ctl, "cols rect %R\ncols show", rw); } void resizecontrolset(Controlset*) { if(getwindow(display, Refnone) < 0) ctlerror("resize failed: %r"); if (hidden()) { if (debug) fprint(2, "resizecontrolset: hidden\n"); return; } rk = screen->r; if (winshow){ rw = rk; rw.min.x = (3*rk.max.x + rk.min.x)/4; rk.max.x = rw.min.x; if (debug) fprint(2, "rw: rect %R\n", rw); chanprint(cs->ctl, "cols rect %R\ncols show", rw); } if (kbdonly) { chanprint(cs->ctl, "keyboard rect %R\nkeyboard show", rk); } else { rs = rk; if (scribbleleft){ rk.min.x = (rk.max.x + 3*rk.min.x)/4; rs.max.x = rk.min.x; }else{ rk.max.x = (3*rk.max.x + rk.min.x)/4; rs.min.x = rk.max.x; } chanprint(cs->ctl, "keyboard rect %R\nkeyboard show", rk); if (debug) fprint(2, "rk: rect %R\nkeyboard show\n", rk); chanprint(cs->ctl, "scribble rect %R\nscribble show", rs); if (debug) fprint(2, "rs: rect %R\nscribble show\n", rs); } } void usage(void) { fprint(2, "usage: keyboard\n"); threadexitsall("usage"); } void timerproc(void*v) { Channel *c; c = v; for(;;){ sleep(5000); sendul(c, 1); } } void watchproc(void*) { for(;;){} } void threadmain(int argc, char *argv[]) { int i, n, kbdfd; char str[UTFmax+1]; Rune r; Mousectl *mousectl; Channel *mtok; char *e, buf[128], *args[8]; int fd; ARGBEGIN{ case 'w': winshow++; break; case 'l': scribbleleft++; break; case 'n': kbdonly++; break; case 'd': ScribbleDebug++; debug++; break; default: usage(); }ARGEND if(argc != 0) usage(); kbdfd = open("/dev/kbdin", OWRITE); if (kbdfd < 0 && (kbdfd = open("#r/kbdin", OWRITE)) < 0) { if (debug) fprint(2, "open %s: %r\n", "#r/kbdin"); kbdfd = 1; } initdraw(0, 0, "keyboard"); mousectl = initmouse(nil, screen); wctl = open("/dev/wctl", ORDWR); if (wctl < 0) { fprint(2, "open %s: %r\n", "/dev/wctl"); wctl = 2; /* for debugging */ } mtok = chancreate(sizeof(Mouse), 0); initcontrols(); cs = newcontrolset(screen, nil, mtok, mousectl->resizec); threadcreate(mousemux, mousectl->c, 4096); kc = chancreate(sizeof(char*), 0); tc = chancreate(sizeof(int), 1); ec = chancreate(sizeof(char*), 1); colors[Back] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyback); namectlimage(colors[Back], "keyback"); colors[Light] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keylight); namectlimage(colors[Light], "keylight"); colors[Shade] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyshade); namectlimage(colors[Shade], "keyshade"); colors[Mask] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, Keymask); namectlimage(colors[Shade], "keymask"); keyfont = openfont(display, "/lib/font/bit/lucidasans/boldlatin1.6.font"); namectlfont(keyfont, "keyfont"); keyctlfont = openfont(display, "/lib/font/bit/lucidasans/unicode.6.font"); namectlfont(keyctlfont, "keyctlfont"); kbd = createkeyboard(cs, "keyboard"); chanprint(cs->ctl, "keyboard font keyfont keyctlfont"); chanprint(cs->ctl, "keyboard image keyback"); chanprint(cs->ctl, "keyboard light keylight"); chanprint(cs->ctl, "keyboard mask keymask"); chanprint(cs->ctl, "keyboard border 1"); chanprint(cs->ctl, "keyboard size %d %d %d %d", 246, 2 + 5 * (keyfont->height + 1), 512, 256); controlwire(kbd, "event", kc); if (kbdonly == 0){ scrib = createscribble(cs, "scribble"); if (scrib == nil) sysfatal("createscribble"); chanprint(cs->ctl, "scribble font keyfont"); chanprint(cs->ctl, "scribble image keyback"); chanprint(cs->ctl, "scribble border 1"); controlwire(scrib, "event", kc); } if (winshow){ boxbox = createboxbox(cs, "cols"); chanprint(cs->ctl, "cols border 2"); chanprint(cs->ctl, "cols bordercolor keyback"); } resizecontrolset(nil); activate(kbd); if (kbdonly == 0) activate(scrib); if (winshow){ refreshwin(); proccreate(timerproc, tc, 2048); } for(;;){ Alt a[] = { { kc, &e, CHANRCV }, { ec, &e, CHANRCV }, { tc, &n, CHANRCV }, { nil, nil, CHANEND } }; switch(alt(a)){ case 0: /* Keyboard */ n = tokenize(e, args, nelem(args)); if(n == 3) if(strcmp(args[0], "keyboard:")==0 || strcmp(args[0], "scribble:")==0) if(strcmp(args[1], "value") == 0){ n = strtol(args[2], 0, 0); if(n <= Runemax){ r = n; i = runetochar(str, &r); write(kbdfd, str, i); } } break; case 1: /* Button event */ n = tokenize(e, args, nelem(args)); if (n != 3 || strcmp(args[1], "value")) sysfatal("event string"); i = atoi(args[0]); if (i < 0 || i >= nwin) sysfatal("win out of range: %d of %d", i, nwin); n = atoi(args[2]); if (n){ sprint(buf, "/dev/wsys/%d/wctl", win[i].n); if((fd = open(buf, OWRITE)) >= 0){ while (write(fd, "top\n", 4) < 0) { /* wait until mouse comes up */ rerrstr(buf, sizeof buf); if (strncmp(buf, "action disallowed when mouse active", sizeof buf)){ fprint(2, "write top: %s\n", buf); break; } sleep(100); } if (write(fd, "current\n", 8) < 0) fprint(2, "write current: %r\n"); close(fd); } chanprint(cs->ctl, "%q value 0", win[i].button->name); } break; case 2: refreshwin(); break; } } }