mouse scrolling
diff --git a/NOTES b/NOTES
index 1e2bdfd..9ac91c8 100644
--- a/NOTES
+++ b/NOTES
@@ -164,6 +164,31 @@
 where spec can be WIDTHxHEIGHT, WIDTHxHEIGHT@XMIN,YMIN
 'XMIN YMIN XMAX YMAX' or XMIN,YMIN,XMAX,YMAX.
 
+* Mouse scrolling
+
+The libraries pass along buttons 4 and 5, so if you have a 
+scroll mouse and have X configured to send the up/down 
+events as buttons 4 and 5, acme and 9term will scroll in
+response.
+
+You will likely need to change your X config to enable this.
+In my XF86Config-4 I have
+
+Section "InputDevice"
+	Identifier	"Mouse0"
+	Driver	"mouse"
+	Option	"Buttons" "5"
+	Option	"Emulate3Buttons" "off"
+	Option	"Protocol" "ImPS/2"
+	Option	"ZAxisMapping" "4 5"
+	Option	"Device" "/dev/psaux"
+EndSection
+
+You'll want to find your mouse section (which may have
+a different Identifier -- just leave it alone) and edit that.
+The "Buttons", "Protocol", "ZAxisMapping", and "Emulate3Buttons"
+lines are all important.
+
 * Helping out
 
 If you'd like to help out, great!
diff --git a/src/cmd/9term/9term.c b/src/cmd/9term/9term.c
index 3dafb38..2827eb8 100644
--- a/src/cmd/9term/9term.c
+++ b/src/cmd/9term/9term.c
@@ -115,6 +115,8 @@
 void	plumb(uint, uint);
 void	plumbclick(uint*, uint*);
 uint	insert(Rune*, int, uint, int);
+void scrolldown(int);
+void scrollup(int);
 
 #define	runemalloc(n)		malloc((n)*sizeof(Rune))
 #define	runerealloc(a, n)	realloc(a, (n)*sizeof(Rune))
@@ -519,7 +521,7 @@
 
 	but = t.m.buttons;
 
-	if(but != 1 && but != 2 && but != 4)
+	if(but != 1 && but != 2 && but != 4 && but != 8 && but != 16)
 		return;
 
 	if (ptinrect(t.m.xy, scrollr)) {
@@ -558,6 +560,12 @@
 			plumb(q0, q1);
 		break;
 	*/
+	case 8:
+		scrollup(3);
+		break;
+	case 16:
+		scrolldown(3);
+		break;
 	}
 }
 
@@ -795,6 +803,20 @@
 }
 
 void
+scrollup(int n)
+{
+	setorigin(backnl(t.org, n), 1);
+}
+
+void
+scrolldown(int n)
+{
+	setorigin(line2q(n), 1);
+	if(t.qh<=t.org+t.f->nchars)
+		consread();
+}
+
+void
 key(Rune r)
 {
 	Rune *rp;
@@ -804,20 +826,16 @@
 		return;
 	switch(r){
 	case Kpgup:
-		setorigin(backnl(t.org, t.f->maxlines*2/3), 1);
+		scrollup(t.f->maxlines*2/3);
 		return;
 	case Kpgdown:
-		setorigin(line2q(t.f->maxlines*2/3), 1);
-		if(t.qh<=t.org+t.f->nchars)
-			consread();
+		scrolldown(t.f->maxlines*2/3);
 		return;
 	case Kup:
-		setorigin(backnl(t.org, t.f->maxlines/3), 1);
+		scrollup(t.f->maxlines/3);
 		return;
 	case Kdown:
-		setorigin(line2q(t.f->maxlines/3), 1);
-		if(t.qh<=t.org+t.f->nchars)
-			consread();
+		scrolldown(t.f->maxlines/3);
 		return;
 	case Kleft:
 		if(t.q0 > 0){