ref: b57dba67153279a84a16bba40ae007c8ae710056
dir: /musw.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <draw.h> #include <mouse.h> #include <keyboard.h> #include "libgeometry/geometry.h" #include "dat.h" #include "fns.h" typedef struct Keymap Keymap; struct Keymap { Rune key; KeyOp op; }; Keymap kmap[] = { {.key = Kup, .op = K↑}, {.key = Kleft, .op = K↺}, {.key = Kright, .op = K↻}, {.key = 'w', .op = K↑}, {.key = 'a', .op = K↺}, {.key = 'd', .op = K↻}, {.key = ' ', .op = Kfire}, {.key = 'h', .op = Khyper}, {.key = 'y', .op = Ksay}, {.key = 'q', .op = Kquit} }; ulong kup, kdown; typedef struct Ball Ball; struct Ball { Point2 p, v; }; Ball bouncer; char winspec[32]; int debug; void kbdproc(void *) { Rune r; Keymap *k; char buf[128], *s; int fd, n; threadsetname("kbdproc"); if((fd = open("/dev/kbd", OREAD)) < 0) sysfatal("kbdproc: %r"); memset(buf, 0, sizeof buf); for(;;){ if(buf[0] != 0){ n = strlen(buf)+1; memmove(buf, buf+n, sizeof(buf)-n); } if(buf[0] == 0){ if((n = read(fd, buf, sizeof(buf)-1)) <= 0) break; buf[n-1] = 0; buf[n] = 0; } if(buf[0] == 'c'){ if(utfrune(buf, Kdel)){ close(fd); threadexitsall(nil); } } if(buf[0] != 'k' && buf[0] != 'K') continue; s = buf+1; kdown = 0; while(*s){ s += chartorune(&r, s); for(k = kmap; k < kmap+nelem(kmap); k++) if(r == k->key){ kdown |= 1 << k->op; break; } } kup = ~kdown; if(debug) fprint(2, "kup %.*lub\nkdown %.*lub\n", sizeof(kup)*8, kup, sizeof(kdown)*8, kdown); } } void threadnetrecv(void *arg) { uchar buf[256]; int fd, n; Ioproc *io; fd = *((int*)arg); io = ioproc(); while((n = ioread(io, fd, buf, sizeof buf)) > 0){ unpack(buf, n, "PP", &bouncer.p, &bouncer.v); if(debug) fprint(2, "bouncer %v %v\n", bouncer.p, bouncer.v); } closeioproc(io); } void resize(void); void threadresize(void *arg) { Mousectl *mc; Alt a[3]; mc = arg; a[0].op = CHANRCV; a[0].c = mc->c; a[0].v = &mc->Mouse; a[1].op = CHANRCV; a[1].c = mc->resizec; a[1].v = nil; a[2].op = CHANEND; for(;;) if(alt(a) == 1) resize(); } void redraw(void) { lockdisplay(display); draw(screen, screen->r, display->black, nil, ZP); fillellipse(screen, addpt(screen->r.min,Pt(Dx(screen->r)/2,Dy(screen->r)/2+bouncer.p.y)), 2, 2, display->white, ZP); flushimage(display, 1); unlockdisplay(display); } void resize(void) { int fd; if(debug) fprint(2, "resizing\n"); lockdisplay(display); if(getwindow(display, Refnone) < 0) sysfatal("resize failed"); unlockdisplay(display); /* ignore move events */ if(Dx(screen->r) != SCRW || Dy(screen->r) != SCRH){ fd = open("/dev/wctl", OWRITE); if(fd >= 0){ fprint(fd, "resize %s", winspec); close(fd); } } redraw(); } void usage(void) { fprint(2, "usage: %s [-d] server\n", argv0); threadexitsall("usage"); } void threadmain(int argc, char *argv[]) { char *server; int fd; Mousectl *mc; Ioproc *io; GEOMfmtinstall(); ARGBEGIN{ case 'd': debug++; break; default: usage(); }ARGEND; if(argc != 1) usage(); server = argv[0]; snprint(winspec, sizeof winspec, "-dx %d -dy %d", SCRWB, SCRHB); if(newwindow(winspec) < 0) sysfatal("newwindow: %r"); if(initdraw(nil, nil, nil) < 0) sysfatal("initdraw: %r"); if((mc = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); display->locking = 1; unlockdisplay(display); proccreate(kbdproc, nil, 4096); fd = dial(server, nil, nil, nil); if(fd < 0) sysfatal("dial: %r"); threadcreate(threadnetrecv, &fd, 4096); threadcreate(threadresize, mc, 4096); io = ioproc(); for(;;){ redraw(); iosleep(io, FPS2MS(30)); } }