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;