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;