--- gpm-1.19.3.orig/synaptics.c	Mon Jan 17 13:34:00 2000
+++ gpm-1.19.3/synaptics.c	Mon Aug 27 22:44:09 2001
@@ -145,10 +145,19 @@
 /* edge motion related configuration constants */
 static int   x_min_center            = 1632;  /* left edge   */
 static int   x_max_center            = 5312;  /* right edge  */
-static int   y_min_center            = 1568;  /* bottom edge */
-static int   y_max_center            = 4288;  /* top edge    */
+static int   y_min_center            = 1408;  /* bottom edge */
+static int   y_max_center            = 4108;  /* top edge    */
 static int   edge_speed              = 20;                                /*C*/
 
+/* use wmode */
+static int use_wmode		     = 0;
+static int finger_threshold	     = 30;
+static int tap_lower_limit	     = 5;
+static int tap_upper_limit	     = 200;
+static int tap_range		     = 100;
+static int tap_interval		     = 200;
+static int drag_lock		     = 0;
+static int multiple_click_delay	     = 30;
 
 /*
 ** Types for describing corner actions.
@@ -229,8 +238,17 @@
   { "lower_left_action",          Corner_Param,  &corner_actions [1]         },
   { "upper_right_action",         Corner_Param,  &corner_actions [2]         },
   { "lower_right_action",         Corner_Param,  &corner_actions [3]         },
+  /* use wmode */
+  { "use_wmode",		  Flag_Param,	 &use_wmode		     },
+  { "finger_threshold",		  Integer_Param, &finger_threshold	     },
+  { "tap_lower_limit",		  Integer_Param, &tap_lower_limit	     },
+  { "tap_upper_limit",		  Integer_Param, &tap_upper_limit	     },
+  { "tap_range",		  Integer_Param, &tap_range		     },
+  { "tap_interval",		  Integer_Param, &tap_interval		     },
+  { "drag_lock",		  Flag_Param,	 &drag_lock		     },
+  { "multiple_click_delay",	  Integer_Param, &multiple_click_delay	     },
   /* end of list */
-  { NULL,                         Flag_Param,    NULL                        },
+  { NULL,                         Flag_Param,    NULL                        }
 };
 
 
@@ -267,6 +285,7 @@
   int finger;
   int left;
   int middle;
+  int down;
   int right;
   int x;
   int y;
@@ -658,7 +677,7 @@
     ** If there is a continuing gesture then report the same buttons.
     ** Otherwise compute new buttons.
     */
-    if (!report.gesture && !report.left && !report.right) {
+    if (!report.gesture && !report.left && !report.right && !report.middle && !report.down) {
       state->buttons = 0;
     } else if (last_gesture) {
       state->buttons = last_buttons;
@@ -670,6 +689,12 @@
       if (report.right) 
         state->buttons |= GPM_B_RIGHT;
 
+      if (report.middle)
+	state->buttons |= GPM_B_MIDDLE;
+
+      if (report.down)
+	state->buttons |= 0x8;
+
       process_corner_taps (state, report);
     }
   }
@@ -1168,6 +1193,100 @@
   }
 }
 
+static void syn_translate_ps2_wmode_report (unsigned char *data,
+				      report_type *report) 
+{
+  int i;
+  static int finger_timer = 0;
+  static int gesture_timer = 0;
+  static int gesture_delay = 0;
+  static int stroke_x;
+  static int stroke_y;
+  static int drag_locked = 0;
+
+  if (((data[0] & 0xc8) == 0x80) && ((data[3] & 0xc8) == 0xc0)) {
+    unsigned int w = ((data[3] & 0x04) >> 2) |
+	    		((data[0] & 0x04) >> 1) |
+			((data[0] & 0x30) >> 2);
+    report->left     = check_bits (data[0], 0x01);
+    report->middle   = check_bits (data[0] ^ data[3], 0x01);
+    report->down     = check_bits (data[0] ^ data[3], 0x02);
+    report->right    = check_bits (data[0], 0x02);
+    report->x        = (((data[1] & 0x0f) << 8) |
+			((data[3] & 0x10) << 8) |
+			data[4]);
+    report->y        = (((data[1] & 0xf0) << 4) |
+			((data[3] & 0x20) << 7) |
+			data[5]);
+    report->pressure = data[2];
+    report->finger   = (data[2] > finger_threshold);
+    
+    if (report->finger) {
+	    
+      if (finger_timer == 0) { /* finger down */
+	stroke_x = report->x;
+	stroke_y = report->y;
+      }
+      
+      if (finger_timer < (tap_upper_limit * 80 / 1000)) finger_timer ++; /* don't want timer to overflow */
+      
+      if (gesture_timer > 0) gesture_timer = 1; /* dragging or consecutive tap, gesture to end with finger up */
+      
+    } else { /* interesting things happen when finger is up */
+	    
+      /* tap determination */
+      if ((finger_timer > (tap_lower_limit * 80 / 1000)) &&  /* minimum finger down time */
+	  (finger_timer < (tap_upper_limit * 80 / 1000)) &&  /* maximum finger down time */
+	  (distance((double)(stroke_x - report->x),  /* maximum range for finger to drift while down */
+	    (double)(stroke_y - report->y))
+	    < sqr((double)tap_range))) {
+
+	/* not a consecutive tap? */
+	if (gesture_timer == 0) gesture_delay = 0; /* right -> don't delay gesture */
+	else { /* a consecutive tap! */
+	  gesture_delay = multiple_click_delay * 80 / 1000; /* delay gesture to create multiple click */
+	}
+	
+	/* is drag locked */
+	if (drag_locked) {
+	  drag_locked = 0; /* unlock it and don't gesture. */
+	  gesture_timer = 0;
+	} else gesture_timer = tap_interval * 80 / 1000; /* setup gesture time to count down */
+	
+      } else {
+	      
+	/* a drag to lock? */
+	if (drag_lock && (gesture_timer > 0) && (finger_timer >= (tap_upper_limit * 80 / 1000)))
+	  drag_locked = 1;
+	      
+	if (gesture_timer > 0) gesture_timer --;
+	if (gesture_delay > 0) gesture_delay --;
+	
+      }
+      
+      finger_timer = 0;
+      
+    }
+    
+    report->gesture  = ((gesture_timer > 0) && (gesture_delay == 0)) || drag_locked;
+    report->left = (report->left || report->gesture);
+
+  } else {
+    gpm_debug_log (LOG_NOTICE,"tossing PS/2 data: ");
+    for (i = 0; i < 6; i++)
+      gpm_debug_log (LOG_NOTICE,"%02X ", data [i]);
+    report->gesture  = 0;
+    report->finger   = 0;
+    report->left     = 0;
+    report->middle   = 0;
+    report->down     = 0;
+    report->right    = 0;
+    report->x        = 0;
+    report->y        = 0;
+    report->pressure = 0;
+  }
+}
+
 
 /****************************************************************************
 **
@@ -1200,7 +1319,8 @@
 {
   report_type   report;
 
-  syn_translate_ps2_report (data, &report);
+  if (use_wmode) syn_translate_ps2_wmode_report (data, &report);
+  else syn_translate_ps2_report (data, &report);
   syn_process_data (state, report);
 }
 
@@ -1254,5 +1374,5 @@
   ps2_set_mode2 (fd, (ABSOLUTE_MODE    |
 		      HIGH_REPORT_RATE |
 		      PS2_NO_SLEEP     |
-		      REPORT_W_OFF));
+		      (use_wmode ? REPORT_W_ON : REPORT_W_OFF)));
 }
