devdraw: control+click = button 2, alt/shift+click = button 3

For single-button mouse users.

R=rsc
https://codereview.appspot.com/7620043
diff --git a/src/cmd/devdraw/x11-inc.h b/src/cmd/devdraw/x11-inc.h
index 5371eac..1ac27d6 100644
--- a/src/cmd/devdraw/x11-inc.h
+++ b/src/cmd/devdraw/x11-inc.h
@@ -32,3 +32,4 @@
 #undef Visual
 #undef Window
 
+void	sendalt(void);
diff --git a/src/cmd/devdraw/x11-itrans.c b/src/cmd/devdraw/x11-itrans.c
index b08601e..4eac847 100644
--- a/src/cmd/devdraw/x11-itrans.c
+++ b/src/cmd/devdraw/x11-itrans.c
@@ -114,8 +114,7 @@
 		case XK_Alt_R:
 		case XK_Meta_R:	/* Shift Alt on PCs */
 		case XK_Multi_key:
-			k = Kalt;
-			break;
+			return -1;
 		default:		/* not ISO-1 or tty control */
 			if(k>0xff) {
 				k = _p9keysym2ucs(k);
@@ -128,7 +127,7 @@
 	if(k == XK_hyphen)
 		k = XK_minus;
 	/* Do control mapping ourselves if translator doesn't */
-	if(e->xkey.state&ControlMask && k != Kalt)
+	if(e->xkey.state&ControlMask)
 		k &= 0x9f;
 	if(k == NoSymbol) {
 		return -1;
@@ -145,18 +144,33 @@
 	alting = 0;
 }
 
+static Rune* sendrune(Rune);
+
 extern int _latin1(Rune*, int);
 static Rune*
 xtoplan9latin1(XEvent *e)
 {
-	static Rune k[10];
-	static int nk;
-	int n;
-	int r;
+	Rune r;
 
 	r = __xtoplan9kbd(e);
 	if(r < 0)
 		return nil;
+	return sendrune(r);
+}
+
+void
+sendalt(void)
+{
+	sendrune(Kalt);
+}
+
+static Rune*
+sendrune(Rune r)
+{
+	static Rune k[10];
+	static int nk;
+	int n;
+
 	if(alting){
 		/*
 		 * Kludge for Mac's X11 3-button emulation.
@@ -228,6 +242,7 @@
 	switch(e->type){
 	case ButtonPress:
 		be = (XButtonEvent*)e;
+
 		/* 
 		 * Fake message, just sent to make us announce snarf.
 		 * Apparently state and button are 16 and 8 bits on
@@ -292,7 +307,7 @@
 		m->xy.x = me->x;
 		m->xy.y = me->y;
 		m->msec = me->time;
-		break;
+		return 0; // do not set buttons
 
 	default:
 		return -1;
diff --git a/src/cmd/devdraw/x11-srv.c b/src/cmd/devdraw/x11-srv.c
index 5a4be70..04ecabe 100644
--- a/src/cmd/devdraw/x11-srv.c
+++ b/src/cmd/devdraw/x11-srv.c
@@ -36,7 +36,7 @@
 	Button2MotionMask|\
 	Button3MotionMask)
 
-#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask|FocusChangeMask
+#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask|EnterWindowMask|LeaveWindowMask|FocusChangeMask
 
 typedef struct Kbdbuf Kbdbuf;
 typedef struct Mousebuf Mousebuf;
@@ -463,6 +463,28 @@
 	}
 }
 
+static int kbuttons;
+static int altdown;
+static int kstate;
+
+static void
+sendmouse(Mouse m)
+{
+	m.buttons |= kbuttons;
+	mouse.m[mouse.wi] = m;
+	mouse.wi++;
+	if(mouse.wi == nelem(mouse.m))
+		mouse.wi = 0;
+	if(mouse.wi == mouse.ri){
+		mouse.stall = 1;
+		mouse.ri = 0;
+		mouse.wi = 1;
+		mouse.m[0] = m;
+		/* fprint(2, "mouse stall\n"); */
+	}
+	matchmouse();
+}
+
 /*
  * Handle an incoming X event.
  */
@@ -472,6 +494,8 @@
 	int c;
 	KeySym k;
 	static Mouse m;
+	XButtonEvent *be;
+	XKeyEvent *ke;
 
 #ifdef SHOWEVENT
 	static int first = 1;
@@ -504,41 +528,86 @@
 		if(_xconfigure(xev)){
 			mouse.resized = 1;
 			_xreplacescreenimage();
-			goto addmouse;
+			sendmouse(m);
 		}
 		break;
 
 	case ButtonPress:
+		be = (XButtonEvent*)xev;
+		if(be->button == 1) {
+			if(kstate & ControlMask)
+				be->button = 2;
+			else if(kstate & Mod1Mask)
+				be->button = 3;
+		}
+		// fall through
 	case ButtonRelease:
+		altdown = 0;
+		// fall through
 	case MotionNotify:
 		if(mouse.stall)
 			return;
 		if(_xtoplan9mouse(xev, &m) < 0)
 			return;
-	addmouse:
-		mouse.m[mouse.wi] = m;
-		mouse.wi++;
-		if(mouse.wi == nelem(mouse.m))
-			mouse.wi = 0;
-		if(mouse.wi == mouse.ri){
-			mouse.stall = 1;
-			mouse.ri = 0;
-			mouse.wi = 1;
-			mouse.m[0] = m;
-			/* fprint(2, "mouse stall\n"); */
-		}
-		matchmouse();
+		sendmouse(m);
 		break;
 	
+	case KeyRelease:
 	case KeyPress:
-		if(kbd.stall)
-			return;
-		XLookupString((XKeyEvent*)xev, NULL, 0, &k, NULL);
+		ke = (XKeyEvent*)xev;
+		XLookupString(ke, NULL, 0, &k, NULL);
+		c = ke->state;
+		switch(k) {
+		case XK_Alt_L:
+		case XK_Meta_L:	/* Shift Alt on PCs */
+		case XK_Alt_R:
+		case XK_Meta_R:	/* Shift Alt on PCs */
+		case XK_Multi_key:
+			if(xev->type == KeyPress)
+				altdown = 1;
+			else if(altdown) {
+				altdown = 0;
+				sendalt();
+			}
+			break;
+		}
+
+		switch(k) {
+		case XK_Control_L:
+			if(xev->type == KeyPress)
+				c |= ControlMask;
+			else
+				c &= ~ControlMask;
+			goto kbutton;
+		case XK_Alt_L:
+		case XK_Shift_L:
+			if(xev->type == KeyPress)
+				c |= Mod1Mask;
+			else
+				c &= ~Mod1Mask;
+		kbutton:
+			kstate = c;
+			if(m.buttons || kbuttons) {
+				altdown = 0; // used alt
+				kbuttons = 0;
+				if(c & ControlMask)
+					kbuttons |= 2;
+				if(c & Mod1Mask)
+					kbuttons |= 4;
+				sendmouse(m);
+				break;
+			}
+		}
+
+		if(xev->type != KeyPress)
+			break;
 		if(k == XK_F11){
 			fullscreen = !fullscreen;
 			_xmovewindow(fullscreen ? screenrect : windowrect);
 			return;
 		}
+		if(kbd.stall)
+			return;
 		if((c = _xtoplan9kbd(xev)) < 0)
 			return;
 		kbd.r[kbd.wi++] = c;