shithub: fork

Download patch

ref: 522979e76a67e0a0d5d677ef9ded8b43844497f4
parent: e1bb0942d72079e7659cff7a6743d7a3508b7eea
author: qwx <qwx@sciops.net>
date: Mon Nov 3 05:21:44 EST 2025

jamterm: scroll by 1 line with shift, extend selection with shift click (thanks akw)

Subject: [PATCH] samterm: Roll our own kbd proc

Now we can process Kshift characters so we may do Kshift+(Kup|Kdown)
for moving one line at a time (as in rio).  Also included is the
ability to "extend" a selection in the direction of the initial
selection, i.e. if we have:

	And, now, I don't mind a bit of a breeze, if anything I prefer
	it, but thon was aggressive.

If we were to select "mind" to "breeze", then a shift+left-click to
the right of "breeze" will extend the selection forward to that point,
and if we were to shift+left-click to a point before "mind", the
selection would reverse.

--- a/sys/src/cmd/jamterm/flayer.c
+++ b/sys/src/cmd/jamterm/flayer.c
@@ -23,7 +23,7 @@
 Image	*maincols[NCOL];
 Image	*cmdcols[NCOL];
 
-int	sel;
+ulong	sel;
 
 void
 flstart(Rectangle r)
@@ -274,7 +274,7 @@
 }
 
 int
-flselect(Flayer *l, ulong *p)
+flselect(Flayer *l)
 {
 	static int clickcount;
 	static Point clickpt = {-10, -10};
@@ -285,7 +285,7 @@
 	dt = mousep->msec - l->click;
 	dx = abs(mousep->xy.x - clickpt.x);
 	dy = abs(mousep->xy.y - clickpt.y);
-	*p = sel = frcharofpt(&l->f, mousep->xy) + l->origin;
+	sel = frcharofpt(&l->f, mousep->xy) + l->origin;
 
 	l->click = mousep->msec;
 	clickpt = mousep->xy;
@@ -305,7 +305,9 @@
 {
 	ulong fp0, fp1;
 
-	if(l->visible==None || !flprepare(l)){
+	if(sel != l->p0 && sel != l->p1)
+		sel = p0;
+	if(!flprepare(l)){
 		l->p0 = p0, l->p1 = p1;
 		return;
 	}
--- a/sys/src/cmd/jamterm/flayer.h
+++ b/sys/src/cmd/jamterm/flayer.h
@@ -40,7 +40,7 @@
 Rectangle flrect(Flayer*, Rectangle);
 void	flrefresh(Flayer*, Rectangle, int);
 void	flresize(Rectangle);
-int	flselect(Flayer*, ulong*);
+int	flselect(Flayer*);
 void	flsetselect(Flayer*, long, long);
 void	flstart(Rectangle);
 void	flupfront(Flayer*);
@@ -53,4 +53,4 @@
 extern	Image	*maincols[NCOL];
 extern	Image	*cmdcols[NCOL];
 
-extern	int	sel;
+extern	ulong	sel;
--- a/sys/src/cmd/jamterm/io.c
+++ b/sys/src/cmd/jamterm/io.c
@@ -16,6 +16,7 @@
 int	kbdc;
 int	resized;
 int	scrselecting;
+int	shifted;
 uchar	*hostp;
 uchar	*hoststop;
 uchar	*plumbbase;
@@ -23,12 +24,77 @@
 uchar	*plumbstop;
 Channel	*plumbc;
 Channel	*hostc;
-Mousectl	*mousectl;
+Mousectl *mousectl;
 Mouse	*mousep;
-Keyboardctl *keyboardctl;
-void	panic(char*);
+Channel *kbdchan;
 
+static void
+kbdproc(void *arg)
+{
+	Channel *c = arg;
+	char buf[1024], *p;
+	int cfd, kfd, n;
+
+	threadsetname("kbdproc");
+	if((cfd = open("/dev/consctl", OWRITE)) < 0){
+		chanprint(c, "%r");
+		return;
+	} 
+	fprint(cfd, "rawon");
+
+	if(sendp(c, nil) <= 0)
+		return;
+
+	if((kfd = open("/dev/kbd", OREAD)) >= 0)
+		while((n = read(kfd, buf, sizeof(buf))) > 0)
+			for(p = buf; p < buf+n; p += strlen(p)+1)
+				chanprint(c, "%s", p);
+}
+
+static Channel*
+initkbd(void)
+{
+	Channel *c;
+	char *e;
+
+	c = chancreate(sizeof(char*), 20);
+	procrfork(kbdproc, c, 4096, RFCFDG);
+	if(e = recvp(c)){
+		chanfree(c);
+		c = nil;
+		werrstr("%s", e);
+		free(e);
+	}
+	return c;
+}
+
 void
+kbdkey(char *s)
+{
+	Rune r;
+	int type;
+
+	if(s == nil)
+		return;
+
+	type = *s++;
+	chartorune(&r, s);
+	if(r != Runeerror){
+		switch(type){
+		case 'k':
+		case 'K':
+			shifted = r == Kshift;
+			kbdc = -1;
+			break;
+		case 'c':
+			kbdc = r;
+			break;
+		}
+	}
+	free(s);
+}
+
+void
 initio(void)
 {
 	threadsetname("main");
@@ -38,11 +104,7 @@
 		threadexitsall("mouse");
 	}
 	mousep = mousectl;
-	keyboardctl = initkeyboard(nil);
-	if(keyboardctl == nil){
-		fprint(2, "jamterm: keyboard init failed: %r\n");
-		threadexitsall("kbd");
-	}
+	kbdchan = initkbd();
 	hoststart();
 	plumbstart();
 }
@@ -82,7 +144,7 @@
 waitforio(void)
 {
 	Alt alts[NRes+1];
-	Rune r;
+	char *s;
 	int i;
 	ulong type;
 
@@ -100,8 +162,8 @@
 	if(block & (1<<RHost))
 		alts[RHost].op = CHANNOP;
 
-	alts[RKeyboard].c = keyboardctl->c;
-	alts[RKeyboard].v = &r;
+	alts[RKeyboard].c = kbdchan;
+	alts[RKeyboard].v = &s;
 	alts[RKeyboard].op = CHANRCV;
 	if(block & (1<<RKeyboard))
 		alts[RKeyboard].op = CHANNOP;
@@ -135,7 +197,7 @@
 		externload(i);
 		break;
 	case RKeyboard:
-		kbdc = r;
+		kbdkey(s);
 		break;
 	case RMouse:
 		break;
@@ -268,12 +330,12 @@
 int
 ecankbd(void)
 {
-	Rune r;
+	char *s;
 
 	if(kpeekc >= 0)
 		return 1;
-	if(nbrecv(keyboardctl->c, &r) > 0){
-		kpeekc = r;
+	if(nbrecv(kbdchan, &s) > 0){
+		kbdkey(s);
 		return 1;
 	}
 	return 0;
@@ -283,7 +345,7 @@
 ekbd(void)
 {
 	int c;
-	Rune r;
+	char *s;
 
 	if(kpeekc >= 0){
 		c = kpeekc;
@@ -290,11 +352,12 @@
 		kpeekc = -1;
 		return c;
 	}
-	if(recv(keyboardctl->c, &r) < 0){
-		fprint(2, "jamterm: keybard recv error: %r\n");
+	if(recv(kbdchan, &s) < 0){
+		fprint(2, "samterm: keybard recv error: %r\n");
 		panic("kbd");
 	}
-	return r;
+	kbdkey(s);
+	return kpeekc;
 }
 
 int
--- a/sys/src/cmd/jamterm/main.c
+++ b/sys/src/cmd/jamterm/main.c
@@ -36,7 +36,6 @@
 	Text *t;
 	Rectangle r;
 	Flayer *nwhich;
-	ulong p;
 
 	rfork(RFENVG|RFNAMEG);
 
@@ -108,19 +107,23 @@
 					current(nwhich, 1, 1);
 				if(ptinrect(mousep->xy, which->scroll) || mousep->buttons & 8)
 					scroll(which, (mousep->buttons&8) ? 4 : 1);
-				else if(ptinrect(mousep->xy, which->f.r)){
-					t = which->user1;
-					nclick = flselect(which, &p);
-					if(nclick > 0){
-						if(nclick > 1)
-							outTsl(Ttclick, t->tag, p);
-						else
-							outTsl(Tdclick, t->tag, p);
-						t->lock++;
-					}else if(t!=&cmd)
-						outcmd();
-					if(mousep->buttons&1)
-						chord = mousep->buttons;
+				else if(nwhich && ptinrect(mousep->xy, which->f.r)){
+					if(shifted)
+						extendsel(which);
+					else{
+						t = which->user1;
+						nclick = flselect(which);
+						if(nclick > 0){
+							if(nclick > 1)
+								outTsl(Ttclick, t->tag, sel);
+							else
+								outTsl(Tdclick, t->tag, sel);
+							t->lock++;
+						}else if(t!=&cmd)
+							outcmd();
+						if(mousep->buttons&1)
+							chord = mousep->buttons;
+					}
 				}
 			}else if((mousep->buttons&2) && which){
 				if(nwhich && nwhich!=which)
@@ -142,6 +145,20 @@
 	}
 }
 
+void
+extendsel(Flayer *l)
+{
+	ulong p;
+	do{
+		p = l->origin+frcharofpt(&l->f, mousep->xy);
+		if(p < sel)
+			flsetselect(l, p, sel);
+		else
+			flsetselect(l, sel, p);
+		if(readmouse(mousectl) < 0)
+			panic("mouse");
+	}while(mousep->buttons & (1|8));
+}
 
 void
 resize(void)
@@ -499,6 +516,9 @@
 nontypingkey(int c)
 {
 	switch(c){
+	case Kalt:
+	case Kctl:
+	case Kshift:
 	case Kup:
 	case Kdown:
 	case Khome:
@@ -512,6 +532,7 @@
 	case Kstx:
 	case Kbel:
 	case Ksyn:
+	case -1:
 		return 1;
 	}
 	return 0;
@@ -573,7 +594,7 @@
 					break;
 			}
 		}
-		if(c == '\n' || p >= buf+sizeof(buf)/sizeof(buf[0]))
+		if(c == '\n' || p >= buf+nelem(buf))
 			break;
 	}
 	if(p > buf){
@@ -596,7 +617,7 @@
 	if(c==Kdown){
 		flushtyping(0);
 		//scrorigin(l, 3, l->origin+frcharofpt(&l->f, Pt(l->scroll.max.x, l->scroll.min.y + l->f.font->height)));
-		center(l, l->origin, l->f.maxlines/3);
+		center(l, l->origin, shifted? 1: l->f.maxlines/3);
 	}else if(c==Kpgdown){
 		flushtyping(0);
 		//scrorigin(l, 3, l->origin+frcharofpt(&l->f, Pt(l->scroll.max.x, l->scroll.max.y - l->f.font->height)));
@@ -605,7 +626,7 @@
 	}else if(c==Kup){
 		flushtyping(0);
 		//scrorigin(l, 1, 2);
-		center(l, l->origin, -(l->f.maxlines/3));
+		center(l, l->origin, shifted? -1: -(l->f.maxlines/3));
 	}else if(c==Kpgup){
 		flushtyping(0);
 		//scrorigin(l, 1, Dy(l->scroll)/l->f.font->height);
--- a/sys/src/cmd/jamterm/samterm.h
+++ b/sys/src/cmd/jamterm/samterm.h
@@ -89,6 +89,7 @@
 extern int	exiting;
 extern int	autoindent;
 extern int	spacesindent;
+extern int	shifted;
 
 Rune	*gettext(Flayer*, long, ulong*);
 void	*alloc(ulong n);
@@ -119,6 +120,7 @@
 int	xmenuhit(int, Menu*);
 void	buttons(int);
 void	warpmouse(Flayer*);
+void	extendsel(Flayer*);
 void	current(Flayer*, int, int);
 void	duplicate(Flayer*, Rectangle, Font*, int);
 void	startfile(Text*);
--