mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-04 09:20:29 +01:00
Merge branch 'wip/trackpoint-acceleration'
This commit is contained in:
commit
6511dca633
17 changed files with 472 additions and 428 deletions
|
|
@ -33,4 +33,4 @@ MatchBus=ps2
|
|||
MatchVendor=0x0002
|
||||
MatchProduct=0x0008
|
||||
MatchVersion=0x0800
|
||||
AttrTrackpointRange=160
|
||||
AttrTrackpointMultiplier=0.125
|
||||
|
|
|
|||
|
|
@ -5,19 +5,44 @@ MatchName=* Touchpad
|
|||
MatchDMIModalias=dmi:*svnDellInc.:*
|
||||
ModelTouchpadVisibleMarker=1
|
||||
|
||||
[Dell Lattitude E6220]
|
||||
[Dell Lattitude E6220 Touchpad]
|
||||
MatchName=*AlpsPS/2 ALPS GlidePoint
|
||||
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeE6220:*
|
||||
AttrPressureRange=100:90
|
||||
|
||||
[Dell XPS L322X]
|
||||
[Dell XPS L322X Touchpad]
|
||||
MatchName=*CyPS/2 Cypress Trackpad
|
||||
MatchDMIModalias=dmi:*svnDell*:XPSL322X*
|
||||
AttrPressureRange=32:20
|
||||
AttrPalmPressureThreshold=254
|
||||
|
||||
[Dell XPS13 9333]
|
||||
[Dell XPS13 9333 Touchpad]
|
||||
MatchName=*Synaptics s3203
|
||||
MatchDMIModalias=dmi:*svnDellInc.:*pnXPS139333*
|
||||
AttrPressureRange=15:10
|
||||
AttrPalmPressureThreshold=150
|
||||
|
||||
[Dell Latitude D620 Trackpoint]
|
||||
MatchName=*DualPoint Stick
|
||||
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeD620*
|
||||
AttrTrackpointMultiplier=0.5
|
||||
|
||||
[Latitude E5570 Trackpoint]
|
||||
MatchName=*DualPoint Stick
|
||||
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeE5570*
|
||||
AttrTrackpointMultiplier=0.1
|
||||
|
||||
[Latitude E6320 Trackpoint]
|
||||
MatchName=*DualPoint Stick
|
||||
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeE6320*
|
||||
AttrTrackpointMultiplier=2.0
|
||||
|
||||
[Latitude E6400 Trackpoint]
|
||||
MatchName=*DualPoint Stick
|
||||
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeE6400*
|
||||
AttrTrackpointMultiplier=1.5
|
||||
|
||||
[Latitude E7470 Trackpoint]
|
||||
MatchName=*DualPoint Stick
|
||||
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeE7470*
|
||||
AttrTrackpointMultiplier=0.6
|
||||
|
|
|
|||
|
|
@ -20,20 +20,15 @@ MatchName=Synaptics tm2964-001
|
|||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT440p*
|
||||
ModelLenovoT450Touchpad=1
|
||||
|
||||
[Lenovo T440s Trackpoint]
|
||||
MatchName=TPPS/2 IBM TrackPoint
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT440s*
|
||||
AttrTrackpointRange=30
|
||||
[Lenovo X200 Trackpoint]
|
||||
MatchName=*TPPS/2 IBM TrackPoint
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX20?:*
|
||||
AttrTrackpointMultiplier=1.25
|
||||
|
||||
[Lenovo T440s Trackpoint]
|
||||
MatchName=TPPS/2 IBM TrackPoint
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT450s*
|
||||
AttrTrackpointRange=50
|
||||
|
||||
[Lenovo X270 Trackpoint]
|
||||
MatchName=TPPS/2 IBM TrackPoint
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX270*
|
||||
AttrTrackpointRange=40
|
||||
[Lenovo X200x Trackpoint]
|
||||
MatchName=*TPPS/2 IBM TrackPoint
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX20??:*
|
||||
AttrTrackpointMultiplier=1.25
|
||||
|
||||
[Lenovo P50 Touchpad]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
|
|
@ -66,11 +61,6 @@ MatchVendor=0x17EF
|
|||
MatchProduct=0x6047
|
||||
AttrKeyboardIntegration=external
|
||||
|
||||
[Lenovo X280 Trackpoint]
|
||||
MatchName=*ALPS TrackPoint*
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX280:*
|
||||
AttrTrackpointRange=70
|
||||
|
||||
# Lenovo Thinkpad Yoga (not the consumer versions) disables the keyboard
|
||||
# mechanically. We must not disable the keyboard because some keys are
|
||||
# still accessible on the screen and volume rocker.
|
||||
|
|
@ -90,3 +80,9 @@ ModelLenovoCarbonX16th=1
|
|||
MatchName=AT Translated Set 2 keyboard
|
||||
MatchDMIModalias=dmi:*svnIBM:*pvrThinkPadX41Tablet:*
|
||||
ModelTabletModeNoSuspend=1
|
||||
|
||||
[Lenovo UltraNav SK-8845 (USB keyboard) Trackpoint]
|
||||
MatchBus=usb
|
||||
MatchVendor=0x06CB
|
||||
MatchProduct=0x0009
|
||||
AttrTrackpointMultiplier=2.5
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ src_doxygen = files(
|
|||
'svg/thumb-detection.svg',
|
||||
'svg/top-software-buttons.svg',
|
||||
'svg/touchscreen-gestures.svg',
|
||||
'svg/trackpoint-delta-illustration.svg',
|
||||
'svg/twofinger-scrolling.svg',
|
||||
# style files
|
||||
'style/header.html',
|
||||
|
|
|
|||
|
|
@ -114,31 +114,24 @@ that trackpoint speed is a function of pressure rather than moving speed.
|
|||
But trackpoint hardware is quite varied in how it reacts to user pressure
|
||||
and unlike other devices it cannot easily be normalized for physical
|
||||
properties. Measuring pressure objectively across a variety of hardware is
|
||||
nontrivial.
|
||||
nontrivial. See @ref trackpoints for more details.
|
||||
|
||||
libinput's pointer acceleration is a function of the total available
|
||||
pressure range on a device. See @ref trackpoint_range for details.
|
||||
The deltas for trackpoints are converted units/ms but there is no common
|
||||
physical reference point for a unit. Thus, the same pressure on different
|
||||
trackpoints will generate different speeds and thus different acceleration
|
||||
behaviors. Additionally, some trackpoints provide the ability to adjust the
|
||||
sensitivity in hardware by modifying a sysfs file on the serio node. A
|
||||
higher sensitivity results in higher deltas, thus changing the definition of
|
||||
what is a unit again.
|
||||
|
||||
libinput relies on some system-wide configured properties, specifically the
|
||||
@ref udev_config. The property that influences trackpoint acceleration is
|
||||
`LIBINPUT_ATTR_TRACKPOINT_RANGE` which specifies the total delta range for
|
||||
the trackpoint. See @ref trackpoint_range for details.
|
||||
|
||||
Additionally, some trackpoints provide the ability to adjust the sensitivity in
|
||||
hardware by modifying a sysfs file on the serio node. The udev property
|
||||
`POINTINGSTICK_SENSITIVITY` indicates the desired value, a udev
|
||||
builtin is expected to apply this to the device, i.e. libinput does not
|
||||
handle this property. Once applied, the sensitivity adjusts the deltas
|
||||
coming out of the hardware. When the sensitivity changes, the trackpoint
|
||||
range changes and thus the `LIBINPUT_ATTR_TRACKPOINT_RANGE` property
|
||||
becomes invalid.
|
||||
|
||||
As of version 1.9, libinput does not parse the `POINTINGSTICK_CONST_ACCEL` property anymore.
|
||||
libinput attempts to normalize unit data to the best of its abilities, see
|
||||
@ref trackpoint_multiplier. Beyond this, it is not possible to have
|
||||
consistent behavior across different touchpad devices.
|
||||
|
||||
@image html ptraccel-trackpoint.svg "Pointer acceleration curves for trackpoints"
|
||||
|
||||
The image above shows the trackpoint acceleration profile for each input
|
||||
delta.
|
||||
The image above shows the trackpoint acceleration profile for the speed in
|
||||
units/ms.
|
||||
|
||||
@section ptraccel-profile-flat The flat pointer acceleration profile
|
||||
|
||||
|
|
|
|||
126
doc/svg/trackpoint-delta-illustration.svg
Normal file
126
doc/svg/trackpoint-delta-illustration.svg
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<svg
|
||||
width="600" height="480"
|
||||
viewBox="0 0 600 480"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
|
||||
<title>Gnuplot</title>
|
||||
<desc>Produced by GNUPLOT 5.0 patchlevel 6 </desc>
|
||||
|
||||
<g id="gnuplot_canvas">
|
||||
|
||||
<rect x="0" y="0" width="600" height="480" fill="none"/>
|
||||
<defs>
|
||||
|
||||
<circle id='gpDot' r='0.5' stroke-width='0.5'/>
|
||||
<path id='gpPt0' stroke-width='0.222' stroke='currentColor' d='M-1,0 h2 M0,-1 v2'/>
|
||||
<path id='gpPt1' stroke-width='0.222' stroke='currentColor' d='M-1,-1 L1,1 M1,-1 L-1,1'/>
|
||||
<path id='gpPt2' stroke-width='0.222' stroke='currentColor' d='M-1,0 L1,0 M0,-1 L0,1 M-1,-1 L1,1 M-1,1 L1,-1'/>
|
||||
<rect id='gpPt3' stroke-width='0.222' stroke='currentColor' x='-1' y='-1' width='2' height='2'/>
|
||||
<rect id='gpPt4' stroke-width='0.222' stroke='currentColor' fill='currentColor' x='-1' y='-1' width='2' height='2'/>
|
||||
<circle id='gpPt5' stroke-width='0.222' stroke='currentColor' cx='0' cy='0' r='1'/>
|
||||
<use xlink:href='#gpPt5' id='gpPt6' fill='currentColor' stroke='none'/>
|
||||
<path id='gpPt7' stroke-width='0.222' stroke='currentColor' d='M0,-1.33 L-1.33,0.67 L1.33,0.67 z'/>
|
||||
<use xlink:href='#gpPt7' id='gpPt8' fill='currentColor' stroke='none'/>
|
||||
<use xlink:href='#gpPt7' id='gpPt9' stroke='currentColor' transform='rotate(180)'/>
|
||||
<use xlink:href='#gpPt9' id='gpPt10' fill='currentColor' stroke='none'/>
|
||||
<use xlink:href='#gpPt3' id='gpPt11' stroke='currentColor' transform='rotate(45)'/>
|
||||
<use xlink:href='#gpPt11' id='gpPt12' fill='currentColor' stroke='none'/>
|
||||
<path id='gpPt13' stroke-width='0.222' stroke='currentColor' d='M0,1.330 L1.265,0.411 L0.782,-1.067 L-0.782,-1.076 L-1.265,0.411 z'/>
|
||||
<use xlink:href='#gpPt13' id='gpPt14' fill='currentColor' stroke='none'/>
|
||||
<filter id='textbox' filterUnits='objectBoundingBox' x='0' y='0' height='1' width='1'>
|
||||
<feFlood flood-color='white' flood-opacity='1' result='bgnd'/>
|
||||
<feComposite in='SourceGraphic' in2='bgnd' operator='atop'/>
|
||||
</filter>
|
||||
<filter id='greybox' filterUnits='objectBoundingBox' x='0' y='0' height='1' width='1'>
|
||||
<feFlood flood-color='lightgrey' flood-opacity='1' result='grey'/>
|
||||
<feComposite in='SourceGraphic' in2='grey' operator='atop'/>
|
||||
</filter>
|
||||
</defs>
|
||||
<g fill="none" color="white" stroke="currentColor" stroke-width="1.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="1.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="black" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<path stroke='rgb( 0, 0, 0)' d='M20.7,449.4 L575.0,449.4 '/></g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<path stroke='rgb( 0, 0, 0)' d='M20.7,449.4 L20.7,16.7 '/> <g transform="translate(325.6,431.7)" stroke="none" fill="black" font-family="Arial" font-size="12.00" text-anchor="end">
|
||||
<text><tspan font-family="Arial" >minimum possible interval</tspan></text>
|
||||
</g>
|
||||
<g transform="translate(114.9,336.5)" stroke="none" fill="black" font-family="Arial" font-size="12.00" text-anchor="end">
|
||||
<text><tspan font-family="Arial" >delta is 1</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<path stroke='rgb( 0, 0, 0)' d='M346.8,414.9 L353.3,410.5 L345.4,411.0 M328.3,419.1 L353.3,410.5 '/></g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<path stroke='rgb( 0, 0, 0)' d='M120.6,353.0 L126.0,354.2 L121.9,350.5 M109.4,345.6 L126.0,354.2 '/></g>
|
||||
<g fill="none" color="black" stroke="rgb( 0, 0, 0)" stroke-width="1.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="1.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<g transform="translate(297.8,471.3)" stroke="none" fill="black" font-family="Arial" font-size="12.00" text-anchor="middle">
|
||||
<text><tspan font-family="Arial" >physical pressure</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="1.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
</g>
|
||||
<g id="gnuplot_plot_1" ><title>time between events</title>
|
||||
<g fill="none" color="white" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<g transform="translate(507.9,38.6)" stroke="none" fill="black" font-family="Arial" font-size="12.00" text-anchor="end">
|
||||
<text><tspan font-family="Arial" >time between events</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<path stroke='rgb(238, 17, 17)' d='M516.2,34.7 L558.4,34.7 M20.7,16.8 L26.3,25.9 L31.9,33.0 L37.5,40.6 L43.1,52.3 L48.7,57.6
|
||||
L54.3,67.9 L59.9,76.9 L65.5,86.7 L71.1,93.9 L76.7,104.2 L82.3,111.4 L87.9,121.6 L93.5,128.3
|
||||
L99.1,137.5 L104.7,145.9 L110.3,155.0 L115.9,164.1 L121.5,172.6 L127.1,183.2 L132.7,191.6 L138.3,199.0
|
||||
L143.9,209.0 L149.5,217.7 L155.1,225.5 L160.7,235.2 L166.3,243.3 L171.9,253.2 L177.5,260.2 L183.1,269.4
|
||||
L188.7,277.8 L194.3,287.4 L199.9,295.5 L205.5,304.9 L211.1,314.1 L216.7,322.2 L222.3,331.1 L227.9,339.4
|
||||
L233.5,348.9 L239.1,357.3 L244.7,366.0 L250.3,374.7 L255.9,383.9 L261.5,392.4 L267.1,401.3 L272.7,405.9
|
||||
L278.3,406.0 L283.9,405.8 L289.5,406.0 L295.1,405.9 L300.6,406.1 L306.2,406.0 L311.8,406.1 L317.4,406.0
|
||||
L323.0,406.2 L328.6,406.0 L334.2,406.0 L339.8,405.8 L345.4,406.0 L351.0,406.1 L356.6,406.0 L362.2,405.8
|
||||
L367.8,405.9 L373.4,406.2 L379.0,406.0 L384.6,406.0 L390.2,406.1 L395.8,405.8 L401.4,406.0 L407.0,406.1
|
||||
L412.6,405.9 L418.2,406.1 L423.8,406.0 L429.4,405.9 L435.0,406.1 L440.6,406.0 L446.2,406.0 L451.8,405.9
|
||||
L457.4,405.9 L463.0,406.1 L468.6,406.2 L474.2,405.9 L479.8,405.9 L485.4,406.1 L491.0,406.1 L496.6,406.0
|
||||
L502.2,405.9 L507.8,406.0 L513.4,405.8 L519.0,406.0 L524.6,405.9 L530.2,405.8 L535.8,406.2 L541.4,406.2
|
||||
L547.0,405.9 L552.6,406.2 L558.2,406.2 L563.8,406.0 L569.4,405.8 L575.0,406.2 '/></g>
|
||||
</g>
|
||||
<g id="gnuplot_plot_2" ><title>(x, y) delta values</title>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<g transform="translate(507.9,56.6)" stroke="none" fill="black" font-family="Arial" font-size="12.00" text-anchor="end">
|
||||
<text><tspan font-family="Arial" >(x, y) delta values</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<path stroke='rgb( 17, 17, 238)' d='M516.2,52.7 L558.4,52.7 M20.7,362.9 L26.3,362.5 L31.9,362.4 L37.5,362.6 L43.1,363.0 L48.7,362.2
|
||||
L54.3,362.3 L59.9,363.1 L65.5,362.5 L71.1,362.7 L76.7,362.7 L82.3,362.3 L87.9,362.8 L93.5,362.7
|
||||
L99.1,362.7 L104.7,362.9 L110.3,362.2 L115.9,362.4 L121.5,362.6 L127.1,362.5 L132.7,363.0 L138.3,362.9
|
||||
L143.9,362.7 L149.5,362.6 L155.1,362.8 L160.7,363.0 L166.3,362.8 L171.9,362.8 L177.5,362.8 L183.1,363.0
|
||||
L188.7,362.3 L194.3,363.0 L199.9,362.3 L205.5,362.3 L211.1,362.2 L216.7,363.0 L222.3,362.6 L227.9,362.8
|
||||
L233.5,362.6 L239.1,362.8 L244.7,362.8 L250.3,362.5 L255.9,362.6 L261.5,362.7 L267.1,362.4 L272.7,360.9
|
||||
L278.3,358.2 L283.9,355.9 L289.5,352.9 L295.1,349.7 L300.6,346.4 L306.2,343.8 L311.8,341.3 L317.4,338.0
|
||||
L323.0,334.5 L328.6,332.4 L334.2,329.1 L339.8,326.2 L345.4,322.9 L351.0,320.7 L356.6,317.6 L362.2,314.0
|
||||
L367.8,311.4 L373.4,309.0 L379.0,305.1 L384.6,302.3 L390.2,300.7 L395.8,297.0 L401.4,294.2 L407.0,291.7
|
||||
L412.6,288.5 L418.2,284.7 L423.8,282.5 L429.4,279.7 L435.0,275.8 L440.6,274.0 L446.2,271.1 L451.8,267.3
|
||||
L457.4,264.2 L463.0,262.4 L468.6,258.9 L474.2,255.4 L479.8,252.8 L485.4,250.3 L491.0,246.8 L496.6,245.0
|
||||
L502.2,241.2 L507.8,239.3 L513.4,234.8 L519.0,233.1 L524.6,230.0 L530.2,227.6 L535.8,224.9 L541.4,220.6
|
||||
L547.0,218.9 L552.6,214.4 L558.2,212.4 L563.8,210.1 L569.4,206.5 L575.0,203.1 '/></g>
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<path stroke='rgb( 0, 0, 0)' d='M561.5,446.6 L575.0,449.4 L561.5,452.2 M547.3,449.4 L575.0,449.4 '/></g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="2.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
<path stroke='rgb( 0, 0, 0)' d='M17.9,27.1 L20.7,16.7 L23.5,27.1 M20.7,38.3 L20.7,16.7 '/></g>
|
||||
<g fill="none" color="black" stroke="rgb( 0, 0, 0)" stroke-width="1.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
</g>
|
||||
<g fill="none" color="black" stroke="currentColor" stroke-width="1.00" stroke-linecap="butt" stroke-linejoin="miter">
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.9 KiB |
|
|
@ -26,128 +26,144 @@ multiple laptops.
|
|||
|
||||
The values provided by a trackpoint are motion deltas, usually corresponding
|
||||
to the pressure applied to the trackstick. For example, pressure towards the
|
||||
screen on a laptop provides negative y deltas at a fixed rate (e.g. every
|
||||
10ms). As the pressure increases, the delta increases too. As the pressure
|
||||
decreases, the delta decreases until it hits the neutral state.
|
||||
screen on a laptop provides negative y deltas. The reporting rate increases
|
||||
as the pressure increases and once events are reported at the maximum rate,
|
||||
the delta values increase. The figure below shows a rough illustration of
|
||||
this concept. As the pressure
|
||||
decreases, the delta decrease first, then the reporting rate until the
|
||||
trackpoint is in a neutral state and no events are reported. Trackpoint data
|
||||
is hart to generalize, see
|
||||
<a href="https://who-t.blogspot.com/2018/06/observations-on-trackpoint-input-data.html">
|
||||
Observations on trackpoint input data</a> for more details.
|
||||
|
||||
@image html trackpoint-delta-illustration.svg Illustration of the relationship between reporting rate and delta values on a trackpoint
|
||||
|
||||
The delta range itself can vary greatly between laptops, some devices send a
|
||||
maximum delta value of 30, others can go beyond 100. To normalize the motion
|
||||
trackpoint, libinput uses the available delta range and fits its
|
||||
acceleration curve into this range. This requires calibration by the user,
|
||||
see @ref trackpoint_range_measure.
|
||||
maximum delta value of 30, others can go beyond 100. However, the useful
|
||||
delta range is a fraction of the maximum range. It is uncomfortable to exert
|
||||
sufficient pressure to even get close to the maximum ranges.
|
||||
|
||||
@section trackpoint_multiplier The magic trackpoint multiplier
|
||||
|
||||
To accomodate for the wildly different input data on trackpoint, libinput
|
||||
uses a multiplier that is applied to input deltas. Trackpoints that send
|
||||
comparatively high deltas can be "slowed down", trackpoints that send low
|
||||
deltas can be "sped up" to match the expected range. The actual acceleration
|
||||
profile is applied to these pre-multiplied deltas.
|
||||
|
||||
Given a trackpoint delta (dx, dy), a multiplier M and a pointer acceleration
|
||||
function f(dx, dy) → (dx', dy'), the algorithm is effectively:
|
||||
@verbatim
|
||||
f(M * dx, M * dy) → (dx', dy')
|
||||
@endverbatim
|
||||
|
||||
The magic trackpoint multiplier **is not user visible configuration**. It is
|
||||
part of the @ref device-quirks system and provided once per device.
|
||||
User-specific preferences can be adjusted with the pointer acceleration speed
|
||||
setting libinput_device_config_accel_set_speed().
|
||||
|
||||
@subsection trackpoint_multiplier_adjustment Adjusting the magic trackpoint multiplier
|
||||
|
||||
This section only applies if:
|
||||
- the trackpoint default speed (speed setting 0) is unusably slow or
|
||||
unusably fast, **and**
|
||||
- the lowest speed setting (-1) is still too fast **or** the highest speed
|
||||
setting is still too slow, **and**
|
||||
- the @ref device-quirks for this device do not list a trackpoint multiplier
|
||||
(see @ref device-quirks-debugging)
|
||||
|
||||
If the only satisfactory speed settings are less than -0.75 or greater than
|
||||
0.75, a multiplier *may* be required.
|
||||
|
||||
A specific multiplier will apply to **all users with the same laptop
|
||||
model**, so proceed with caution. You must be capable/willing to adjust
|
||||
device quirks, build libinput from source and restart the session frequently
|
||||
to adjust the multiplier. If this does not apply, wait for someone else with
|
||||
the same hardware to do this.
|
||||
|
||||
Finding the correct multiplier is difficult and requires some trial and
|
||||
error. The default multiplier is always 1.0. A value between 0.0 and 1.0
|
||||
slows the trackpoint down, a value above 1.0 speeds the trackpoint up.
|
||||
Values below zero are invalid.
|
||||
|
||||
@note The multiplier is not a configuration to adjust to personal
|
||||
preferences. The multiplier normalizes the input data into a range that can
|
||||
then be configured with the speed setting.
|
||||
|
||||
To adjust the local multiplier, first @ref building_libinput
|
||||
"build libinput from git master". It is not required to install libinput
|
||||
from git. The below assumes that all @ref building_dependencies are already
|
||||
installed.
|
||||
|
||||
@verbatim
|
||||
$ cd path/to/libinput.git
|
||||
|
||||
# Use an approximate multiplier in the quirks file
|
||||
$ cat > data/99-trackpont-override.quirks <<EOF
|
||||
[Trackpoint Override]
|
||||
MatchUdevType=pointingstick
|
||||
AttrTrackpointMultiplier=1.0
|
||||
EOF
|
||||
|
||||
# Use your trackpoint's event node. If the Attr does not show up
|
||||
# then the quirk does not apply to your trackpoint.
|
||||
$ ./builddir/libinput quirks list /dev/input/event18
|
||||
AttrTrackpointMultiplier=1.0
|
||||
|
||||
# Now start a GUI program to debug the trackpoint speed.
|
||||
# ESC closes the debug GUI
|
||||
$ sudo ./builddir/libinput debug-gui
|
||||
@endverbatim
|
||||
|
||||
Replace the multiplier with an approximate value and the event node with
|
||||
your trackpoint's event node. Try to use trackpoint and verify the
|
||||
multiplier is good enough. If not, adjust the `.quirks` file and re-run the
|
||||
`libinput debug-gui`. Note that the `libinput debug-gui` always feels
|
||||
less responsive than libinput would behave in a normal install.
|
||||
|
||||
Once the trackpoint behaves correctly you are ready to test the system
|
||||
libinput:
|
||||
|
||||
@verbatim
|
||||
$ sudo cp data/99-trackpoint-override.quirks /etc/libinput/local-overrides.quirks
|
||||
@endverbatim
|
||||
|
||||
Now verify the override is seen by the system libinput
|
||||
@verbatim
|
||||
$ libinput quirks list
|
||||
AttrTrackpointMultiplier=1.0
|
||||
@endverbatim
|
||||
|
||||
If the multiplier is listed, restart your Wayland session or X server. The
|
||||
new multiplier is now applied to your trackpoint.
|
||||
|
||||
If the trackpoint behavior is acceptable, you are ready to submit this file
|
||||
upstream. First, find add a more precise match for the device so it only
|
||||
applies to the built-in trackpoint on your laptop model. Usually a
|
||||
variation of the following is sufficient:
|
||||
|
||||
@verbatim
|
||||
[Trackpoint Override]
|
||||
MatchUdevType=pointingstick
|
||||
MatchName=*TPPS/2 IBM TrackPoint*
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT440p*
|
||||
AttrTrackpointMultiplier=1.0
|
||||
@endverbatim
|
||||
|
||||
Look at your `/sys/class/dmi/id/modalias` file for the values to add. Verify
|
||||
that `libinput quirks list` still shows the `AttrTrackpointMultiplier`. If
|
||||
it does, then you should @ref reporting_bugs "report a bug" with the contents of
|
||||
the file. Alternatively, file a merge request with the data added.
|
||||
|
||||
|
||||
@section trackpoint_range_measure Measuring the trackpoint range
|
||||
|
||||
This section describes how to measure the trackpoint range and apply @ref
|
||||
device-quirks to make this range known to libinput. libinput provides the tool
|
||||
`libinput measure trackpoint-range` for this task. This is an interactive
|
||||
tool and prints its instructions on the commandline. Example output from
|
||||
this tool is below:
|
||||
This section only applied to libinput version 1.9.x, 1.10.x, and 1.11.x and
|
||||
has been removed. See @ref trackpoint_multiplier for versions 1.12.x and later.
|
||||
|
||||
@verbatim
|
||||
$ sudo libinput measure trackpoint-range
|
||||
This tool measures the commonly used pressure range of the
|
||||
trackpoint. Push the trackpoint:
|
||||
- Four times around the screen edges
|
||||
- From the top left to the bottom right and back, twice
|
||||
- From the top right to the bottom left and back, twice
|
||||
A minimum of 1000 events for each axis is required
|
||||
|
||||
Movements should emulate fast pointer movement on the screen
|
||||
but not use excessive pressure that would not be used
|
||||
during day-to-day movement. For best results, run this tool
|
||||
several times to get an idea of the common range.
|
||||
|
||||
Trackpoint sends: max x: 19, max y: 23 samples [121, 121]
|
||||
@endverbatim
|
||||
|
||||
Once sufficient samples have been collected, the tool prints a simplified
|
||||
histogram for x and y axis deltas. This histogram should be used to
|
||||
<b>estimate</b> the appropriate trackpoint range. For example, let's look at
|
||||
the histogram below:
|
||||
|
||||
@verbatim
|
||||
Histogram for x axis deltas, in counts of 5
|
||||
-30:
|
||||
-29:
|
||||
-28: +
|
||||
-27: +
|
||||
-26: ++
|
||||
-25: ++++
|
||||
-24: +++++
|
||||
-23: ++
|
||||
-22: ++++++
|
||||
-21: +++
|
||||
-20: ++++
|
||||
-19: +++++++
|
||||
-18: ++++++++++++
|
||||
-17: ++++++++++++
|
||||
-16: ++++++++++++
|
||||
-15: ++++
|
||||
-14: +++++
|
||||
-13: +++++
|
||||
-12: ++++++
|
||||
-11: +++++
|
||||
-10: +++
|
||||
-9: ++++
|
||||
-8: +++++++
|
||||
-7: +++++++
|
||||
-6: ++++++++++++
|
||||
-5: ++++++++++++
|
||||
-4: ++++++++++++
|
||||
-3: +++++++++
|
||||
-2: +++++++++
|
||||
-1: ++++++++
|
||||
0: +++++++
|
||||
1: +++++
|
||||
2: +++++
|
||||
3: ++++++
|
||||
4: ++++++
|
||||
5: +++++++
|
||||
6: ++++
|
||||
7: ++
|
||||
8: +++
|
||||
9: +++
|
||||
10: +++
|
||||
11: +++
|
||||
12: +++
|
||||
13: ++++
|
||||
14: ++++++
|
||||
15: ++++
|
||||
16: ++++
|
||||
17: ++++
|
||||
18: ++++++
|
||||
19: +++++++
|
||||
20: ++++
|
||||
21: ++++++
|
||||
22: ++++++
|
||||
23: ++++++
|
||||
24: ++++++
|
||||
25: +++++++++
|
||||
26: +++++++
|
||||
27: ++++++++
|
||||
28: +++++
|
||||
29: ++
|
||||
30: ++
|
||||
31: +
|
||||
32:
|
||||
33:
|
||||
34:
|
||||
@endverbatim
|
||||
|
||||
The 0 delta is the neutral state, each + represents 5 events with that
|
||||
delta value. Note how the curve is distributed, it's not a classic bell
|
||||
curve. That can be a factor of the input provided or the firmware-based
|
||||
pointer acceleration.
|
||||
|
||||
Overall, the majority of events appear to be in the 0-25 range with a few
|
||||
outliers. So the trackpoint range libinput should use for this particular
|
||||
device would be 25. Note how there is a fair bit of guesswork involved, a
|
||||
trackpoint's data is never clean enough to get a definitive value. It is
|
||||
generally better to take a (slightly) smaller range than one too large.
|
||||
|
||||
The device quirk set is `AttrTrackpointRange=25`. See @ref
|
||||
device-quirks for details on how to apply device quirks.
|
||||
If using libinput version 1.11.x or earlier, please see
|
||||
<a href="https://wayland.freedesktop.org/libinput/doc/1.11.0/trackpoints.html#trackpoint_range_measure">
|
||||
the 1.11.0 documentation</a>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
|||
61
src/evdev.c
61
src/evdev.c
|
|
@ -956,7 +956,7 @@ evdev_init_accel(struct evdev_device *device,
|
|||
if (which == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT)
|
||||
filter = create_pointer_accelerator_filter_flat(device->dpi);
|
||||
else if (device->tags & EVDEV_TAG_TRACKPOINT)
|
||||
filter = create_pointer_accelerator_filter_trackpoint(device->trackpoint_range);
|
||||
filter = create_pointer_accelerator_filter_trackpoint(device->trackpoint_multiplier);
|
||||
else if (device->dpi < DEFAULT_MOUSE_DPI)
|
||||
filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi);
|
||||
else
|
||||
|
|
@ -1176,59 +1176,36 @@ evdev_read_wheel_tilt_props(struct evdev_device *device)
|
|||
return flags;
|
||||
}
|
||||
|
||||
static inline int
|
||||
evdev_get_trackpoint_range(struct evdev_device *device)
|
||||
static inline double
|
||||
evdev_get_trackpoint_multiplier(struct evdev_device *device)
|
||||
{
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
const char *prop;
|
||||
uint32_t range = DEFAULT_TRACKPOINT_RANGE;
|
||||
double multiplier = 1.0;
|
||||
|
||||
if (!(device->tags & EVDEV_TAG_TRACKPOINT))
|
||||
return DEFAULT_TRACKPOINT_RANGE;
|
||||
return 1.0;
|
||||
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (q && quirks_get_uint32(q, QUIRK_ATTR_TRACKPOINT_RANGE, &range)) {
|
||||
goto out;
|
||||
if (q) {
|
||||
quirks_get_double(q, QUIRK_ATTR_TRACKPOINT_MULTIPLIER, &multiplier);
|
||||
quirks_unref(q);
|
||||
}
|
||||
|
||||
evdev_log_info(device,
|
||||
"trackpoint does not have a specified range, "
|
||||
"guessing... see %strackpoints.html\n",
|
||||
HTTP_DOC_LINK);
|
||||
|
||||
prop = udev_device_get_property_value(device->udev_device,
|
||||
"POINTINGSTICK_SENSITIVITY");
|
||||
if (prop) {
|
||||
int sensitivity;
|
||||
|
||||
if (!safe_atoi(prop, &sensitivity) ||
|
||||
(sensitivity < 0.0 || sensitivity > 255)) {
|
||||
evdev_log_error(device,
|
||||
"trackpoint sensitivity property is present but invalid, "
|
||||
"using %d instead\n",
|
||||
DEFAULT_TRACKPOINT_SENSITIVITY);
|
||||
sensitivity = DEFAULT_TRACKPOINT_SENSITIVITY;
|
||||
}
|
||||
range = 1.0 * DEFAULT_TRACKPOINT_RANGE *
|
||||
sensitivity/DEFAULT_TRACKPOINT_SENSITIVITY;
|
||||
|
||||
evdev_log_debug(device,
|
||||
"trackpoint udev sensitivity is %d\n",
|
||||
sensitivity);
|
||||
if (multiplier <= 0.0) {
|
||||
evdev_log_bug_libinput(device,
|
||||
"trackpoint multiplier %.2f is invalid\n",
|
||||
multiplier);
|
||||
multiplier = 1.0;
|
||||
}
|
||||
|
||||
out:
|
||||
quirks_unref(q);
|
||||
if (multiplier != 1.0)
|
||||
evdev_log_info(device,
|
||||
"trackpoint device set to range %.2f\n",
|
||||
multiplier);
|
||||
|
||||
if (range == 0) {
|
||||
evdev_log_bug_libinput(device, "trackpoint range is zero\n");
|
||||
range = DEFAULT_TRACKPOINT_RANGE;
|
||||
}
|
||||
|
||||
evdev_log_info(device, "trackpoint device set to range %d\n", range);
|
||||
return range;
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
|
@ -1749,7 +1726,7 @@ evdev_configure_device(struct evdev_device *device)
|
|||
evdev_tag_external_mouse(device, device->udev_device);
|
||||
evdev_tag_trackpoint(device, device->udev_device);
|
||||
device->dpi = evdev_read_dpi_prop(device);
|
||||
device->trackpoint_range = evdev_get_trackpoint_range(device);
|
||||
device->trackpoint_multiplier = evdev_get_trackpoint_multiplier(device);
|
||||
|
||||
device->seat_caps |= EVDEV_DEVICE_POINTER;
|
||||
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ struct evdev_device {
|
|||
bool is_mt;
|
||||
bool is_suspended;
|
||||
int dpi; /* HW resolution */
|
||||
int trackpoint_range; /* trackpoint max delta */
|
||||
double trackpoint_multiplier; /* trackpoint constant multiplier */
|
||||
struct ratelimit syn_drop_limit; /* ratelimit for SYN_DROPPED logging */
|
||||
struct ratelimit nonpointer_rel_limit; /* ratelimit for REL_* events from non-pointer devices */
|
||||
uint32_t model_flags;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright © 2006-2009 Simon Thum
|
||||
* Copyright © 2012 Jonas Ådahl
|
||||
* Copyright © 2014-2015 Red Hat, Inc.
|
||||
* Copyright © 2014-2018 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
|
|
@ -36,121 +36,41 @@
|
|||
#include "libinput-util.h"
|
||||
#include "filter-private.h"
|
||||
|
||||
/* Trackpoint acceleration */
|
||||
#define TRACKPOINT_DEFAULT_MAX_ACCEL 2.0 /* in units/us */
|
||||
#define TRACKPOINT_DEFAULT_MAX_DELTA 120
|
||||
/* As measured on a Lenovo T440 at kernel-default sensitivity 128 */
|
||||
#define TRACKPOINT_DEFAULT_RANGE 20 /* max value */
|
||||
|
||||
struct tablet_accelerator_flat {
|
||||
struct motion_filter base;
|
||||
|
||||
double factor;
|
||||
int xres, yres;
|
||||
double xres_scale, /* 1000dpi : tablet res */
|
||||
yres_scale; /* 1000dpi : tablet res */
|
||||
};
|
||||
|
||||
struct trackpoint_accelerator {
|
||||
struct motion_filter base;
|
||||
|
||||
struct device_float_coords history[4];
|
||||
size_t history_size;
|
||||
struct pointer_trackers trackers;
|
||||
double speed_factor;
|
||||
|
||||
double scale_factor;
|
||||
double max_accel;
|
||||
double max_delta;
|
||||
|
||||
double incline; /* incline of the function */
|
||||
double offset; /* offset of the function */
|
||||
double multiplier;
|
||||
};
|
||||
|
||||
double
|
||||
trackpoint_accel_profile(struct motion_filter *filter,
|
||||
void *data,
|
||||
double delta)
|
||||
double velocity,
|
||||
uint64_t time)
|
||||
{
|
||||
struct trackpoint_accelerator *accel_filter =
|
||||
(struct trackpoint_accelerator *)filter;
|
||||
const double max_accel = accel_filter->max_accel;
|
||||
double factor;
|
||||
|
||||
delta = fabs(delta);
|
||||
velocity = v_us2ms(velocity); /* make it units/ms */
|
||||
|
||||
/* This is almost the equivalent of the xserver acceleration
|
||||
at sensitivity 128 and speed 0.0 */
|
||||
factor = delta * accel_filter->incline + accel_filter->offset;
|
||||
factor = min(factor, max_accel);
|
||||
/* Just a nice-enough curve that provides fluid factor conversion
|
||||
* from the minimum speed up to the real maximum. Generated by
|
||||
* https://www.mycurvefit.com/ with input data
|
||||
* 0 0.3
|
||||
* 0.1 1
|
||||
* 0.4 3
|
||||
* 0.6 4
|
||||
*/
|
||||
factor = 10.06254 + (0.3 - 10.06254)/(1 + pow(velocity/0.9205459, 1.15363));
|
||||
|
||||
factor *= accel_filter->speed_factor;
|
||||
return factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Average the deltas, they are messy and can provide sequences like 7, 7,
|
||||
* 9, 8, 14, 7, 9, 8 ... The outliers cause unpredictable jumps, so average
|
||||
* them out.
|
||||
*/
|
||||
static inline struct device_float_coords
|
||||
trackpoint_average_delta(struct trackpoint_accelerator *filter,
|
||||
const struct device_float_coords *unaccelerated)
|
||||
{
|
||||
size_t i;
|
||||
struct device_float_coords avg = {0};
|
||||
|
||||
memmove(&filter->history[1],
|
||||
&filter->history[0],
|
||||
sizeof(*filter->history) * (filter->history_size - 1));
|
||||
filter->history[0] = *unaccelerated;
|
||||
|
||||
for (i = 0; i < filter->history_size; i++) {
|
||||
avg.x += filter->history[i].x;
|
||||
avg.y += filter->history[i].y;
|
||||
}
|
||||
avg.x /= filter->history_size;
|
||||
avg.y /= filter->history_size;
|
||||
|
||||
return avg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo any system-wide magic scaling, so we're behaving the same regardless
|
||||
* of the trackpoint hardware. This way we can apply our profile independent
|
||||
* of any other configuration that messes with things.
|
||||
*/
|
||||
static inline struct device_float_coords
|
||||
trackpoint_normalize_deltas(const struct trackpoint_accelerator *accel_filter,
|
||||
const struct device_float_coords *delta)
|
||||
{
|
||||
struct device_float_coords scaled = *delta;
|
||||
|
||||
scaled.x *= accel_filter->scale_factor;
|
||||
scaled.y *= accel_filter->scale_factor;
|
||||
|
||||
return scaled;
|
||||
}
|
||||
|
||||
/**
|
||||
* We set a max delta per event, to avoid extreme jumps once we exceed the
|
||||
* expected pressure. Trackpoint hardware is inconsistent once the pressure
|
||||
* gets high, so we can expect sequences like 30, 40, 35, 55, etc. This may
|
||||
* be caused by difficulty keeping up high consistent pressures or just
|
||||
* measuring errors in the hardware. Either way, we cap to a max delta so
|
||||
* once we hit the high pressures, movement is capped and consistent.
|
||||
*/
|
||||
static inline struct normalized_coords
|
||||
trackpoint_clip_to_max_delta(const struct trackpoint_accelerator *accel_filter,
|
||||
struct normalized_coords coords)
|
||||
{
|
||||
const double max_delta = accel_filter->max_delta;
|
||||
|
||||
if (abs(coords.x) > max_delta)
|
||||
coords.x = copysign(max_delta, coords.x);
|
||||
if (abs(coords.y) > max_delta)
|
||||
coords.y = copysign(max_delta, coords.y);
|
||||
|
||||
return coords;
|
||||
}
|
||||
|
||||
static struct normalized_coords
|
||||
trackpoint_accelerator_filter(struct motion_filter *filter,
|
||||
const struct device_float_coords *unaccelerated,
|
||||
|
|
@ -158,23 +78,20 @@ trackpoint_accelerator_filter(struct motion_filter *filter,
|
|||
{
|
||||
struct trackpoint_accelerator *accel_filter =
|
||||
(struct trackpoint_accelerator *)filter;
|
||||
struct device_float_coords scaled;
|
||||
struct device_float_coords avg;
|
||||
struct device_float_coords multiplied;
|
||||
struct normalized_coords coords;
|
||||
double f;
|
||||
double delta;
|
||||
double velocity;
|
||||
|
||||
scaled = trackpoint_normalize_deltas(accel_filter, unaccelerated);
|
||||
avg = trackpoint_average_delta(accel_filter, &scaled);
|
||||
multiplied.x = unaccelerated->x * accel_filter->multiplier;
|
||||
multiplied.y = unaccelerated->y * accel_filter->multiplier;
|
||||
|
||||
delta = hypot(avg.x, avg.y);
|
||||
trackers_feed(&accel_filter->trackers, &multiplied, time);
|
||||
velocity = trackers_velocity(&accel_filter->trackers, time);
|
||||
|
||||
f = trackpoint_accel_profile(filter, data, delta);
|
||||
|
||||
coords.x = avg.x * f;
|
||||
coords.y = avg.y * f;
|
||||
|
||||
coords = trackpoint_clip_to_max_delta(accel_filter, coords);
|
||||
f = trackpoint_accel_profile(filter, data, velocity, time);
|
||||
coords.x = multiplied.x * f;
|
||||
coords.y = multiplied.y * f;
|
||||
|
||||
return coords;
|
||||
}
|
||||
|
|
@ -184,90 +101,74 @@ trackpoint_accelerator_filter_noop(struct motion_filter *filter,
|
|||
const struct device_float_coords *unaccelerated,
|
||||
void *data, uint64_t time)
|
||||
{
|
||||
|
||||
struct trackpoint_accelerator *accel_filter =
|
||||
(struct trackpoint_accelerator *)filter;
|
||||
struct device_float_coords scaled;
|
||||
struct device_float_coords avg;
|
||||
struct normalized_coords coords;
|
||||
|
||||
scaled = trackpoint_normalize_deltas(accel_filter, unaccelerated);
|
||||
avg = trackpoint_average_delta(accel_filter, &scaled);
|
||||
|
||||
coords.x = avg.x;
|
||||
coords.y = avg.y;
|
||||
|
||||
coords = trackpoint_clip_to_max_delta(accel_filter, coords);
|
||||
coords.x = unaccelerated->x * accel_filter->multiplier;
|
||||
coords.y = unaccelerated->y * accel_filter->multiplier;
|
||||
|
||||
return coords;
|
||||
}
|
||||
|
||||
/* Maps the [-1, 1] speed setting into a constant acceleration
|
||||
* range. This isn't a linear scale, we keep 0 as the 'optimized'
|
||||
* mid-point and scale down to 0 for setting -1 and up to 5 for
|
||||
* setting 1. On the premise that if you want a faster cursor, it
|
||||
* doesn't matter as much whether you have 0.56789 or 0.56790,
|
||||
* but for lower settings it does because you may lose movements.
|
||||
* *shrug*.
|
||||
*
|
||||
* Magic numbers calculated by MyCurveFit.com, data points were
|
||||
* 0.0 0.0
|
||||
* 0.1 0.1 (because we need 4 points)
|
||||
* 1 1
|
||||
* 2 5
|
||||
*
|
||||
* This curve fits nicely into the range necessary.
|
||||
*/
|
||||
static inline double
|
||||
speed_factor(double s)
|
||||
{
|
||||
s += 1; /* map to [0, 2] */
|
||||
return 435837.2 + (0.04762636 - 435837.2)/(1 + pow(s/240.4549,
|
||||
2.377168));
|
||||
}
|
||||
|
||||
static bool
|
||||
trackpoint_accelerator_set_speed(struct motion_filter *filter,
|
||||
double speed_adjustment)
|
||||
{
|
||||
struct trackpoint_accelerator *accel_filter =
|
||||
(struct trackpoint_accelerator*)filter;
|
||||
double incline, offset, max;
|
||||
|
||||
assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
|
||||
|
||||
/* Helloooo, magic numbers.
|
||||
|
||||
These numbers were obtained by finding an acceleration curve that
|
||||
provides precision at slow speeds but still provides a good
|
||||
acceleration at higher pressure - and a quick ramp-up to that
|
||||
acceleration.
|
||||
|
||||
Trackpoints have built-in acceleration curves already, so we
|
||||
don't put a new function on top, we merely scale the output from
|
||||
those curves (re-calculating the pressure values from the
|
||||
firmware-defined curve and applying a new curve is unreliable).
|
||||
|
||||
For that basic scaling, we assume a constant factor f based on
|
||||
the speed setting together with a maximum factor m (for this
|
||||
speed setting). Delta acceleration is thus:
|
||||
factor = max(m, f)
|
||||
accelerated_delta = delta * factor;
|
||||
|
||||
Trial and error showed a couple of pairs that work well for the
|
||||
various speed settings (Lenovo T440, sensitivity 128):
|
||||
|
||||
-1.0: f = 0.3, m = 1
|
||||
-0.5: f = 0.6, m = 2
|
||||
0.0: f = 1.0, m = 6
|
||||
0.5: f = 1.4, m = 8
|
||||
1.0: f = 1.9, m = 15
|
||||
|
||||
Note: if f >= 2.0, some pixels are unaddressable
|
||||
|
||||
Those pairs were fed into the linear/exponential regression tool
|
||||
at http://www.xuru.org/rt/LR.asp and show two functions that map
|
||||
speed settings to the respective f and m.
|
||||
Given a speed setting s in [-1.0, 1.0]
|
||||
f(s) = 0.8 * s + 1.04
|
||||
m(s) = 4.6 * e**(1.2 * s)
|
||||
These are close enough to the tested pairs.
|
||||
*/
|
||||
|
||||
max = 4.6 * pow(M_E, 1.2 * speed_adjustment);
|
||||
incline = 0.8 * speed_adjustment + 1.04;
|
||||
offset = 0;
|
||||
|
||||
accel_filter->max_accel = max;
|
||||
accel_filter->incline = incline;
|
||||
accel_filter->offset = offset;
|
||||
filter->speed_adjustment = speed_adjustment;
|
||||
accel_filter->speed_factor = speed_factor(speed_adjustment);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
trackpoint_accelerator_restart(struct motion_filter *filter,
|
||||
void *data,
|
||||
uint64_t time)
|
||||
{
|
||||
struct trackpoint_accelerator *accel =
|
||||
(struct trackpoint_accelerator *) filter;
|
||||
|
||||
trackers_reset(&accel->trackers, time);
|
||||
}
|
||||
|
||||
static void
|
||||
trackpoint_accelerator_destroy(struct motion_filter *filter)
|
||||
{
|
||||
struct trackpoint_accelerator *accel_filter =
|
||||
(struct trackpoint_accelerator *)filter;
|
||||
|
||||
trackers_free(&accel_filter->trackers);
|
||||
free(accel_filter);
|
||||
}
|
||||
|
||||
|
|
@ -275,40 +176,37 @@ struct motion_filter_interface accelerator_interface_trackpoint = {
|
|||
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||
.filter = trackpoint_accelerator_filter,
|
||||
.filter_constant = trackpoint_accelerator_filter_noop,
|
||||
.restart = NULL,
|
||||
.restart = trackpoint_accelerator_restart,
|
||||
.destroy = trackpoint_accelerator_destroy,
|
||||
.set_speed = trackpoint_accelerator_set_speed,
|
||||
};
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_trackpoint(int max_hw_delta)
|
||||
create_pointer_accelerator_filter_trackpoint(double multiplier)
|
||||
{
|
||||
struct trackpoint_accelerator *filter;
|
||||
|
||||
assert(multiplier > 0.0);
|
||||
|
||||
/* Trackpoints are special. They don't have a movement speed like a
|
||||
* mouse or a finger, instead they send a constant stream of events
|
||||
* based on the pressure applied.
|
||||
* mouse or a finger, instead they send a stream of events based on
|
||||
* the pressure applied.
|
||||
*
|
||||
* Physical ranges on a trackpoint are the max values for relative
|
||||
* deltas, but these are highly device-specific.
|
||||
* deltas, but these are highly device-specific and unreliable to
|
||||
* measure.
|
||||
*
|
||||
* Instead, we just have a constant multiplier we have in the quirks
|
||||
* system.
|
||||
*/
|
||||
|
||||
filter = zalloc(sizeof *filter);
|
||||
if (!filter)
|
||||
return NULL;
|
||||
|
||||
filter->history_size = ARRAY_LENGTH(filter->history);
|
||||
filter->max_accel = TRACKPOINT_DEFAULT_MAX_ACCEL;
|
||||
filter->max_delta = TRACKPOINT_DEFAULT_MAX_DELTA;
|
||||
filter->multiplier = multiplier;
|
||||
|
||||
filter->scale_factor = 1.0 * TRACKPOINT_DEFAULT_RANGE / max_hw_delta;
|
||||
|
||||
/* Crop to a maximum 1.0 for the scale factor, otherwise we scale up
|
||||
* events from low-res trackpoints when really we should just take
|
||||
* those as-is.
|
||||
*/
|
||||
filter->scale_factor = min(1.0, filter->scale_factor);
|
||||
trackers_init(&filter->trackers);
|
||||
|
||||
filter->base.interface = &accelerator_interface_trackpoint;
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ struct motion_filter *
|
|||
create_pointer_accelerator_filter_lenovo_x230(int dpi);
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_trackpoint(int max_delta);
|
||||
create_pointer_accelerator_filter_trackpoint(double multiplier);
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_tablet(int xres, int yres);
|
||||
|
|
@ -154,5 +154,6 @@ touchpad_lenovo_x230_accel_profile(struct motion_filter *filter,
|
|||
double
|
||||
trackpoint_accel_profile(struct motion_filter *filter,
|
||||
void *data,
|
||||
double delta);
|
||||
double delta,
|
||||
uint64_t time);
|
||||
#endif /* FILTER_H */
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@
|
|||
|
||||
/* The HW DPI rate we normalize to before calculating pointer acceleration */
|
||||
#define DEFAULT_MOUSE_DPI 1000
|
||||
#define DEFAULT_TRACKPOINT_RANGE 20
|
||||
#define DEFAULT_TRACKPOINT_SENSITIVITY 128
|
||||
|
||||
#define ANSI_HIGHLIGHT "\x1B[0;1;39m"
|
||||
|
|
|
|||
33
src/quirks.c
33
src/quirks.c
|
|
@ -54,6 +54,7 @@ enum property_type {
|
|||
PT_BOOL,
|
||||
PT_DIMENSION,
|
||||
PT_RANGE,
|
||||
PT_DOUBLE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -74,6 +75,7 @@ struct property {
|
|||
char *s;
|
||||
struct quirk_dimensions dim;
|
||||
struct quirk_range range;
|
||||
double d;
|
||||
} value;
|
||||
};
|
||||
|
||||
|
|
@ -262,7 +264,7 @@ quirk_get_name(enum quirk q)
|
|||
case QUIRK_ATTR_PRESSURE_RANGE: return "AttrPressureRange";
|
||||
case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD: return "AttrPalmPressureThreshold";
|
||||
case QUIRK_ATTR_RESOLUTION_HINT: return "AttrResolutionHint";
|
||||
case QUIRK_ATTR_TRACKPOINT_RANGE: return "AttrTrackpointRange";
|
||||
case QUIRK_ATTR_TRACKPOINT_MULTIPLIER: return "AttrTrackpointMultiplier";
|
||||
case QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD: return "AttrThumbPressureThreshold";
|
||||
default:
|
||||
abort();
|
||||
|
|
@ -640,6 +642,7 @@ parse_attr(struct quirks_context *ctx,
|
|||
struct quirk_dimensions dim;
|
||||
struct quirk_range range;
|
||||
unsigned int v;
|
||||
double d;
|
||||
|
||||
if (streq(key, quirk_get_name(QUIRK_ATTR_SIZE_HINT))) {
|
||||
p->id = QUIRK_ATTR_SIZE_HINT;
|
||||
|
|
@ -705,12 +708,12 @@ parse_attr(struct quirks_context *ctx,
|
|||
p->type = PT_DIMENSION;
|
||||
p->value.dim = dim;
|
||||
rc = true;
|
||||
} else if (streq(key, quirk_get_name(QUIRK_ATTR_TRACKPOINT_RANGE))) {
|
||||
p->id = QUIRK_ATTR_TRACKPOINT_RANGE;
|
||||
if (!safe_atou(value, &v))
|
||||
} else if (streq(key, quirk_get_name(QUIRK_ATTR_TRACKPOINT_MULTIPLIER))) {
|
||||
p->id = QUIRK_ATTR_TRACKPOINT_MULTIPLIER;
|
||||
if (!safe_atod(value, &d))
|
||||
goto out;
|
||||
p->type = PT_UINT;
|
||||
p->value.u = v;
|
||||
p->type = PT_DOUBLE;
|
||||
p->value.d = d;
|
||||
rc = true;
|
||||
} else if (streq(key, quirk_get_name(QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD))) {
|
||||
p->id = QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD;
|
||||
|
|
@ -1434,6 +1437,24 @@ quirks_get_uint32(struct quirks *q, enum quirk which, uint32_t *val)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
quirks_get_double(struct quirks *q, enum quirk which, double *val)
|
||||
{
|
||||
struct property *p;
|
||||
|
||||
if (!q)
|
||||
return false;
|
||||
|
||||
p = quirk_find_prop(q, which);
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
assert(p->type == PT_DOUBLE);
|
||||
*val = p->value.d;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
quirks_get_string(struct quirks *q, enum quirk which, char **val)
|
||||
{
|
||||
|
|
|
|||
15
src/quirks.h
15
src/quirks.h
|
|
@ -93,7 +93,7 @@ enum quirk {
|
|||
QUIRK_ATTR_PRESSURE_RANGE,
|
||||
QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
|
||||
QUIRK_ATTR_RESOLUTION_HINT,
|
||||
QUIRK_ATTR_TRACKPOINT_RANGE,
|
||||
QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
|
||||
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
|
||||
};
|
||||
|
||||
|
|
@ -216,6 +216,19 @@ quirks_get_int32(struct quirks *q,
|
|||
enum quirk which,
|
||||
int32_t *val);
|
||||
|
||||
/**
|
||||
* Get the value of the given quirk, as double.
|
||||
* This function will assert if the quirk type does not match the
|
||||
* requested type. If the quirk is not set for this device, val is
|
||||
* unchanged.
|
||||
*
|
||||
* @return true if the quirk value is valid, false otherwise.
|
||||
*/
|
||||
bool
|
||||
quirks_get_double(struct quirks *q,
|
||||
enum quirk which,
|
||||
double *val);
|
||||
|
||||
/**
|
||||
* Get the value of the given quirk, as string.
|
||||
* This function will assert if the quirk type does not match the
|
||||
|
|
|
|||
|
|
@ -69,20 +69,19 @@ plot for [s in speeds] fname(s) using 1:2 title s, \
|
|||
EOF
|
||||
|
||||
outfile="ptraccel-trackpoint"
|
||||
$tool --mode=accel --dpi=1000 --filter=linear > $outfile-mouse.gnuplot
|
||||
for speed in $speeds; do
|
||||
$tool --mode=accel --speed=$speed --filter=trackpoint > $outfile-$speed.gnuplot
|
||||
done
|
||||
$gnuplot <<EOF
|
||||
set terminal svg enhanced background rgb 'white'
|
||||
set output "$outfile.svg"
|
||||
set xlabel "delta (units)"
|
||||
set xlabel "delta (units/ms)"
|
||||
set ylabel "accel factor"
|
||||
set style data lines
|
||||
set yrange [0:5]
|
||||
set xrange [0:20]
|
||||
set xrange [0:1]
|
||||
speeds="$speeds"
|
||||
fname(s)=sprintf("$outfile-%s.gnuplot", s)
|
||||
plot for [s in speeds] fname(s) using 1:2 title s, \
|
||||
plot for [s in speeds] fname(s) using 4:2 title s, \
|
||||
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -161,29 +161,12 @@ print_accel_func(struct motion_filter *filter,
|
|||
printf("# set style data lines\n");
|
||||
printf("# plot \"gnuplot.data\" using 1:2 title 'accel factor'\n");
|
||||
printf("#\n");
|
||||
printf("# data: velocity(mm/s) factor velocity(units/us)\n");
|
||||
printf("# data: velocity(mm/s) factor velocity(units/us) velocity(units/ms)\n");
|
||||
for (mmps = 0.0; mmps < 1000.0; mmps += 1) {
|
||||
double units_per_us = mmps_to_upus(mmps, dpi);
|
||||
double units_per_ms = units_per_us * 1000.0;
|
||||
double result = profile(filter, NULL, units_per_us, 0 /* time */);
|
||||
printf("%.8f\t%.4f\t%.8f\n", mmps, result, units_per_us);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_accel_func_trackpoint(struct motion_filter *filter,
|
||||
int max)
|
||||
{
|
||||
printf("# gnuplot:\n");
|
||||
printf("# set xlabel \"deltas (units)\"\n");
|
||||
printf("# set ylabel \"raw accel factor\"\n");
|
||||
printf("# set style data lines\n");
|
||||
printf("# plot \"gnuplot.data\" using 1:2 title 'accel factor'\n");
|
||||
printf("#\n");
|
||||
printf("# data: delta(units) factor\n");
|
||||
for (double delta = 0; delta < max; delta += 0.2) {
|
||||
double factor = trackpoint_accel_profile(filter, NULL, delta);
|
||||
|
||||
printf("%.2f %f\n", delta, factor);
|
||||
printf("%.8f\t%.4f\t%.8f\t%.8f\n", mmps, result, units_per_us, units_per_ms);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +185,6 @@ usage(void)
|
|||
"--steps=<double> ... in motion and delta modes only. Increase dx by step each round\n"
|
||||
"--speed=<double> ... accel speed [-1, 1], default 0\n"
|
||||
"--dpi=<int> ... device resolution in DPI (default: 1000)\n"
|
||||
"--trackpoint-range=<int> ... range of the trackpoint deltas (default: 20)\n"
|
||||
"--filter=<linear|low-dpi|touchpad|x230|trackpoint> \n"
|
||||
" linear ... the default motion filter\n"
|
||||
" low-dpi ... low-dpi filter, use --dpi with this argument\n"
|
||||
|
|
@ -253,7 +235,6 @@ main(int argc, char **argv)
|
|||
OPT_SPEED,
|
||||
OPT_DPI,
|
||||
OPT_FILTER,
|
||||
OPT_TRACKPOINT_RANGE,
|
||||
};
|
||||
|
||||
while (1) {
|
||||
|
|
@ -268,7 +249,6 @@ main(int argc, char **argv)
|
|||
{"speed", 1, 0, OPT_SPEED },
|
||||
{"dpi", 1, 0, OPT_DPI },
|
||||
{"filter", 1, 0, OPT_FILTER },
|
||||
{"trackpoint-range", 1, 0, OPT_TRACKPOINT_RANGE },
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
|
@ -326,9 +306,6 @@ main(int argc, char **argv)
|
|||
case OPT_FILTER:
|
||||
filter_type = optarg;
|
||||
break;
|
||||
case OPT_TRACKPOINT_RANGE:
|
||||
tp_range_max = strtod(optarg, NULL);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(1);
|
||||
|
|
@ -350,7 +327,7 @@ main(int argc, char **argv)
|
|||
profile = touchpad_lenovo_x230_accel_profile;
|
||||
} else if (streq(filter_type, "trackpoint")) {
|
||||
filter = create_pointer_accelerator_filter_trackpoint(tp_range_max);
|
||||
profile = NULL; /* trackpoint is special */
|
||||
profile = trackpoint_accel_profile;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid filter type %s\n", filter_type);
|
||||
return 1;
|
||||
|
|
@ -381,10 +358,7 @@ main(int argc, char **argv)
|
|||
|
||||
switch (mode) {
|
||||
case ACCEL:
|
||||
if (!profile) /* trackpoint */
|
||||
print_accel_func_trackpoint(filter, tp_range_max);
|
||||
else
|
||||
print_accel_func(filter, profile, dpi);
|
||||
print_accel_func(filter, profile, dpi);
|
||||
break;
|
||||
case DELTA:
|
||||
print_ptraccel_deltas(filter, step);
|
||||
|
|
|
|||
|
|
@ -615,7 +615,7 @@ tools_list_device_quirks(struct quirks_context *ctx,
|
|||
QUIRK_ATTR_PRESSURE_RANGE,
|
||||
QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
|
||||
QUIRK_ATTR_RESOLUTION_HINT,
|
||||
QUIRK_ATTR_TRACKPOINT_RANGE,
|
||||
QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
|
||||
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
|
||||
};
|
||||
enum quirk *q;
|
||||
|
|
@ -630,6 +630,7 @@ tools_list_device_quirks(struct quirks_context *ctx,
|
|||
struct quirk_range r;
|
||||
uint32_t v;
|
||||
char *s;
|
||||
double d;
|
||||
|
||||
if (!quirks_has_quirk(quirks, *q))
|
||||
continue;
|
||||
|
|
@ -682,7 +683,6 @@ tools_list_device_quirks(struct quirks_context *ctx,
|
|||
break;
|
||||
case QUIRK_ATTR_PALM_SIZE_THRESHOLD:
|
||||
case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD:
|
||||
case QUIRK_ATTR_TRACKPOINT_RANGE:
|
||||
case QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD:
|
||||
quirks_get_uint32(quirks, *q, &v);
|
||||
snprintf(buf, sizeof(buf), "%s=%u", name, v);
|
||||
|
|
@ -695,6 +695,11 @@ tools_list_device_quirks(struct quirks_context *ctx,
|
|||
snprintf(buf, sizeof(buf), "%s=%s", name, s);
|
||||
callback(userdata, buf);
|
||||
break;
|
||||
case QUIRK_ATTR_TRACKPOINT_MULTIPLIER:
|
||||
quirks_get_double(quirks, *q, &d);
|
||||
snprintf(buf, sizeof(buf), "%s=%0.2f\n", name, d);
|
||||
callback(userdata, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue