ref: 15fb95683835a788826d0826f28e88fcd68ea85d
parent: d2a70ae3ee19a6e74e3ad1fcc568c26d1dbe227b
author: sirjofri <sirjofri@sirjofri.de>
date: Mon Jan 6 17:17:52 EST 2025
adds rudimentary mousefs implementation
--- /dev/null
+++ b/mousefs/mkfile
@@ -1,0 +1,6 @@
+</$objtype/mkfile
+
+TARG=mousefs
+OFILES=mousefs.$O
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/mousefs/mousefs.c
@@ -1,0 +1,538 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <cursor.h>
+#include <mouse.h>
+#include <thread.h>
+#include <fcall.h>
+#include <9p.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;
+
+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;
+ qunlock(&mouse);
+ // TODO: wakeup?
+}
+
+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);
+ 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);
+}
+
+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();
+
+ postsrv(&fs, srvname);
+}
--- /dev/null
+++ b/mousefs/t.rc
@@ -1,0 +1,11 @@
+#!/bin/rc
+
+rfork en
+mk
+rm /srv/mousefs.test >[2]/dev/null
+6.out -n test $*
+mount /srv/mousefs.test /mnt/mousetest
+cd /mnt/mousetest
+prompt=('mousefs; ' ' ')
+rc
+rm /srv/mousefs.test >[2]/dev/null
--
⑨