--- xf86Wacom.c.ots	Sun Aug 16 13:46:51 1998
+++ xf86Wacom.c	Sun Aug 16 15:28:01 1998
@@ -239,13 +239,13 @@
 #define HEADER_BIT	0x80
 #define ZAXIS_SIGN_BIT	0x40
 #define ZAXIS_BIT    	0x04
-#define ZAXIS_BITS    	0x7f
+#define ZAXIS_BITS    	0x3f
 #define POINTER_BIT     0x20
 #define PROXIMITY_BIT   0x40
 #define BUTTON_FLAG	0x08
 #define BUTTONS_BITS	0x78
 #define TILT_SIGN_BIT	0x40
-#define TILT_BITS	0x7f
+#define TILT_BITS	0x3f
 
 /* defines to discriminate second side button and the eraser */
 #define ERASER_PROX	4
@@ -717,6 +717,33 @@
 }
 
 static void
+xf86WcmSendButtons(LocalDevicePtr	local,
+		   int                  buttons,
+		   int                  rx,
+		   int                  ry,
+		   int                  rz,
+		   int                  rtx,
+		   int                  rty)
+		   
+{
+    int             button;
+    WacomDevicePtr  priv = (WacomDevicePtr) local->private;
+
+    for (button=1; button<16; button++) {
+	int mask = 1 << (button-1);
+	
+	if ((mask & priv->oldButtons) != (mask & buttons)) {
+	    DBG(4, ErrorF("xf86WcmReadInput button=%d state=%d\n", 
+			  button, (buttons & mask) != 0));
+	    xf86PostButtonEvent(local->dev, 
+				(priv->flags & ABSOLUTE_FLAG),
+				button, (buttons & mask) != 0,
+				0, 5, rx, ry, rz, rtx, rty);
+	}
+    }
+}
+
+static void
 xf86WcmSendEvents(LocalDevicePtr	local,
 		  int			is_stylus,
 		  int			is_button,
@@ -731,6 +758,7 @@
     int			tx = 0, ty = 0;
     int			rx, ry, rz, rtx, rty;
     int			is_core_pointer, is_absolute;
+    int                 curDevice;
 
     DBG(7, ErrorF("[%s] prox=%s\tx=%d\ty=%d\tz=%d\tbutton=%s\tbuttons=%d\n",
 		  is_stylus ? "stylus" : "cursor",
@@ -775,41 +803,55 @@
 	    tx = (common->wcmData[7] & TILT_BITS);
 	    ty = (common->wcmData[8] & TILT_BITS);
 	    if (common->wcmData[7] & TILT_SIGN_BIT)
-		tx = - (~(tx-1) & 0x7f);
+		tx -= (TILT_BITS + 1);
 	    if (common->wcmData[8] & TILT_SIGN_BIT)
-		ty = - (~(ty-1) & 0x7f);
+		ty -= (TILT_BITS + 1);
 	}
-	
+
 	/*
 	* The eraser is reported as button 4 and 5 of the stylus.
 	* if we haven't an independent device for the eraser
 	* report the button as button 3 of the stylus.
 	*/
-	if ((buttons > 3) && common->wcmHasEraser &&
-	    ((is_proximity && !priv->oldProximity && 
-	      (buttons == 4 || buttons == 5)) ||
-	     (priv->oldProximity == ERASER_PROX))) {
-	    if (DEVICE_ID(priv->flags) != ERASER_ID)
-		return;
-	    DBG(10, ErrorF("Eraser\n"));
+	if (is_proximity) {
+	    if ((buttons & 4) && common->wcmHasEraser &&
+		((!priv->oldProximity ||
+		  (priv->oldProximity == ERASER_PROX)))) {
+		curDevice = ERASER_ID;
+	    } else {
+		curDevice = STYLUS_ID;
+	    }
+
 	} else {
 	    /*
 	    * When we are out of proximity with the eraser the
 	    * button 4 isn't reported so we must check the
 	    * previous proximity device.
 	    */
-	    if (common->wcmHasEraser && !is_proximity &&
-		(priv->oldProximity == ERASER_PROX)) {
-		if (DEVICE_ID(priv->flags) != ERASER_ID)
-		    return;
-		DBG(10, ErrorF("Eraser\n"));
-	    }
-	    else {
-		if (DEVICE_ID(priv->flags) != STYLUS_ID)
-		    return;
-		DBG(10, ErrorF("Stylus\n"));
+	    if (common->wcmHasEraser && (priv->oldProximity == ERASER_PROX)) {
+		curDevice = ERASER_ID;
+	    } else {
+		curDevice = STYLUS_ID;
 	    }
 	}
+
+	/* We check here to see if we changed between eraser and stylus
+	 * without leaving proximity. The most likely cause is that
+	 * we were fooled by the second side switch into thinking the
+	 * stylus was the eraser. If this happens, we send
+	 * a proximity-out for the old device.
+	 */
+	if (curDevice != DEVICE_ID(priv->flags)) {
+	    if (priv->oldProximity) {
+		buttons = 0;
+		is_proximity = 0;
+	    } else 
+		return;
+	}
+ 
+	DBG(10, ErrorF((DEVICE_ID(priv->flags) == ERASER_ID) ? 
+		       "Eraser\n" : 
+		       "Stylus\n"));
     }
     else {
 	if (DEVICE_ID(priv->flags) != CURSOR_ID)
@@ -872,14 +914,19 @@
 	* we have the eraser else we have the second side
 	* switch.
 	*/
-	if (is_stylus && buttons > 3) {
-	    if (buttons == 4) {
-		buttons = (priv->oldProximity == ERASER_PROX) ? 0 : 4;
-	    }
-	    else {
-		if (priv->oldProximity == ERASER_PROX && buttons == 5)
-		    buttons = ((DEVICE_ID(priv->flags) == ERASER_ID) ? 1 : 3);
+	if (is_stylus) {
+	    if (buttons & 4) {
+		if (priv->oldProximity == ERASER_PROX) {
+		    buttons &= ~4;
+		}
 	    }
+	} else {
+	    /* If the button flag is pressed, but the switch state
+	    * is zero, this means that cursor button 16 was pressed */
+	    if (buttons = 0)
+		buttons = 16;
+	    /* Turn button index reported for cursor into a bit mask. */
+	    buttons = 1 << (buttons - 1);
 	}
 		
 	DBG(4, ErrorF("xf86WcmReadInput %s rx=%d ry=%d rz=%d priv->oldButtons=%d\n",
@@ -899,17 +946,7 @@
 	    }
 	}
 	if (priv->oldButtons != buttons) {
-	    int		delta;
-	    int		button;
-
-	    delta = buttons - priv->oldButtons;
-	    button = (delta > 0) ? delta : -delta;
-		    
-	    DBG(4, ErrorF("xf86WcmReadInput button=%d delta=%d\n", button,
-			  delta));
-	    
-	    xf86PostButtonEvent(local->dev, is_absolute, button, (delta > 0),
-				0, 5, rx, ry, rz, rtx, rty); 
+	    xf86WcmSendButtons (local, buttons, rx, ry, rz, rtx, rty);
 	}
 	priv->oldButtons = buttons;
 	priv->oldX = x;
@@ -921,9 +958,7 @@
     else { /* !PROXIMITY */
 	/* reports button up when the device has been down and becomes out of proximity */
 	if (priv->oldButtons) {
-	    xf86PostButtonEvent(local->dev, is_absolute, priv->oldButtons, 0, 0, 5,
-				rx, ry, rz, rtx, rty);
-	    priv->oldButtons = 0;
+	    xf86WcmSendButtons (local, 0, rx, ry, rz, rtx, rty);
 	}
 	if (!is_core_pointer) {
 	    /* macro button management */
@@ -1082,7 +1117,7 @@
 	    z = ((common->wcmData[6] & ZAXIS_BITS) * 2) +
 		((common->wcmData[3] & ZAXIS_BIT) >> 2);
 	    if (common->wcmData[6] & ZAXIS_SIGN_BIT)
-		z = - (~(z-1) & 0x7f);
+		z -= 0x80;
 	  
 	    is_button = (common->wcmData[0] & BUTTON_FLAG);
 	    is_proximity = (common->wcmData[0] & PROXIMITY_BIT);
@@ -1581,8 +1616,9 @@
 					      nbaxes,
 					      xf86GetMotionEvents, 
 					      local->history_size,
-					      (priv->flags & ABSOLUTE_FLAG) 
-					      ? Absolute : Relative)
+					      ((priv->flags & ABSOLUTE_FLAG) 
+					      ? Absolute : Relative) |
+					      OutOfProximity)
 		== FALSE) {
 		ErrorF("unable to allocate Valuator class device\n"); 
 		return !Success;