ref: 798897c28e191cd4c2513afb658fa196b3fbb95c
dir: /mousefs/mousefs.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <cursor.h> #include <mouse.h> #include <thread.h> #include <fcall.h> #include <9p.h> #include "fns.h" void usage(void) { fprint(2, "usage: %s [-n name]\n", argv0); exits("usage"); } static char Enofile[] = "file not found"; static char Eshort[] = "short read"; static char Enoread[] = "read not supported"; #define min(A, B) ((A) < (B) ? (A) : (B)) QLock drawlock; Rendez readrend; Cursor arrow = { { -1, -1 }, { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C, 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04, 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40, }, { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00, }, }; Cursor cursor; static void Cursortocursor(Cursor *c) { qlock(&drawlock); memmove(&cursor, c, sizeof(Cursor)); qunlock(&drawlock); } typedef struct Mouseinfo Mouseinfo; typedef struct Mousestate Mousestate; struct Mousestate { Point xy; int buttons; ulong counter; ulong msec; }; struct Mouseinfo { QLock; Mousestate; int inbuttons; int redraw; Rendez redrawr; ulong lastcounter; int resize; Rendez r; Ref; int open; int acceleration; int maxacc; Mousestate queue[16]; ulong ri; ulong wi; }; Mouseinfo mouse; static uchar buttonmap[8] = { 0, 1, 2, 3, 4, 5, 6, 7, }; static int mouseswap; static int scrollswap; static ulong mousetime; Rectangle screenr; void absmousetrack(int x, int y, int b, ulong msec) { int lastb; if (x < screenr.min.x) x = screenr.min.x; if (x >= screenr.max.x) x = screenr.max.x - 1; if (y < screenr.min.y) y = screenr.min.y; if (y >= screenr.max.y) y = screenr.max.y - 1; qlock(&mouse); mouse.xy = Pt(x, y); lastb = mouse.buttons; b |= mouse.inbuttons; mouse.buttons = b; mouse.msec = msec; mouse.counter++; if (b != lastb && (mouse.wi - mouse.ri) < nelem(mouse.queue)) mouse.queue[mouse.wi++ % nelem(mouse.queue)] = mouse.Mousestate; rwakeup(&readrend); qunlock(&mouse); } void scmousetrack(int x, int y, int b, ulong msec) { vlong vx, vy; vx = (vlong)(uint)x * (screenr.max.x - screenr.min.x); x = (vx + (1<<30) - (~vx>>31&1) >> 31) + screenr.min.x; vy = (vlong)(uint)y * (screenr.max.y - screenr.min.y); y = (vy + (1<<30) - (~vy>>31&1) >> 31) + screenr.min.y; absmousetrack(x, y, b, msec); } static int scale(int x) { int sign = 1; if (x < 0) { sign = -1; x = -x; } switch (x) { case 0: case 1: case 2: case 3: break; case 4: x = 6 + (mouse.acceleration>>2); break; case 5: x = 9 + (mouse.acceleration>>1); break; default: x *= mouse.maxacc; break; } return sign * x; } /* called at interrupt level */ void mousetrack(int dx, int dy, int b, ulong msec) { if (mouse.acceleration) { dx = scale(dx); dy = scale(dy); } absmousetrack(mouse.xy.x + dx, mouse.xy.y + dy, b, msec); } enum { Qroot, Qmouse, Qmousein, Qmousectl, Qcursor, Qmax }; typedef struct Qfile Qfile; struct Qfile { char *name; int mode; }; Qfile qfiles[] = { [Qroot] { nil, 0555 | DMDIR }, [Qmouse] { "mouse", 0666 }, [Qmousein] { "mousein", 0666 }, [Qmousectl] { "mousectl", 0222 }, [Qcursor] { "cursor", 0666 }, }; void mkqid(Qid *qid, int q) { qid->vers = 0; qid->path = q; qid->type = qfiles[q].mode&DMDIR ? QTDIR : QTFILE; } int mkqdir(Dir *d, int q) { if (q < Qroot || q >= Qmax) return -1; mkqid(&d->qid, q); d->name = qfiles[q].name ? estrdup9p(qfiles[q].name) : nil; d->mode = qfiles[q].mode; d->uid = estrdup9p(getuser()); d->gid = estrdup9p(d->uid); d->muid = estrdup9p(d->uid); d->atime = d->mtime = time(0); d->length = 0; return 0; } int genroot(int n, Dir *dir, void*) { n++; /* skip Qroot */ return mkqdir(dir, n); } void fsopen(Req *r) { switch (r->fid->qid.path) { default: respond(r, nil); return; case Qmousein: r->fid->aux = mallocz(sizeof(Mousestate), 1); respond(r, nil); return; case Qmouse: qlock(&mouse); mouse.lastcounter = mouse.counter; mouse.resize = 0; qunlock(&mouse); /* wet floor */ case Qcursor: incref(&mouse); respond(r, nil); } } void fsclose(Fid *fid) { Mousestate *m; switch (fid->qid.path) { case Qmousein: m = (Mousestate*)fid->aux; qlock(&mouse); mouse.inbuttons &= ~m->buttons; qunlock(&mouse); free(fid->aux); fid->aux = nil; return; case Qmouse: qlock(&mouse); mouse.open = 0; qunlock(&mouse); /* wet floor */ case Qcursor: if (decref(&mouse) != 0) return; Cursortocursor(&arrow); } } void fsread(Req *r) { Mousestate m; int b; char buf[1+4*12+1]; char t; switch (r->fid->qid.path) { case Qmousectl: respond(r, Enoread); return; case Qroot: dirread9p(r, genroot, nil); respond(r, nil); return; case Qcursor: if (r->ifcall.offset != 0) { respond(r, nil); return; } if (r->ifcall.count < 2*4+2*2*16) { respond(r, Eshort); return; } BPLONG(r->ofcall.data+0, arrow.offset.x); BPLONG(r->ofcall.data+4, arrow.offset.y); memmove(r->ofcall.data+8, arrow.clr, 2*16); memmove(r->ofcall.data+40, arrow.set, 2*16); r->ofcall.count = 2*4+2*2*16; respond(r, nil); return; case Qmouse: qlock(&mouse); rsleep(&readrend); if (mouse.ri != mouse.wi) m = mouse.queue[mouse.ri++ % nelem(mouse.queue)]; else m = mouse.Mousestate; qunlock(&mouse); if(0) { case Qmousein: if (r->ifcall.offset != 0) { respond(r, nil); return; } qlock(&mouse); m = mouse.Mousestate; qunlock(&mouse); t = 'm'; } else { /* Qmouse */ mouse.lastcounter = m.counter; if (mouse.resize) { mouse.resize = 0; t = 'r'; } else { t = 'm'; } } b = buttonmap[m.buttons&7]; /* put buttons 4 and 5 back in */ b |= m.buttons & (3<<3); if (scrollswap) if (b == 8) b = 16; else if (b == 16) b = 8; snprint(buf, sizeof(buf), "%c%11d %11d %11d %11ld ", t, m.xy.x, m.xy.y, b, m.msec); r->ofcall.count = 1+4*12; memmove(r->ofcall.data, buf, r->ofcall.count); respond(r, nil); return; } respond(r, Enofile); } void fswrite(Req *r) { Point pt; char *p; Cursor curs; char buf[64]; int b, z, msec; Mousestate *m; switch (r->fid->qid.path) { case Qcursor: if (r->ifcall.count < 2*4+2*2*16) { Cursortocursor(&arrow); r->ofcall.count = r->ifcall.count; respond(r, nil); return; } r->ofcall.count = 2*4+2*2*16; curs.offset.x = BGLONG(r->ifcall.data+0); curs.offset.y = BGLONG(r->ifcall.data+4); memmove(curs.clr, r->ifcall.data+8, 2*16); memmove(curs.set, r->ifcall.data+40, 2*16); Cursortocursor(&curs); respond(r, nil); return; case Qmousectl: /* TODO */ break; case Qmousein: r->ofcall.count = sizeof(buf) - 1; memmove(buf, r->ifcall.data, min(r->ifcall.count, sizeof(buf)-1)); buf[r->ifcall.count] = 0; pt.x = strtol(buf+1, &p, 0); if (*p == 0) { respond(r, Eshort); return; } pt.y = strtol(p, &p, 0); if (*p == 0) { respond(r, Eshort); return; } b = strtol(p, &p, 0); msec = (ulong)strtoll(p, 0, 0); // if (msec == 0) // msec = TK2MS(MACHP(0)->ticks); // TODO /* exclude wheel */ z = b & (8|16); b ^= z; m = (Mousestate*)r->fid->aux; m->xy = pt; m->msec = msec; b ^= m->buttons; m->buttons ^= b; qlock(&mouse); mouse.inbuttons = (m->buttons & b) | (mouse.inbuttons & ~b); b = mouse.buttons & ~b; qunlock(&mouse); /* include wheel */ b &= ~(8|16); b ^= z; if (buf[0] == 'A') absmousetrack(pt.x, pt.y, b, msec); else if (buf[0] == 'a') scmousetrack(pt.x, pt.y, b, msec); else mousetrack(pt.x, pt.y, b, msec); respond(r, nil); return; case Qmouse: r->ofcall.count = r->ifcall.count; memmove(buf, r->ifcall.data, r->ifcall.count); buf[r->ifcall.count] = 0; pt.x = strtol(buf+1, &p, 0); if (*p == 0) { respond(r, Eshort); return; } pt.y = strtol(p, 0, 0); absmousetrack(pt.x, pt.y, mouse.buttons, 0); respond(r, nil); return; } respond(r, "not implemented"); } char* fswalk(Fid *fid, char *name, Qid *qid) { switch (fid->qid.path) { case Qroot: if (strcmp(name, "..") == 0) { *qid = fid->qid; return nil; } for (int q = Qmouse; q < Qmax; q++) { if (strcmp(qfiles[q].name, name) == 0) { mkqid(&fid->qid, q); *qid = fid->qid; return nil; } } break; } return Enofile; } void fsstat(Req *r) { if (mkqdir(&r->d, r->fid->qid.path) < 0) respond(r, Enofile); else respond(r, nil); } void fsattach(Req *r) { mkqid(&r->fid->qid, Qroot); r->ofcall.qid = r->fid->qid; respond(r, nil); } Srv fs = { .attach = fsattach, .walk1 = fswalk, .stat = fsstat, .open = fsopen, .destroyfid = fsclose, .read = fsread, .write = fswrite, }; static void mouseinit(void) { Cursortocursor(&arrow); screenr = Rect(0, 0, 1024, 768); readrend.l = &mouse; } void main(int argc, char **argv) { char *name = nil; char *srvname; char buf[16]; ARGBEGIN{ case 'D': chatty9p++; fprint(2, "enable chatty 9p\n"); break; case 'n': name = EARGF(usage()); break; default: usage(); }ARGEND; if (!name) { snprint(buf, sizeof buf, "%d", getpid()); name = buf; } srvname = smprint("mousefs.%s", name); if (!srvname) sysfatal("%r"); mouseinit(); initcmdfs(name); postsrv(&fs, srvname); }