shithub: lola

Download patch

ref: 1c5f593c22a22f0cc35d5c8c0476e4d7007d208a
parent: f42ae8d3b918c57f5c82d192aef0b9feccd7a313
author: aap <aap@papnet.eu>
date: Sat Jan 28 15:34:31 EST 2023

kbdtap

--- a/TODO
+++ b/TODO
@@ -1,8 +1,6 @@
 rethink resizing and repainting
 implement all Qids
 	wctl
-	tap
-tap
 border resize/move
 write text
 wctl
--- a/fs.c
+++ b/fs.c
@@ -18,7 +18,7 @@
 	Qwdir,
 //	Qwctl,
 	Qwindow,
-//	Qtap,		//
+	Qtap,
 
 	NQids
 };
@@ -47,6 +47,7 @@
 	Qcursor,	QTFILE, "cursor",
 	Qscreen,	QTFILE, "screen",
 	Qwindow,	QTFILE, "window",
+	Qtap,	QTFILE, "kbdtap",
 };
 
 char Eperm[] = "permission denied";
@@ -320,6 +321,8 @@
 
 	w = XF(r->fid)->w;
 
+	/* TODO: check and sanitize mode */
+
 	if(w == nil || w->deleted){
 		respond(r, Edeleted);
 		return;
@@ -357,6 +360,12 @@
 		w->resized = FALSE;
 		w->mouseopen = TRUE;
 		break;
+
+	case Qtap:
+		r->ifcall.mode &= (OREAD|OWRITE|ORDWR);
+		chanprint(ctltap, "%c%c", Tapon, r->ifcall.mode);
+		respond(r, recvp(resptap));
+		return;
 	}
 
 	respond(r, nil);
@@ -410,6 +419,11 @@
 		w->cursorp = nil;
 		wsetcursor(w);
 		break;
+
+	case Qtap:
+		chanprint(ctltap, "%c%c", Tapoff, fid->omode);
+		recvp(resptap);
+		break;
 	}
 
 	wrelease(xf->w);
@@ -485,7 +499,10 @@
 	w = XF(r->fid)->w;
 
 	alts[Adata] = ALT(readchan, &chan, CHANRCV);
-	alts[Agone] = ALT(w->gone, nil, CHANRCV);
+	if(w)
+		alts[Agone] = ALT(w->gone, nil, CHANRCV);
+	else
+		alts[Agone] = ALT(nil, nil, CHANNOP);
 	alts[Aflush] = ALT(XR(r)->flush, nil, CHANRCV);
 	alts[NALT].op = CHANEND;
 	switch(alt(alts)){
@@ -494,7 +511,7 @@
 		pair.ns = r->ifcall.count;
 		send(chan, &pair);
 		recv(chan, &pair);
-		r->ofcall.count = pair.ns;
+		r->ofcall.count = min(r->ifcall.count, pair.ns);
 		return nil;
 	case Agone:
 		return Edeleted;
@@ -557,6 +574,9 @@
 	case Qwindow:
 		respond(r, readimg(r, w->img));
 		return;
+	case Qtap:
+		respond(r, readblocking(r, totap));
+		return;
 	default:
 		respond(r, "cannot read");
 		return;
@@ -572,7 +592,7 @@
 	Text *x;
 	vlong offset;
 	u32int count;
-	char *data, *p;
+	char *data, *p, *e;
 	Point pt;
 	Channel *kbd;
 	Stringpair pair;
@@ -585,6 +605,7 @@
 	offset = r->ifcall.offset;
 	count = r->ifcall.count;
 	data = r->ifcall.data;
+	r->ofcall.count = count;
 
 	if(w == nil || w->deleted){
 		respond(r, Edeleted);
@@ -603,7 +624,6 @@
 			memmove(xf->cnv.buf+xf->cnv.n, data, count);
 			xf->cnv.n += count;
 			pair = b2r(&xf->cnv);
-			r->ofcall.count = r->ifcall.count;
 			send(kbd, &pair);
 			break;
 		case Agone:
@@ -713,6 +733,28 @@
 		}
 		free(w->dir);
 		w->dir = cleanname(p);
+		break;
+
+	case Qtap:
+		if(count < 2){
+			respond(r, "malformed key");
+			return;
+		}
+		e = data + count;
+		for(p = data; p < e; p += strlen(p)+1){
+			switch(*p){
+			case '\0':
+				r->ofcall.count = p - data;
+				respond(r, "null message type");
+				return;
+			case Tapfocus:
+				/* cleanup our own pollution */
+				break;
+			default:
+				chanprint(fromtap, "%s", p);
+				break;	
+			}
+		}
 		break;
 
 	default:
--- a/inc.h
+++ b/inc.h
@@ -17,7 +17,7 @@
 	TRUE = 1
 };
 
-#define ALT(c, v, t) (Alt){ c, v, t, nil, nil, 0 };
+#define ALT(c, v, t) (Alt){ c, v, t, nil, nil, 0 }
 
 #define CTRL(c) ((c)&0x1F)
 
@@ -248,6 +248,17 @@
 void wsetname(Window *w);
 void wsetpid(Window *w, int pid, int dolabel);
 void winshell(void *args);
+
+enum{
+	Tapon = 'b',
+	Tapoff = 'e',
+	Tapfocus = 'z',
+};
+extern Channel *ctltap;	/* open/close */
+extern Channel *resptap;	/* open/close err */
+extern Channel	*fromtap;	/* input from kbd tap program to window */
+extern Channel *totap;		/* our keyboard input to tap program */
+extern Channel *wintap;	/* tell the tapthread which Window to send to */
 
 
 Rectangle newrect(void);
--- a/main.c
+++ b/main.c
@@ -728,23 +728,160 @@
 	return nil;
 }
 
-void
-kbthread(void*)
+/*
+ *    kbd    -----+-------> to tap
+ *                 \
+ *                  \
+ * from tap  --------+----> window
+ */
+
+Channel *ctltap;	/* open/close */
+Channel *resptap;	/* open/close err */
+Channel	*fromtap;	/* input from kbd tap program to window */
+Channel *totap;		/* our keyboard input to tap program */
+Channel *wintap;	/* tell the tapthread which Window to send to */
+
+static int tapseats[] = { [OREAD] Tapoff, [OWRITE] Tapoff };
+
+char*
+tapctlmsg(char *msg)
 {
-	char *s;
+	int perm;
 
-	for(;;){
-		recv(kbctl->c, &s);
-		if(*s == 'k' || *s == 'K')
-			shiftdown = utfrune(s+1, Kshift) != nil;
-		if(focused)
-			send(focused->kbd, &s);
+	perm = msg[1];
+	switch(msg[0]){
+	case Tapoff:
+		if(perm == ORDWR)
+			tapseats[OREAD] = Tapoff, tapseats[OWRITE] = Tapoff;
 		else
-			free(s);
+			tapseats[perm] = Tapoff;
+		break;
+	case Tapon:
+		switch(perm){
+		case ORDWR:
+			if(tapseats[OREAD] != Tapoff || tapseats[OWRITE] != Tapoff)
+				return "seat taken";
+			tapseats[OREAD] = Tapon, tapseats[OWRITE] = Tapon;
+			break;
+		case OREAD: case OWRITE:
+			if(tapseats[perm] != Tapoff)
+				return "seat taken";
+			tapseats[perm] = Tapon;
+			break;
+		}
+		break;
 	}
+	return nil;
 }
 
 void
+keyboardtap(void*)
+{
+	char *s, *ctl;
+	char *e;
+	char *watched;
+	Channel *fschan;
+	int n;
+	Stringpair pair;
+	Window *w, *cur;
+
+	threadsetname("keyboardtap");
+	fschan = chancreate(sizeof(Stringpair), 0);
+	enum { Awin, Actl, Afrom, Adev, Ato, Ainp, Awatch, NALT };
+	Alt alts[NALT+1] = {
+		[Awin]	{.c = wintap, .v = &w, .op = CHANRCV},
+		[Actl]	{.c = ctltap, .v = &ctl, .op = CHANRCV},
+		[Afrom]	{.c = fromtap, .v = &s, .op = CHANRCV},
+		[Adev]	{.c = kbctl->c, .v = &s, .op = CHANRCV},
+		[Ato]	{.c = totap, .v = &fschan, .op = CHANNOP},
+		[Ainp]	{.c = nil, .v = &s, .op = CHANNOP},
+		[Awatch]{.c = totap, .v = &fschan, .op = CHANNOP},
+		[NALT]	{.op = CHANEND},
+	};
+
+	cur = nil;
+	watched = nil;
+	for(;;)
+		switch(alt(alts)){
+		case Awin:
+			cur = w;
+			if(cur != nil){
+				alts[Ainp].c = cur->kbd;
+				if(tapseats[OREAD] == Tapoff)	
+					goto Reset;
+				if(alts[Awatch].op == CHANSND)
+					free(watched);
+				watched = smprint("%c%d", Tapfocus, cur->id);
+				alts[Awatch].op = CHANSND;
+			}
+			if(alts[Ainp].op != CHANNOP || alts[Ato].op != CHANNOP)
+				free(s);
+			goto Reset;
+		case Actl:
+			e = tapctlmsg(ctl);
+			sendp(resptap, e);
+			if(e != nil || *ctl != Tapoff){
+				free(ctl);
+				break;
+			}
+			free(ctl);
+			goto Reset;
+		case Afrom:
+			if(cur == nil){
+				free(s);
+				break;
+			}
+			alts[Afrom].op = CHANNOP;
+			alts[Adev].op = CHANNOP;
+			alts[Ato].op = CHANNOP;
+			alts[Ainp].op = CHANSND;
+			break;
+		case Adev:
+			if(tapseats[OWRITE] == Tapoff && cur == nil){
+				free(s);
+				break;
+			}
+			alts[Afrom].op = CHANNOP;
+			alts[Adev].op = CHANNOP;
+			if(tapseats[OWRITE] == Tapoff)
+				alts[Ainp].op = CHANSND;
+			else
+				alts[Ato].op = CHANSND;
+			break;
+
+		/* These two do the xreq channel dance
+		 * ugly... */
+		case Ato:
+			recv(fschan, &pair);
+			n = strlen(s)+1;
+			memmove(pair.s, s, min(n, pair.ns));
+			free(s);
+			pair.ns = n;
+			send(fschan, &pair);
+			goto Reset;
+		case Awatch:
+			recv(fschan, &pair);
+			n = strlen(watched)+1;
+			memmove(pair.s, watched, min(n, pair.ns));
+			free(watched);
+			pair.ns = n;
+			send(fschan, &pair);
+			alts[Awatch].op = CHANNOP;
+			break;
+
+		case Ainp:
+			if(*s == 'k' || *s == 'K')
+				shiftdown = utfrune(s+1, Kshift) != nil;
+		Reset:
+			alts[Ainp].op = CHANNOP;
+			alts[Ato].op = CHANNOP;
+			alts[Afrom].op = CHANRCV;
+			alts[Adev].op = CHANRCV;
+			break;
+		}
+}
+
+void
 threadmain(int, char *[])
 {
 	char buf[256];
@@ -763,6 +900,11 @@
 	mctl = initmouse(nil, screen);
 	if(mctl == nil)
 		sysfatal("initmouse: %r");
+	totap = chancreate(sizeof(Channel**), 0);
+	fromtap = chancreate(sizeof(char*), 32);
+	wintap = chancreate(sizeof(Window*), 0);
+	ctltap = chancreate(sizeof(char*), 0);
+	resptap = chancreate(sizeof(char*), 0);
 
 	servekbd = kbctl->kbdfd >= 0;
 	snarffd = open("/dev/snarf", OREAD|OCEXEC);
@@ -788,9 +930,12 @@
 	draw(screen, screen->r, background, nil, ZP);
 
 	timerinit();
+
+
 	threadcreate(mthread, nil, mainstacksize);
-	threadcreate(kbthread, nil, mainstacksize);
 	threadcreate(resthread, nil, mainstacksize);
+	/* proc so mouse keeps working if tap program crashes */
+	proccreate(keyboardtap, nil, mainstacksize);
 
 	flushimage(display, 1);
 
--- a/wind.c
+++ b/wind.c
@@ -331,6 +331,7 @@
 		return;
 	prev = focused;
 	focused = w;
+	sendp(wintap, w);
 	if(prev)
 		wrepaint(prev);
 	if(focused)
@@ -847,10 +848,9 @@
 				m = (Mousestate){w->mc.Mouse, w->mq.counter};
 			w->mq.lastcounter = m.counter;
 
-			nb = snprint(pair.s, pair.ns, "%c%11d %11d %11d %11ld ",
+			pair.ns = snprint(pair.s, pair.ns, "%c%11d %11d %11d %11ld ",
 				"mr"[w->resized], m.xy.x, m.xy.y, m.buttons, m.msec);
 			w->resized = FALSE;
-			pair.ns = min(nb, pair.ns);
 			send(fsc, &pair);
 			break;