summaryrefslogtreecommitdiff
path: root/src/synaptics.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/synaptics.c')
-rw-r--r--src/synaptics.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/synaptics.c b/src/synaptics.c
index 5b95d9d..dbd0809 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -669,6 +669,20 @@ set_default_parameters(InputInfoPtr pInfo)
pars->scroll_twofinger_horiz =
xf86SetBoolOption(opts, "HorizTwoFingerScroll", horizTwoFingerScroll);
pars->touchpad_off = xf86SetIntOption(opts, "TouchpadOff", TOUCHPAD_ON);
+
+ if (priv->has_scrollbuttons) {
+ pars->updown_button_scrolling =
+ xf86SetBoolOption(opts, "UpDownScrolling", TRUE);
+ pars->leftright_button_scrolling =
+ xf86SetBoolOption(opts, "LeftRightScrolling", TRUE);
+ pars->updown_button_repeat =
+ xf86SetBoolOption(opts, "UpDownScrollRepeat", TRUE);
+ pars->leftright_button_repeat =
+ xf86SetBoolOption(opts, "LeftRightScrollRepeat", TRUE);
+ }
+ pars->scroll_button_repeat =
+ xf86SetIntOption(opts, "ScrollButtonRepeat", 100);
+
pars->locked_drags = xf86SetBoolOption(opts, "LockedDrags", FALSE);
pars->locked_drag_time = xf86SetIntOption(opts, "LockedDragTimeout", 5000);
pars->tap_action[RT_TAP] = xf86SetIntOption(opts, "RTCornerButton", 0);
@@ -818,6 +832,8 @@ SynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
xf86ErrorFVerb(6, "port opened successfully\n");
/* initialize variables */
+ priv->repeatButtons = 0;
+ priv->nextRepeat = 0;
priv->count_packet_finger = 0;
priv->tap_state = TS_START;
priv->tap_button = 0;
@@ -995,6 +1011,7 @@ SynapticsReset(SynapticsPrivate * priv)
priv->circ_scroll_on = FALSE;
priv->circ_scroll_vert = FALSE;
priv->mid_emu_state = MBE_OFF;
+ priv->nextRepeat = 0;
priv->lastButtons = 0;
priv->prev_z = 0;
priv->prevFingers = 0;
@@ -2574,6 +2591,46 @@ handle_clickfinger(SynapticsPrivate * priv, struct SynapticsHwState *hw)
}
}
+/* Adjust the hardware state according to the extra buttons (if the touchpad
+ * has any and not many touchpads do these days). These buttons are up/down
+ * tilt buttons and/or left/right buttons that then map into a specific
+ * function (or scrolling into).
+ */
+static Bool
+adjust_state_from_scrollbuttons(const InputInfoPtr pInfo,
+ struct SynapticsHwState *hw)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ SynapticsParameters *para = &priv->synpara;
+ Bool double_click = FALSE;
+
+ if (!para->updown_button_scrolling) {
+ if (hw->down) { /* map down button to middle button */
+ hw->middle = TRUE;
+ }
+
+ if (hw->up) { /* up button generates double click */
+ if (!priv->prev_up)
+ double_click = TRUE;
+ }
+ priv->prev_up = hw->up;
+
+ /* reset up/down button events */
+ hw->up = hw->down = FALSE;
+ }
+
+ /* Left/right button scrolling, or middle clicks */
+ if (!para->leftright_button_scrolling) {
+ if (hw->multi[2] || hw->multi[3])
+ hw->middle = TRUE;
+
+ /* reset left/right button events */
+ hw->multi[2] = hw->multi[3] = FALSE;
+ }
+
+ return double_click;
+}
+
static void
update_hw_button_state(const InputInfoPtr pInfo, struct SynapticsHwState *hw,
struct SynapticsHwState *old, CARD32 now, int *delay)
@@ -2653,6 +2710,66 @@ post_scroll_events(const InputInfoPtr pInfo)
xf86PostMotionEventM(pInfo->dev, FALSE, priv->scroll_events_mask);
}
+static inline int
+repeat_scrollbuttons(const InputInfoPtr pInfo,
+ const struct SynapticsHwState *hw,
+ int buttons, CARD32 now, int delay)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ SynapticsParameters *para = &priv->synpara;
+ int repeat_delay, timeleft;
+ int rep_buttons = 0;
+
+ if (para->updown_button_repeat)
+ rep_buttons |= (1 << (4 - 1)) | (1 << (5 - 1));
+ if (para->leftright_button_repeat)
+ rep_buttons |= (1 << (6 - 1)) | (1 << (7 - 1));
+
+ /* Handle auto repeat buttons */
+ repeat_delay = clamp(para->scroll_button_repeat, SBR_MIN, SBR_MAX);
+ if (((hw->up || hw->down) && para->updown_button_repeat &&
+ para->updown_button_scrolling) ||
+ ((hw->multi[2] || hw->multi[3]) && para->leftright_button_repeat &&
+ para->leftright_button_scrolling)) {
+ priv->repeatButtons = buttons & rep_buttons;
+ if (!priv->nextRepeat) {
+ priv->nextRepeat = now + repeat_delay * 2;
+ }
+ }
+ else {
+ priv->repeatButtons = 0;
+ priv->nextRepeat = 0;
+ }
+
+ if (priv->repeatButtons) {
+ timeleft = TIME_DIFF(priv->nextRepeat, now);
+ if (timeleft > 0)
+ delay = MIN(delay, timeleft);
+ if (timeleft <= 0) {
+ int change, id;
+
+ change = priv->repeatButtons;
+ while (change) {
+ id = ffs(change);
+ change &= ~(1 << (id - 1));
+ if (id == 4)
+ priv->scroll.delta_y -= para->scroll_dist_vert;
+ else if (id == 5)
+ priv->scroll.delta_y += para->scroll_dist_vert;
+ else if (id == 6)
+ priv->scroll.delta_x -= para->scroll_dist_horiz;
+ else if (id == 7)
+ priv->scroll.delta_x += para->scroll_dist_horiz;
+ }
+
+ priv->nextRepeat = now + repeat_delay;
+ delay = MIN(delay, repeat_delay);
+ }
+ }
+
+ return delay;
+}
+
/* Update the open slots and number of active touches */
static void
UpdateTouchState(InputInfoPtr pInfo, struct SynapticsHwState *hw)
@@ -2849,6 +2966,8 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now,
/* these two just update hw->left, right, etc. */
update_hw_button_state(pInfo, hw, priv->old_hw_state, now, &delay);
+ if (priv->has_scrollbuttons)
+ double_click = adjust_state_from_scrollbuttons(pInfo, hw);
/* now we know that these _coordinates_ aren't in the area.
invalid are: x, y, z, numFingers, fingerWidth
@@ -2940,6 +3059,9 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now,
0, 0);
}
+ if (priv->has_scrollbuttons)
+ delay = repeat_scrollbuttons(pInfo, hw, buttons, now, delay);
+
/* Process scroll events only if coordinates are
* in the Synaptics Area
*/