diff --git a/conf/50-synaptics.conf b/conf/50-synaptics.conf index aa5045651f0bc57cf9aff867611f3e99a1df7bc7..5fb131eef50d1634e1a7a7ea0fa586589bdcab87 100644 --- a/conf/50-synaptics.conf +++ b/conf/50-synaptics.conf @@ -44,3 +44,10 @@ Section "InputClass" MatchDriver "synaptics" Option "SoftButtonAreas" "0 0 0 0 0 0 0 0" EndSection + +Section "InputClass" + Identifier "Lenovo *50 and Carbon 3rd trackpoint buttons" + MatchDriver "synaptics" + MatchTag "has_trackpoint_buttons" + Option "HasTrackpointButtons" "on" +EndSection diff --git a/conf/71-synaptics.rules b/conf/71-synaptics.rules new file mode 100644 index 0000000000000000000000000000000000000000..a7074216c3b5275163e9affdbd5585918b184863 --- /dev/null +++ b/conf/71-synaptics.rules @@ -0,0 +1,10 @@ +ACTION=="remove", GOTO="touchpad_end" +KERNEL!="event*", GOTO="touchpad_end" +ENV{ID_INPUT_TOUCHPAD}=="", GOTO="touchpad_end" + +# Lenovo X1 Carbon 3rd +KERNELS=="serio1", \ + ATTRS{firmware_id}=="*LEN0048*", \ + ENV{ID_INPUT.tags}="has_trackpoint_buttons" + +LABEL="touchpad_end" diff --git a/conf/Makefile.am b/conf/Makefile.am index 38d2a011b011878d138859d3eb837ee8faa85a7c..4dde90287b82f1b81efe49b8e7a66bf275004743 100644 --- a/conf/Makefile.am +++ b/conf/Makefile.am @@ -25,3 +25,10 @@ else fdidir = $(datadir)/hal/fdi/policy/20thirdparty dist_fdi_DATA = 11-x11-synaptics.fdi endif + +if HAVE_UDEV_RULES_DIR +udevdir=$(UDEV_RULES_DIR) +udev_DATA = 71-synaptics.rules +endif + +EXTRA_DIST = 71-synaptics.rules diff --git a/configure.ac b/configure.ac index 0a2bfb6a50e86d1c08809e6dcaa6b1e09469b836..2844da280308221a7cbfb4f9e719f54e86c63ba0 100644 --- a/configure.ac +++ b/configure.ac @@ -135,6 +135,16 @@ AM_CONDITIONAL([BUILD_EVENTCOMM], [test "x${BUILD_EVENTCOMM}" = "xyes"]) AM_CONDITIONAL([BUILD_PSMCOMM], [test "x${BUILD_PSMCOMM}" = "xyes"]) AM_CONDITIONAL([BUILD_PS2COMM], [test "x${BUILD_PS2COMM}" = "xyes"]) +AC_ARG_WITH(udev-rules-dir, + AS_HELP_STRING([--with-udev-rules-dir=DIR], + [Directory where udev expects its rules files + [[default=$libdir/udev/rules.d]]]), + [udevdir="$withval"], + [udevdir="$libdir/udev/rules.d"]) +UDEV_RULES_DIR=${udevdir} +AC_SUBST(UDEV_RULES_DIR) +AM_CONDITIONAL(HAVE_UDEV_RULES_DIR, [test "x$UDEV_RULES_DIR" != "xno"]) + # ----------------------------------------------------------------------------- # Dependencies for synclient and syndaemon # ----------------------------------------------------------------------------- diff --git a/man/synaptics.man b/man/synaptics.man index 7083b3a33e810258df9f9c6026575c7f4bb4d147..65fb337a39f1556bf08e1f4067cb1e172c38ec3c 100644 --- a/man/synaptics.man +++ b/man/synaptics.man @@ -518,6 +518,20 @@ initialized if .B Option \*qHasSecondarySoftButtons\*q is enabled and this option is set in the __xconfigfile__(__filemansuffix__). . +.TP +.BI "Option \*qHasTrackpointButtons\*q \*q" boolean \*q +This option is only available on selected devices. You should never need to +set this option manually, your distribution should ship +__xconfigfile__(__filemansuffix__) snippets to enable this option where +required. Devices that require this option include the Lenovo X1 Carbon 3rd +and the Lenovo *50 series (T450, T550, etc.). +If enabled, the device is considered to have the trackpoint left, middle, +right buttons wired to the touchpad. If set, this option disables scroll +buttons, i.e. +.B Option \*qUpDownScrolling\*q, \*qLeftRightScrolling\*q +and the respective repeat options for scroll buttons. +This options is considered a hardware property and is not exposed as +configurable X Input device property. .SH CONFIGURATION DETAILS .SS Area handling diff --git a/src/synaptics.c b/src/synaptics.c index e6a90f271a9c2d970fc01657d994a26e95b900df..0f0b5b9f8d48aab9a8caea461d8767f07828c556 100644 --- a/src/synaptics.c +++ b/src/synaptics.c @@ -702,6 +702,12 @@ set_default_parameters(InputInfoPtr pInfo) xf86SetBoolOption(opts, "HorizTwoFingerScroll", horizTwoFingerScroll); pars->touchpad_off = xf86SetIntOption(opts, "TouchpadOff", TOUCHPAD_ON); + if (priv->has_scrollbuttons) { + priv->has_trackpoint_buttons = xf86SetBoolOption(opts, "HasTrackpointButtons", FALSE); + if (priv->has_trackpoint_buttons) + priv->has_scrollbuttons = FALSE; + } + if (priv->has_scrollbuttons) { pars->updown_button_scrolling = xf86SetBoolOption(opts, "UpDownScrolling", TRUE); @@ -1081,6 +1087,7 @@ SynapticsReset(SynapticsPrivate * priv) priv->mid_emu_state = MBE_OFF; priv->nextRepeat = 0; priv->lastButtons = 0; + priv->lastTrackpointButtons = 0; priv->prev_z = 0; priv->prevFingers = 0; priv->num_active_touches = 0; @@ -2782,6 +2789,34 @@ handle_clickfinger(SynapticsPrivate * priv, struct SynapticsHwState *hw) } } +static void +handle_trackpoint_buttons(const InputInfoPtr pInfo, + struct SynapticsHwState *hw) +{ + SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private); + unsigned int buttons, change; + int id; + + buttons = (hw->multi[0] ? 0x1 : 0) | + (hw->multi[1] ? 0x4 : 0) | + (hw->multi[2] ? 0x2 : 0); + + change = buttons ^ priv->lastTrackpointButtons; + while (change) { + id = ffs(change); /* number of first set bit 1..32 is returned */ + change &= ~(1 << (id - 1)); + xf86PostButtonEvent(pInfo->dev, FALSE, id, + (buttons & (1 << (id - 1))), + 0, 0); + } + + hw->multi[0] = FALSE; + hw->multi[1] = FALSE; + hw->multi[2] = FALSE; + + priv->lastTrackpointButtons = buttons; +} + /* 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 @@ -3137,6 +3172,13 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now, Bool using_cumulative_coords = FALSE; Bool ignore_motion; + /* if we have phys. trackpoint buttons wired up to the touchpad, process + * them first. They belong to a different device so we don't care about + * sending out motion events before the trackpoint buttons. This makes + * the code a lot easier to slot in */ + if (priv->has_trackpoint_buttons) + handle_trackpoint_buttons(pInfo, hw); + /* We need both and x/y, the driver can't handle just one of the two * yet. But since it's possible to hit a phys button on non-clickpads * without ever getting motion data first, we must continue with 0/0 for diff --git a/src/synapticsstr.h b/src/synapticsstr.h index a17e39b32a95650c9c7b6dd8539a14293761dd73..0bc276d992fa76b6e6493cf7f99de7ec6cc151c6 100644 --- a/src/synapticsstr.h +++ b/src/synapticsstr.h @@ -290,6 +290,7 @@ struct _SynapticsPrivateRec { int repeatButtons; /* buttons for repeat */ int nextRepeat; /* Time when to trigger next auto repeat event */ int lastButtons; /* last state of the buttons */ + int lastTrackpointButtons; /* last state of the trackpoint buttons */ int prev_z; /* previous z value, for palm detection */ int prevFingers; /* previous numFingers, for transition detection */ int avg_width; /* weighted average of previous fingerWidth values */ @@ -309,6 +310,7 @@ struct _SynapticsPrivateRec { Bool has_pressure; /* device reports pressure */ Bool has_width; /* device reports finger width */ Bool has_scrollbuttons; /* device has physical scrollbuttons */ + Bool has_trackpoint_buttons;/* device has trackpoint buttons wired to touchpad */ Bool has_semi_mt; /* device is only semi-multitouch capable */ Bool has_mt_palm_detect; /* device reports per finger width and pressure */