code: plan9front

Download patch

ref: e982ca2f8d6779b6b103a0d812d61f88f2338294
parent: 32acb3ebd8ecb684a4db054febc082b99d5957be
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Feb 6 14:04:15 EST 2023

rio: refactor the keyboardtap code a bit

run the keyboardtap as a thread instead of a proc
so that we can read input window variable.
This gets rid of the wintap channel.

do focus handling by tracking the last window and
only send context switch when we start typing into
a different window.

have fromtap, totap channels created by open and
use the variable also as the in-use flag.

handle use nbsendp() when sending to the tap
program, as it might be blocked or misbehaving.
if the totap channel is full, we bypass the tap
and send to input again.

handle keyup on focus loss in the window thread instead
(just like the artificial mouseup) it is unrelated to
keyboardtap.

--- a/sys/src/cmd/rio/dat.h
+++ b/sys/src/cmd/rio/dat.h
@@ -172,6 +172,7 @@
 	uchar		deleted;
 	uchar		mouseopen;
 	uchar		kbdopen;
+	uchar		keyup;
 	uchar		winnameread;
 	char			*label;
 	char			*dir;
@@ -315,16 +316,10 @@
 int		gotscreen;
 int		servekbd;
 
-enum{
-	Tapon = 'b',
-	Tapoff = 'e',
-	Tapfocus = 'z',
-};
-Channel *ctltap;	/* open/close */
-Channel *resptap;	/* open/close err */
-Channel	*fromtap;	/* input from kbd tap program to window */
+Channel *opentap;	/* open fromtap or totap */
+Channel *closetap;	/* close fromtap or totap */
+Channel	*fromtap;	/* keyboard output from the tap program */
 Channel *totap;		/* our keyboard input to tap program */
-Channel *wintap;	/* tell the tapthread which Window to send to */
 
 Window	*input;
 QLock	all;			/* BUG */
--- a/sys/src/cmd/rio/rio.c
+++ b/sys/src/cmd/rio/rio.c
@@ -196,12 +196,9 @@
 	kbdchan = initkbd();
 	if(kbdchan == nil)
 		error("can't find keyboard");
-	totap = chancreate(sizeof(char*), 32);
-	fromtap = chancreate(sizeof(char*), 32);
-	wintap = chancreate(sizeof(Window*), 0);
-	ctltap = chancreate(sizeof(char*), 0);
-	resptap = chancreate(sizeof(char*), 0);
-	proccreate(keyboardtap, nil, STACK);
+	opentap = chancreate(sizeof(Channel*), 0);
+	closetap = chancreate(sizeof(Channel*), 0);
+	threadcreate(keyboardtap, nil, STACK);
 
 	wscreen = allocscreen(screen, background, 0);
 	if(wscreen == nil)
@@ -352,132 +349,73 @@
 			write(window[i]->notefd, "hangup", 6); 
 }
 
-static int tapseats[] = { [OREAD] Tapoff, [OWRITE] Tapoff };
-
-char*
-tapctlmsg(char *msg)
-{
-	int perm;
-
-	perm = msg[1];
-	switch(msg[0]){
-	case Tapoff:
-		if(perm == ORDWR)
-			tapseats[OREAD] = Tapoff, tapseats[OWRITE] = Tapoff;
-		else
-			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;
-	Window *w, *cur;
-	static char keys[64];
+	Window *cur = nil;
+	Channel *c;
+	char *s;
 
-	threadsetname("keyboardtap");
-	enum { Awin, Actl, Afrom, Adev, Ato, Ainp, Awatch, NALT };
+	enum { Akbd, Aopen, Aclose, Awrite, 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 = kbdchan, .v = &s, .op = CHANRCV},
-		[Ato]	{.c = totap, .v = &s, .op = CHANNOP},
-		[Ainp]	{.c = nil, .v = &s, .op = CHANNOP},
-		[Awatch]{.c = totap, .v = &watched, .op = CHANNOP},
+		[Akbd]	{.c = kbdchan, .v = &s, .op = CHANRCV},
+		[Aopen] {.c = opentap, .v = &c, .op = CHANRCV},
+		[Aclose]{.c = closetap, .v = &c, .op = CHANRCV},
+		[Awrite]{.c = nil, .v = &s, .op = CHANNOP},
 		[NALT]	{.op = CHANEND},
 	};
 
-	cur = nil;
-	watched = nil;
-	keys[0] = 0;
-	for(;;)
+	threadsetname("keyboardtap");
+
+	for(;;){
 		switch(alt(alts)){
-		case Awin:
-			cur = w;
-			if(cur != nil){
-				alts[Ainp].c = cur->ck;
-				if(tapseats[OREAD] != Tapoff){	
-					if(alts[Awatch].op == CHANSND)
-						free(watched);
-					watched = smprint("%c%d", Tapfocus, cur->id);
-					alts[Awatch].op = CHANSND;
+		case Akbd:
+			if(*s == 'k' || *s == 'K')
+				shiftdown = utfrune(s+1, Kshift) != nil;
+			if(totap == nil)
+				goto Bypass;
+			if(input != nil && input != cur){	/* context change */
+				char *z = smprint("z%d", input->id);
+				if(nbsendp(totap, z) != 1){
+					free(z);
+					goto Bypass;
 				}
 			}
-			if(alts[Ainp].op != CHANNOP || alts[Ato].op != CHANNOP)
-				free(s);
-			if(cur == nil)
-				goto Reset;
-			s = smprint("K%s", keys);
-			alts[Ainp].op = CHANSND;
-			alts[Ato].op = CHANNOP;
+			cur = input;
+			if(nbsendp(totap, s) != 1)
+				goto Bypass;
 			break;
-		case Actl:
-			e = tapctlmsg(ctl);
-			sendp(resptap, e);
-			if(e != nil || *ctl != Tapoff){
-				free(ctl);
-				break;
+		case Aopen:
+			if(c == fromtap){
+				alts[Awrite].c = c;
+				alts[Awrite].op = CHANRCV;
 			}
-			free(ctl);
-			goto Reset;
-		case Afrom:
-			if(cur == nil){
+			break;
+		case Aclose:
+			if(c == fromtap){
+				fromtap = nil;
+				alts[Awrite].c = nil;
+				alts[Awrite].op = CHANNOP;
+			}
+			if(c == totap)
+				totap = nil;
+			chanfree(c);
+			break;
+		case Awrite:
+			if(input != cur){
 				free(s);
 				break;
 			}
-			alts[Afrom].op = CHANNOP;
-			alts[Adev].op = CHANNOP;
-			alts[Ato].op = CHANNOP;
-			alts[Ainp].op = CHANSND;
-			break;
-		case Adev:
-			if(*s == 'k' || *s == 'K')
-				strcpy(keys, s+1);
-			if(tapseats[OWRITE] == Tapoff && cur == nil){
+		Bypass:
+			cur = input;
+			if(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;
+			sendp(cur->ck, s);
 			break;
-		case Awatch:
-			alts[Awatch].op = CHANNOP;
-			break;
-		case Ainp:
-			if(*s == 'k' || *s == 'K')
-				shiftdown = utfrune(s+1, Kshift) != nil;
-		case Ato:
-		Reset:
-			alts[Ainp].op = CHANNOP;
-			alts[Ato].op = CHANNOP;
-			alts[Afrom].op = CHANRCV;
-			alts[Adev].op = CHANRCV;
-			break;
 		}
+	}
 }
 
 int
--- a/sys/src/cmd/rio/wind.c
+++ b/sys/src/cmd/rio/wind.c
@@ -83,7 +83,6 @@
 	Channel *c;
 
 	if(input == nil){
-		sendp(wintap, w);
 		input = w;
 		return;
 	}
@@ -90,7 +89,6 @@
 	if(w == input)
 		return;
 	incref(input);
-	sendp(wintap, w);
 	c = chancreate(sizeof(Window*), 0);
 	wsendctlmesg(input, Repaint, ZR, c);
 	sendp(c, w);		/* send the new input */
@@ -1305,7 +1303,6 @@
 		return;
 	w->deleted = TRUE;
 	if(w == input){
-		sendp(wintap, nil);
 		input = nil;
 		riosetcursor(nil);
 	}
@@ -1384,11 +1381,12 @@
 			Channel *c = p;
 			input = recvp(c);
 
-			/* when we lost input, release mouse buttons */
+			/* when we lost input, release mouse and keyboard buttons */
 			if(w->mc.buttons){
 				w->mc.buttons = 0;
 				w->mouse.counter++;
 			}
+			w->keyup = w->kbdopen;
 			w->wctlready = 1;
 
 			sendp(c, w);
@@ -1559,9 +1557,9 @@
 			alts[WWread].op = CHANNOP;
 			alts[WCread].op = CHANNOP;
 		} else {
-			alts[WKbdread].op = (w->kbdopen && kbdqw != kbdqr) ?
+			alts[WKbdread].op = w->kbdopen && (kbdqw != kbdqr || w->keyup) ?
 				CHANSND : CHANNOP;
-			alts[WMouseread].op = (w->mouseopen && w->mouse.counter != w->mouse.lastcounter) ? 
+			alts[WMouseread].op = w->mouseopen && w->mouse.counter != w->mouse.lastcounter ? 
 				CHANSND : CHANNOP;
 			alts[WCwrite].op = w->scrolling || w->mouseopen || (w->qh <= w->org+w->nchars) ?
 				CHANSND : CHANNOP;
@@ -1614,6 +1612,11 @@
 				free(kbds);
 				nb += i;
 				kbdqr++;
+			}
+			if(w->keyup && nb+2 <= pair.ns){
+				w->keyup = 0;
+				memmove((char*)pair.s + nb, "K", 2);
+				nb += 2;
 			}
 			pair.ns = nb;
 			send(crm.c2, &pair);
--- a/sys/src/cmd/rio/xfid.c
+++ b/sys/src/cmd/rio/xfid.c
@@ -247,7 +247,6 @@
 {
 	Fcall t;
 	Window *w;
-	char *s;
 
 	w = x->f->w;
 	if(w != nil && w->deleted){
@@ -313,12 +312,23 @@
 		}
 		break;
 	case Qtap:
-		chanprint(ctltap, "%c%c", Tapon, x->mode);
-		s = recvp(resptap);
-		if(s == nil)
-			break;
-		filsysrespond(x->fs, x, &t, s);
-		return;
+		if((x->mode == OWRITE || x->mode == ORDWR) && fromtap != nil){
+			filsysrespond(x->fs, x, &t, Einuse);
+			return;
+		}
+		if(x->mode == OREAD || x->mode == ORDWR){
+			if(totap != nil){
+				filsysrespond(x->fs, x, &t, Einuse);
+				return;
+			}
+			totap = chancreate(sizeof(char*), 32);
+			sendp(opentap, totap);
+		}
+		if(x->mode == OWRITE || x->mode == ORDWR){
+			fromtap = chancreate(sizeof(char*), 32);
+			sendp(opentap, fromtap);
+		}
+		break;
 	}
 	t.qid = x->f->qid;
 	t.iounit = messagesize-IOHDRSZ;
@@ -374,8 +384,10 @@
 			w->wctlopen = FALSE;
 		break;
 	case Qtap:
-		chanprint(ctltap, "%c%c", Tapoff, x->f->mode);
-		recvp(resptap);
+		if(fromtap != nil && (x->f->mode == OWRITE || x->f->mode == ORDWR))
+			sendp(closetap, fromtap);
+		if(totap != nil && (x->f->mode == OREAD || x->f->mode == ORDWR))
+			sendp(closetap, totap);
 		break;
 	}
 	if(w)
@@ -592,8 +604,7 @@
 				fc.count = p - x->data;
 				filsysrespond(x->fs, x, &fc, "null message type");
 				return;
-			case Tapfocus:
-				/* cleanup our own pollution */
+			case 'z':	/* ignore context change */
 				break;
 			default:
 				chanprint(fromtap, "%s", p);
@@ -727,6 +738,7 @@
 		break;
 
 	case Qtap:
+		assert(totap != nil);
 		alts[Adata].c = totap;
 		alts[Adata].v = &t;
 		alts[Adata].op = CHANRCV;