--- xf86-input-synaptics-1.4.0/src/eventcomm.c-orig 2011-03-24 13:33:29.640001111 +0700 +++ xf86-input-synaptics-1.4.0/src/eventcomm.c 2011-03-24 13:40:06.433001138 +0700 @@ -277,6 +277,13 @@ } xf86Msg(X_PROBED, "%s: buttons:%s\n", pInfo->name, buf); + + /* clickpad device reports only the single left button mask */ + if (priv->has_left && !priv->has_right && !priv->has_middle) { + priv->is_clickpad = TRUE; + xf86Msg(X_INFO, "%s: is Clickpad device\n", pInfo->name); + } + } } --- xf86-input-synaptics-1.4.0/xf86-input-synaptics-1.4.0/src/synaptics.c-orig 2011-03-24 13:34:01.809001113 +0700 +++ xf86-input-synaptics-1.4.0/src/synaptics.c 2011-03-24 13:50:09.042001182 +0700 @@ -513,6 +513,18 @@ vertResolution = priv->resy; } + /* Clickpad mode -- bottom area is used as buttons */ + if (priv->is_clickpad) { + int button_bottom; + /* Clickpad devices usually the button area at the bottom, and + * its size seems ca. 20% of the touchpad height no matter how + * large the pad is. + */ + button_bottom = priv->maxy - (abs(priv->maxy - priv->miny) * 20) / 100; + if (button_bottom < b && button_bottom >= t) + b = button_bottom; + } + /* set the parameters */ pars->left_edge = xf86SetIntOption(opts, "LeftEdge", l); pars->right_edge = xf86SetIntOption(opts, "RightEdge", r); @@ -1091,6 +1103,59 @@ return Success; } +/* clickpad event handling */ +static void +HandleClickpad(InputInfoPtr pInfo, struct SynapticsHwState *hw, edge_type edge) +{ + SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private); + SynapticsParameters *para = &priv->synpara; + + if (edge & BOTTOM_EDGE) { + /* button area */ + int width = priv->maxx - priv->minx; + int left_button_x, right_button_x; + + /* left and right clickpad button ranges; + * the gap between them is interpreted as a middle-button click + */ + left_button_x = width * 2/ 5 + priv->minx; + right_button_x = width * 3 / 5 + priv->minx; + + /* clickpad reports only one button, and we need + * to fake left/right buttons depending on the touch position + */ + if (hw->left) { /* clicked? */ + hw->left = 0; + if (hw->x < left_button_x) + hw->left = 1; + else if (hw->x > right_button_x) + hw->right = 1; + else + hw->middle = 1; + } + + /* Don't move pointer position in the button area during clicked, + * except for horiz/vert scrolling is enabled. + * + * The synaptics driver tends to be pretty sensitive. This hack + * is to avoid that the pointer moves slightly and misses the + * poistion you aimed to click. + * + * Also, when the pointer movement is reported, the dragging + * (with a sort of multi-touching) doesn't work well, too. + */ + if (hw->left || !(para->scroll_edge_horiz || + ((edge & RIGHT_EDGE) && para->scroll_edge_vert))) + hw->z = 0; /* don't move pointer */ + + } else if (hw->left) { + /* dragging */ + hw->left = priv->prev_hw.left; + hw->right = priv->prev_hw.right; + hw->middle = priv->prev_hw.middle; + } + priv->prev_hw = *hw; +} /* * Convert from absolute X/Y coordinates to a coordinate system where @@ -2313,6 +2378,13 @@ { SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private); SynapticsParameters *para = &priv->synpara; + edge_type edge = NO_EDGE; + + edge = edge_detection(priv, hw->x, hw->y); + + /* Clickpad handling for button area */ + if (priv->is_clickpad) + HandleClickpad(pInfo, hw, edge); /* Treat the first two multi buttons as up/down for now. */ hw->up |= hw->multi[0]; @@ -2469,7 +2540,7 @@ /* no edge or finger detection outside of area */ if (inside_active_area) { - edge = edge_detection(priv, hw->x, hw->y); + /*edge = edge_detection(priv, hw->x, hw->y);*/ finger = SynapticsDetectFinger(priv, hw); } --- xf86-input-synaptics-1.4.0/src/synapticsstr.h-orig 2011-03-24 13:34:49.909001117 +0700 +++ xf86-input-synaptics-1.4.0/src/synapticsstr.h 2011-03-24 13:52:14.511001191 +0700 @@ -239,6 +239,8 @@ Bool has_pressure; /* device reports pressure */ Bool has_width; /* device reports finger width */ Bool has_scrollbuttons; /* device has physical scrollbuttons */ + Bool is_clickpad; /* is Clickpad device (one-button) */ + struct SynapticsHwState prev_hw; /* previous h/w state (for clickpad) */ enum TouchpadModel model; /* The detected model */ } SynapticsPrivate;