Merge branch 'wip/trackpoint-acceleration'

This commit is contained in:
Peter Hutterer 2018-07-12 16:48:49 +10:00
commit 6511dca633
17 changed files with 472 additions and 428 deletions

View file

@ -33,4 +33,4 @@ MatchBus=ps2
MatchVendor=0x0002
MatchProduct=0x0008
MatchVersion=0x0800
AttrTrackpointRange=160
AttrTrackpointMultiplier=0.125

View file

@ -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

View file

@ -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

View file

@ -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',

View file

@ -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

View 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

View file

@ -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>
*/

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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 */

View file

@ -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"

View file

@ -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)
{

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;
}
}