mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-05-09 07:08:01 +02: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
|
MatchVendor=0x0002
|
||||||
MatchProduct=0x0008
|
MatchProduct=0x0008
|
||||||
MatchVersion=0x0800
|
MatchVersion=0x0800
|
||||||
AttrTrackpointRange=160
|
AttrTrackpointMultiplier=0.125
|
||||||
|
|
|
||||||
|
|
@ -5,19 +5,44 @@ MatchName=* Touchpad
|
||||||
MatchDMIModalias=dmi:*svnDellInc.:*
|
MatchDMIModalias=dmi:*svnDellInc.:*
|
||||||
ModelTouchpadVisibleMarker=1
|
ModelTouchpadVisibleMarker=1
|
||||||
|
|
||||||
[Dell Lattitude E6220]
|
[Dell Lattitude E6220 Touchpad]
|
||||||
MatchName=*AlpsPS/2 ALPS GlidePoint
|
MatchName=*AlpsPS/2 ALPS GlidePoint
|
||||||
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeE6220:*
|
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeE6220:*
|
||||||
AttrPressureRange=100:90
|
AttrPressureRange=100:90
|
||||||
|
|
||||||
[Dell XPS L322X]
|
[Dell XPS L322X Touchpad]
|
||||||
MatchName=*CyPS/2 Cypress Trackpad
|
MatchName=*CyPS/2 Cypress Trackpad
|
||||||
MatchDMIModalias=dmi:*svnDell*:XPSL322X*
|
MatchDMIModalias=dmi:*svnDell*:XPSL322X*
|
||||||
AttrPressureRange=32:20
|
AttrPressureRange=32:20
|
||||||
AttrPalmPressureThreshold=254
|
AttrPalmPressureThreshold=254
|
||||||
|
|
||||||
[Dell XPS13 9333]
|
[Dell XPS13 9333 Touchpad]
|
||||||
MatchName=*Synaptics s3203
|
MatchName=*Synaptics s3203
|
||||||
MatchDMIModalias=dmi:*svnDellInc.:*pnXPS139333*
|
MatchDMIModalias=dmi:*svnDellInc.:*pnXPS139333*
|
||||||
AttrPressureRange=15:10
|
AttrPressureRange=15:10
|
||||||
AttrPalmPressureThreshold=150
|
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*
|
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT440p*
|
||||||
ModelLenovoT450Touchpad=1
|
ModelLenovoT450Touchpad=1
|
||||||
|
|
||||||
[Lenovo T440s Trackpoint]
|
[Lenovo X200 Trackpoint]
|
||||||
MatchName=TPPS/2 IBM TrackPoint
|
MatchName=*TPPS/2 IBM TrackPoint
|
||||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT440s*
|
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX20?:*
|
||||||
AttrTrackpointRange=30
|
AttrTrackpointMultiplier=1.25
|
||||||
|
|
||||||
[Lenovo T440s Trackpoint]
|
[Lenovo X200x Trackpoint]
|
||||||
MatchName=TPPS/2 IBM TrackPoint
|
MatchName=*TPPS/2 IBM TrackPoint
|
||||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT450s*
|
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX20??:*
|
||||||
AttrTrackpointRange=50
|
AttrTrackpointMultiplier=1.25
|
||||||
|
|
||||||
[Lenovo X270 Trackpoint]
|
|
||||||
MatchName=TPPS/2 IBM TrackPoint
|
|
||||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX270*
|
|
||||||
AttrTrackpointRange=40
|
|
||||||
|
|
||||||
[Lenovo P50 Touchpad]
|
[Lenovo P50 Touchpad]
|
||||||
MatchName=SynPS/2 Synaptics TouchPad
|
MatchName=SynPS/2 Synaptics TouchPad
|
||||||
|
|
@ -66,11 +61,6 @@ MatchVendor=0x17EF
|
||||||
MatchProduct=0x6047
|
MatchProduct=0x6047
|
||||||
AttrKeyboardIntegration=external
|
AttrKeyboardIntegration=external
|
||||||
|
|
||||||
[Lenovo X280 Trackpoint]
|
|
||||||
MatchName=*ALPS TrackPoint*
|
|
||||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX280:*
|
|
||||||
AttrTrackpointRange=70
|
|
||||||
|
|
||||||
# Lenovo Thinkpad Yoga (not the consumer versions) disables the keyboard
|
# Lenovo Thinkpad Yoga (not the consumer versions) disables the keyboard
|
||||||
# mechanically. We must not disable the keyboard because some keys are
|
# mechanically. We must not disable the keyboard because some keys are
|
||||||
# still accessible on the screen and volume rocker.
|
# still accessible on the screen and volume rocker.
|
||||||
|
|
@ -90,3 +80,9 @@ ModelLenovoCarbonX16th=1
|
||||||
MatchName=AT Translated Set 2 keyboard
|
MatchName=AT Translated Set 2 keyboard
|
||||||
MatchDMIModalias=dmi:*svnIBM:*pvrThinkPadX41Tablet:*
|
MatchDMIModalias=dmi:*svnIBM:*pvrThinkPadX41Tablet:*
|
||||||
ModelTabletModeNoSuspend=1
|
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/thumb-detection.svg',
|
||||||
'svg/top-software-buttons.svg',
|
'svg/top-software-buttons.svg',
|
||||||
'svg/touchscreen-gestures.svg',
|
'svg/touchscreen-gestures.svg',
|
||||||
|
'svg/trackpoint-delta-illustration.svg',
|
||||||
'svg/twofinger-scrolling.svg',
|
'svg/twofinger-scrolling.svg',
|
||||||
# style files
|
# style files
|
||||||
'style/header.html',
|
'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
|
But trackpoint hardware is quite varied in how it reacts to user pressure
|
||||||
and unlike other devices it cannot easily be normalized for physical
|
and unlike other devices it cannot easily be normalized for physical
|
||||||
properties. Measuring pressure objectively across a variety of hardware is
|
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
|
The deltas for trackpoints are converted units/ms but there is no common
|
||||||
pressure range on a device. See @ref trackpoint_range for details.
|
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
|
libinput attempts to normalize unit data to the best of its abilities, see
|
||||||
@ref udev_config. The property that influences trackpoint acceleration is
|
@ref trackpoint_multiplier. Beyond this, it is not possible to have
|
||||||
`LIBINPUT_ATTR_TRACKPOINT_RANGE` which specifies the total delta range for
|
consistent behavior across different touchpad devices.
|
||||||
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.
|
|
||||||
|
|
||||||
@image html ptraccel-trackpoint.svg "Pointer acceleration curves for trackpoints"
|
@image html ptraccel-trackpoint.svg "Pointer acceleration curves for trackpoints"
|
||||||
|
|
||||||
The image above shows the trackpoint acceleration profile for each input
|
The image above shows the trackpoint acceleration profile for the speed in
|
||||||
delta.
|
units/ms.
|
||||||
|
|
||||||
@section ptraccel-profile-flat The flat pointer acceleration profile
|
@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
|
The values provided by a trackpoint are motion deltas, usually corresponding
|
||||||
to the pressure applied to the trackstick. For example, pressure towards the
|
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
|
screen on a laptop provides negative y deltas. The reporting rate increases
|
||||||
10ms). As the pressure increases, the delta increases too. As the pressure
|
as the pressure increases and once events are reported at the maximum rate,
|
||||||
decreases, the delta decreases until it hits the neutral state.
|
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
|
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
|
maximum delta value of 30, others can go beyond 100. However, the useful
|
||||||
trackpoint, libinput uses the available delta range and fits its
|
delta range is a fraction of the maximum range. It is uncomfortable to exert
|
||||||
acceleration curve into this range. This requires calibration by the user,
|
sufficient pressure to even get close to the maximum ranges.
|
||||||
see @ref trackpoint_range_measure.
|
|
||||||
|
@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
|
@section trackpoint_range_measure Measuring the trackpoint range
|
||||||
|
|
||||||
This section describes how to measure the trackpoint range and apply @ref
|
This section only applied to libinput version 1.9.x, 1.10.x, and 1.11.x and
|
||||||
device-quirks to make this range known to libinput. libinput provides the tool
|
has been removed. See @ref trackpoint_multiplier for versions 1.12.x and later.
|
||||||
`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:
|
|
||||||
|
|
||||||
@verbatim
|
If using libinput version 1.11.x or earlier, please see
|
||||||
$ sudo libinput measure trackpoint-range
|
<a href="https://wayland.freedesktop.org/libinput/doc/1.11.0/trackpoints.html#trackpoint_range_measure">
|
||||||
This tool measures the commonly used pressure range of the
|
the 1.11.0 documentation</a>
|
||||||
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.
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
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)
|
if (which == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT)
|
||||||
filter = create_pointer_accelerator_filter_flat(device->dpi);
|
filter = create_pointer_accelerator_filter_flat(device->dpi);
|
||||||
else if (device->tags & EVDEV_TAG_TRACKPOINT)
|
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)
|
else if (device->dpi < DEFAULT_MOUSE_DPI)
|
||||||
filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi);
|
filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi);
|
||||||
else
|
else
|
||||||
|
|
@ -1176,59 +1176,36 @@ evdev_read_wheel_tilt_props(struct evdev_device *device)
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline double
|
||||||
evdev_get_trackpoint_range(struct evdev_device *device)
|
evdev_get_trackpoint_multiplier(struct evdev_device *device)
|
||||||
{
|
{
|
||||||
struct quirks_context *quirks;
|
struct quirks_context *quirks;
|
||||||
struct quirks *q;
|
struct quirks *q;
|
||||||
const char *prop;
|
double multiplier = 1.0;
|
||||||
uint32_t range = DEFAULT_TRACKPOINT_RANGE;
|
|
||||||
|
|
||||||
if (!(device->tags & EVDEV_TAG_TRACKPOINT))
|
if (!(device->tags & EVDEV_TAG_TRACKPOINT))
|
||||||
return DEFAULT_TRACKPOINT_RANGE;
|
return 1.0;
|
||||||
|
|
||||||
quirks = evdev_libinput_context(device)->quirks;
|
quirks = evdev_libinput_context(device)->quirks;
|
||||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||||
if (q && quirks_get_uint32(q, QUIRK_ATTR_TRACKPOINT_RANGE, &range)) {
|
if (q) {
|
||||||
goto out;
|
quirks_get_double(q, QUIRK_ATTR_TRACKPOINT_MULTIPLIER, &multiplier);
|
||||||
|
quirks_unref(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
evdev_log_info(device,
|
if (multiplier <= 0.0) {
|
||||||
"trackpoint does not have a specified range, "
|
evdev_log_bug_libinput(device,
|
||||||
"guessing... see %strackpoints.html\n",
|
"trackpoint multiplier %.2f is invalid\n",
|
||||||
HTTP_DOC_LINK);
|
multiplier);
|
||||||
|
multiplier = 1.0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
if (multiplier != 1.0)
|
||||||
quirks_unref(q);
|
evdev_log_info(device,
|
||||||
|
"trackpoint device set to range %.2f\n",
|
||||||
|
multiplier);
|
||||||
|
|
||||||
if (range == 0) {
|
return multiplier;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
|
@ -1749,7 +1726,7 @@ evdev_configure_device(struct evdev_device *device)
|
||||||
evdev_tag_external_mouse(device, device->udev_device);
|
evdev_tag_external_mouse(device, device->udev_device);
|
||||||
evdev_tag_trackpoint(device, device->udev_device);
|
evdev_tag_trackpoint(device, device->udev_device);
|
||||||
device->dpi = evdev_read_dpi_prop(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;
|
device->seat_caps |= EVDEV_DEVICE_POINTER;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ struct evdev_device {
|
||||||
bool is_mt;
|
bool is_mt;
|
||||||
bool is_suspended;
|
bool is_suspended;
|
||||||
int dpi; /* HW resolution */
|
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 syn_drop_limit; /* ratelimit for SYN_DROPPED logging */
|
||||||
struct ratelimit nonpointer_rel_limit; /* ratelimit for REL_* events from non-pointer devices */
|
struct ratelimit nonpointer_rel_limit; /* ratelimit for REL_* events from non-pointer devices */
|
||||||
uint32_t model_flags;
|
uint32_t model_flags;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright © 2006-2009 Simon Thum
|
* Copyright © 2006-2009 Simon Thum
|
||||||
* Copyright © 2012 Jonas Ådahl
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
|
@ -36,121 +36,41 @@
|
||||||
#include "libinput-util.h"
|
#include "libinput-util.h"
|
||||||
#include "filter-private.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 trackpoint_accelerator {
|
||||||
struct motion_filter base;
|
struct motion_filter base;
|
||||||
|
|
||||||
struct device_float_coords history[4];
|
struct pointer_trackers trackers;
|
||||||
size_t history_size;
|
double speed_factor;
|
||||||
|
|
||||||
double scale_factor;
|
double multiplier;
|
||||||
double max_accel;
|
|
||||||
double max_delta;
|
|
||||||
|
|
||||||
double incline; /* incline of the function */
|
|
||||||
double offset; /* offset of the function */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
double
|
double
|
||||||
trackpoint_accel_profile(struct motion_filter *filter,
|
trackpoint_accel_profile(struct motion_filter *filter,
|
||||||
void *data,
|
void *data,
|
||||||
double delta)
|
double velocity,
|
||||||
|
uint64_t time)
|
||||||
{
|
{
|
||||||
struct trackpoint_accelerator *accel_filter =
|
struct trackpoint_accelerator *accel_filter =
|
||||||
(struct trackpoint_accelerator *)filter;
|
(struct trackpoint_accelerator *)filter;
|
||||||
const double max_accel = accel_filter->max_accel;
|
|
||||||
double factor;
|
double factor;
|
||||||
|
|
||||||
delta = fabs(delta);
|
velocity = v_us2ms(velocity); /* make it units/ms */
|
||||||
|
|
||||||
/* This is almost the equivalent of the xserver acceleration
|
/* Just a nice-enough curve that provides fluid factor conversion
|
||||||
at sensitivity 128 and speed 0.0 */
|
* from the minimum speed up to the real maximum. Generated by
|
||||||
factor = delta * accel_filter->incline + accel_filter->offset;
|
* https://www.mycurvefit.com/ with input data
|
||||||
factor = min(factor, max_accel);
|
* 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;
|
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
|
static struct normalized_coords
|
||||||
trackpoint_accelerator_filter(struct motion_filter *filter,
|
trackpoint_accelerator_filter(struct motion_filter *filter,
|
||||||
const struct device_float_coords *unaccelerated,
|
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 *accel_filter =
|
||||||
(struct trackpoint_accelerator *)filter;
|
(struct trackpoint_accelerator *)filter;
|
||||||
struct device_float_coords scaled;
|
struct device_float_coords multiplied;
|
||||||
struct device_float_coords avg;
|
|
||||||
struct normalized_coords coords;
|
struct normalized_coords coords;
|
||||||
double f;
|
double f;
|
||||||
double delta;
|
double velocity;
|
||||||
|
|
||||||
scaled = trackpoint_normalize_deltas(accel_filter, unaccelerated);
|
multiplied.x = unaccelerated->x * accel_filter->multiplier;
|
||||||
avg = trackpoint_average_delta(accel_filter, &scaled);
|
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);
|
f = trackpoint_accel_profile(filter, data, velocity, time);
|
||||||
|
coords.x = multiplied.x * f;
|
||||||
coords.x = avg.x * f;
|
coords.y = multiplied.y * f;
|
||||||
coords.y = avg.y * f;
|
|
||||||
|
|
||||||
coords = trackpoint_clip_to_max_delta(accel_filter, coords);
|
|
||||||
|
|
||||||
return coords;
|
return coords;
|
||||||
}
|
}
|
||||||
|
|
@ -184,90 +101,74 @@ trackpoint_accelerator_filter_noop(struct motion_filter *filter,
|
||||||
const struct device_float_coords *unaccelerated,
|
const struct device_float_coords *unaccelerated,
|
||||||
void *data, uint64_t time)
|
void *data, uint64_t time)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct trackpoint_accelerator *accel_filter =
|
struct trackpoint_accelerator *accel_filter =
|
||||||
(struct trackpoint_accelerator *)filter;
|
(struct trackpoint_accelerator *)filter;
|
||||||
struct device_float_coords scaled;
|
|
||||||
struct device_float_coords avg;
|
|
||||||
struct normalized_coords coords;
|
struct normalized_coords coords;
|
||||||
|
|
||||||
scaled = trackpoint_normalize_deltas(accel_filter, unaccelerated);
|
coords.x = unaccelerated->x * accel_filter->multiplier;
|
||||||
avg = trackpoint_average_delta(accel_filter, &scaled);
|
coords.y = unaccelerated->y * accel_filter->multiplier;
|
||||||
|
|
||||||
coords.x = avg.x;
|
|
||||||
coords.y = avg.y;
|
|
||||||
|
|
||||||
coords = trackpoint_clip_to_max_delta(accel_filter, coords);
|
|
||||||
|
|
||||||
return coords;
|
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
|
static bool
|
||||||
trackpoint_accelerator_set_speed(struct motion_filter *filter,
|
trackpoint_accelerator_set_speed(struct motion_filter *filter,
|
||||||
double speed_adjustment)
|
double speed_adjustment)
|
||||||
{
|
{
|
||||||
struct trackpoint_accelerator *accel_filter =
|
struct trackpoint_accelerator *accel_filter =
|
||||||
(struct trackpoint_accelerator*)filter;
|
(struct trackpoint_accelerator*)filter;
|
||||||
double incline, offset, max;
|
|
||||||
|
|
||||||
assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
|
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;
|
filter->speed_adjustment = speed_adjustment;
|
||||||
|
accel_filter->speed_factor = speed_factor(speed_adjustment);
|
||||||
|
|
||||||
|
|
||||||
return true;
|
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
|
static void
|
||||||
trackpoint_accelerator_destroy(struct motion_filter *filter)
|
trackpoint_accelerator_destroy(struct motion_filter *filter)
|
||||||
{
|
{
|
||||||
struct trackpoint_accelerator *accel_filter =
|
struct trackpoint_accelerator *accel_filter =
|
||||||
(struct trackpoint_accelerator *)filter;
|
(struct trackpoint_accelerator *)filter;
|
||||||
|
|
||||||
|
trackers_free(&accel_filter->trackers);
|
||||||
free(accel_filter);
|
free(accel_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,40 +176,37 @@ struct motion_filter_interface accelerator_interface_trackpoint = {
|
||||||
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
.type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||||
.filter = trackpoint_accelerator_filter,
|
.filter = trackpoint_accelerator_filter,
|
||||||
.filter_constant = trackpoint_accelerator_filter_noop,
|
.filter_constant = trackpoint_accelerator_filter_noop,
|
||||||
.restart = NULL,
|
.restart = trackpoint_accelerator_restart,
|
||||||
.destroy = trackpoint_accelerator_destroy,
|
.destroy = trackpoint_accelerator_destroy,
|
||||||
.set_speed = trackpoint_accelerator_set_speed,
|
.set_speed = trackpoint_accelerator_set_speed,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct motion_filter *
|
struct motion_filter *
|
||||||
create_pointer_accelerator_filter_trackpoint(int max_hw_delta)
|
create_pointer_accelerator_filter_trackpoint(double multiplier)
|
||||||
{
|
{
|
||||||
struct trackpoint_accelerator *filter;
|
struct trackpoint_accelerator *filter;
|
||||||
|
|
||||||
|
assert(multiplier > 0.0);
|
||||||
|
|
||||||
/* Trackpoints are special. They don't have a movement speed like a
|
/* Trackpoints are special. They don't have a movement speed like a
|
||||||
* mouse or a finger, instead they send a constant stream of events
|
* mouse or a finger, instead they send a stream of events based on
|
||||||
* based on the pressure applied.
|
* the pressure applied.
|
||||||
*
|
*
|
||||||
* Physical ranges on a trackpoint are the max values for relative
|
* 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);
|
filter = zalloc(sizeof *filter);
|
||||||
if (!filter)
|
if (!filter)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
filter->history_size = ARRAY_LENGTH(filter->history);
|
filter->multiplier = multiplier;
|
||||||
filter->max_accel = TRACKPOINT_DEFAULT_MAX_ACCEL;
|
|
||||||
filter->max_delta = TRACKPOINT_DEFAULT_MAX_DELTA;
|
|
||||||
|
|
||||||
filter->scale_factor = 1.0 * TRACKPOINT_DEFAULT_RANGE / max_hw_delta;
|
trackers_init(&filter->trackers);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
filter->base.interface = &accelerator_interface_trackpoint;
|
filter->base.interface = &accelerator_interface_trackpoint;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ struct motion_filter *
|
||||||
create_pointer_accelerator_filter_lenovo_x230(int dpi);
|
create_pointer_accelerator_filter_lenovo_x230(int dpi);
|
||||||
|
|
||||||
struct motion_filter *
|
struct motion_filter *
|
||||||
create_pointer_accelerator_filter_trackpoint(int max_delta);
|
create_pointer_accelerator_filter_trackpoint(double multiplier);
|
||||||
|
|
||||||
struct motion_filter *
|
struct motion_filter *
|
||||||
create_pointer_accelerator_filter_tablet(int xres, int yres);
|
create_pointer_accelerator_filter_tablet(int xres, int yres);
|
||||||
|
|
@ -154,5 +154,6 @@ touchpad_lenovo_x230_accel_profile(struct motion_filter *filter,
|
||||||
double
|
double
|
||||||
trackpoint_accel_profile(struct motion_filter *filter,
|
trackpoint_accel_profile(struct motion_filter *filter,
|
||||||
void *data,
|
void *data,
|
||||||
double delta);
|
double delta,
|
||||||
|
uint64_t time);
|
||||||
#endif /* FILTER_H */
|
#endif /* FILTER_H */
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@
|
||||||
|
|
||||||
/* The HW DPI rate we normalize to before calculating pointer acceleration */
|
/* The HW DPI rate we normalize to before calculating pointer acceleration */
|
||||||
#define DEFAULT_MOUSE_DPI 1000
|
#define DEFAULT_MOUSE_DPI 1000
|
||||||
#define DEFAULT_TRACKPOINT_RANGE 20
|
|
||||||
#define DEFAULT_TRACKPOINT_SENSITIVITY 128
|
#define DEFAULT_TRACKPOINT_SENSITIVITY 128
|
||||||
|
|
||||||
#define ANSI_HIGHLIGHT "\x1B[0;1;39m"
|
#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_BOOL,
|
||||||
PT_DIMENSION,
|
PT_DIMENSION,
|
||||||
PT_RANGE,
|
PT_RANGE,
|
||||||
|
PT_DOUBLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,6 +75,7 @@ struct property {
|
||||||
char *s;
|
char *s;
|
||||||
struct quirk_dimensions dim;
|
struct quirk_dimensions dim;
|
||||||
struct quirk_range range;
|
struct quirk_range range;
|
||||||
|
double d;
|
||||||
} value;
|
} value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -262,7 +264,7 @@ quirk_get_name(enum quirk q)
|
||||||
case QUIRK_ATTR_PRESSURE_RANGE: return "AttrPressureRange";
|
case QUIRK_ATTR_PRESSURE_RANGE: return "AttrPressureRange";
|
||||||
case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD: return "AttrPalmPressureThreshold";
|
case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD: return "AttrPalmPressureThreshold";
|
||||||
case QUIRK_ATTR_RESOLUTION_HINT: return "AttrResolutionHint";
|
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";
|
case QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD: return "AttrThumbPressureThreshold";
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
|
|
@ -640,6 +642,7 @@ parse_attr(struct quirks_context *ctx,
|
||||||
struct quirk_dimensions dim;
|
struct quirk_dimensions dim;
|
||||||
struct quirk_range range;
|
struct quirk_range range;
|
||||||
unsigned int v;
|
unsigned int v;
|
||||||
|
double d;
|
||||||
|
|
||||||
if (streq(key, quirk_get_name(QUIRK_ATTR_SIZE_HINT))) {
|
if (streq(key, quirk_get_name(QUIRK_ATTR_SIZE_HINT))) {
|
||||||
p->id = 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->type = PT_DIMENSION;
|
||||||
p->value.dim = dim;
|
p->value.dim = dim;
|
||||||
rc = true;
|
rc = true;
|
||||||
} else if (streq(key, quirk_get_name(QUIRK_ATTR_TRACKPOINT_RANGE))) {
|
} else if (streq(key, quirk_get_name(QUIRK_ATTR_TRACKPOINT_MULTIPLIER))) {
|
||||||
p->id = QUIRK_ATTR_TRACKPOINT_RANGE;
|
p->id = QUIRK_ATTR_TRACKPOINT_MULTIPLIER;
|
||||||
if (!safe_atou(value, &v))
|
if (!safe_atod(value, &d))
|
||||||
goto out;
|
goto out;
|
||||||
p->type = PT_UINT;
|
p->type = PT_DOUBLE;
|
||||||
p->value.u = v;
|
p->value.d = d;
|
||||||
rc = true;
|
rc = true;
|
||||||
} else if (streq(key, quirk_get_name(QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD))) {
|
} else if (streq(key, quirk_get_name(QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD))) {
|
||||||
p->id = 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;
|
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
|
bool
|
||||||
quirks_get_string(struct quirks *q, enum quirk which, char **val)
|
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_PRESSURE_RANGE,
|
||||||
QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
|
QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
|
||||||
QUIRK_ATTR_RESOLUTION_HINT,
|
QUIRK_ATTR_RESOLUTION_HINT,
|
||||||
QUIRK_ATTR_TRACKPOINT_RANGE,
|
QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
|
||||||
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
|
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -216,6 +216,19 @@ quirks_get_int32(struct quirks *q,
|
||||||
enum quirk which,
|
enum quirk which,
|
||||||
int32_t *val);
|
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.
|
* Get the value of the given quirk, as string.
|
||||||
* This function will assert if the quirk type does not match the
|
* 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
|
EOF
|
||||||
|
|
||||||
outfile="ptraccel-trackpoint"
|
outfile="ptraccel-trackpoint"
|
||||||
$tool --mode=accel --dpi=1000 --filter=linear > $outfile-mouse.gnuplot
|
|
||||||
for speed in $speeds; do
|
for speed in $speeds; do
|
||||||
$tool --mode=accel --speed=$speed --filter=trackpoint > $outfile-$speed.gnuplot
|
$tool --mode=accel --speed=$speed --filter=trackpoint > $outfile-$speed.gnuplot
|
||||||
done
|
done
|
||||||
$gnuplot <<EOF
|
$gnuplot <<EOF
|
||||||
set terminal svg enhanced background rgb 'white'
|
set terminal svg enhanced background rgb 'white'
|
||||||
set output "$outfile.svg"
|
set output "$outfile.svg"
|
||||||
set xlabel "delta (units)"
|
set xlabel "delta (units/ms)"
|
||||||
set ylabel "accel factor"
|
set ylabel "accel factor"
|
||||||
set style data lines
|
set style data lines
|
||||||
set yrange [0:5]
|
set yrange [0:5]
|
||||||
set xrange [0:20]
|
set xrange [0:1]
|
||||||
speeds="$speeds"
|
speeds="$speeds"
|
||||||
fname(s)=sprintf("$outfile-%s.gnuplot", s)
|
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
|
EOF
|
||||||
|
|
|
||||||
|
|
@ -161,29 +161,12 @@ print_accel_func(struct motion_filter *filter,
|
||||||
printf("# set style data lines\n");
|
printf("# set style data lines\n");
|
||||||
printf("# plot \"gnuplot.data\" using 1:2 title 'accel factor'\n");
|
printf("# plot \"gnuplot.data\" using 1:2 title 'accel factor'\n");
|
||||||
printf("#\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) {
|
for (mmps = 0.0; mmps < 1000.0; mmps += 1) {
|
||||||
double units_per_us = mmps_to_upus(mmps, dpi);
|
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 */);
|
double result = profile(filter, NULL, units_per_us, 0 /* time */);
|
||||||
printf("%.8f\t%.4f\t%.8f\n", mmps, result, units_per_us);
|
printf("%.8f\t%.4f\t%.8f\t%.8f\n", mmps, result, units_per_us, units_per_ms);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,7 +185,6 @@ usage(void)
|
||||||
"--steps=<double> ... in motion and delta modes only. Increase dx by step each round\n"
|
"--steps=<double> ... in motion and delta modes only. Increase dx by step each round\n"
|
||||||
"--speed=<double> ... accel speed [-1, 1], default 0\n"
|
"--speed=<double> ... accel speed [-1, 1], default 0\n"
|
||||||
"--dpi=<int> ... device resolution in DPI (default: 1000)\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"
|
"--filter=<linear|low-dpi|touchpad|x230|trackpoint> \n"
|
||||||
" linear ... the default motion filter\n"
|
" linear ... the default motion filter\n"
|
||||||
" low-dpi ... low-dpi filter, use --dpi with this argument\n"
|
" low-dpi ... low-dpi filter, use --dpi with this argument\n"
|
||||||
|
|
@ -253,7 +235,6 @@ main(int argc, char **argv)
|
||||||
OPT_SPEED,
|
OPT_SPEED,
|
||||||
OPT_DPI,
|
OPT_DPI,
|
||||||
OPT_FILTER,
|
OPT_FILTER,
|
||||||
OPT_TRACKPOINT_RANGE,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
@ -268,7 +249,6 @@ main(int argc, char **argv)
|
||||||
{"speed", 1, 0, OPT_SPEED },
|
{"speed", 1, 0, OPT_SPEED },
|
||||||
{"dpi", 1, 0, OPT_DPI },
|
{"dpi", 1, 0, OPT_DPI },
|
||||||
{"filter", 1, 0, OPT_FILTER },
|
{"filter", 1, 0, OPT_FILTER },
|
||||||
{"trackpoint-range", 1, 0, OPT_TRACKPOINT_RANGE },
|
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -326,9 +306,6 @@ main(int argc, char **argv)
|
||||||
case OPT_FILTER:
|
case OPT_FILTER:
|
||||||
filter_type = optarg;
|
filter_type = optarg;
|
||||||
break;
|
break;
|
||||||
case OPT_TRACKPOINT_RANGE:
|
|
||||||
tp_range_max = strtod(optarg, NULL);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
@ -350,7 +327,7 @@ main(int argc, char **argv)
|
||||||
profile = touchpad_lenovo_x230_accel_profile;
|
profile = touchpad_lenovo_x230_accel_profile;
|
||||||
} else if (streq(filter_type, "trackpoint")) {
|
} else if (streq(filter_type, "trackpoint")) {
|
||||||
filter = create_pointer_accelerator_filter_trackpoint(tp_range_max);
|
filter = create_pointer_accelerator_filter_trackpoint(tp_range_max);
|
||||||
profile = NULL; /* trackpoint is special */
|
profile = trackpoint_accel_profile;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invalid filter type %s\n", filter_type);
|
fprintf(stderr, "Invalid filter type %s\n", filter_type);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -381,10 +358,7 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case ACCEL:
|
case ACCEL:
|
||||||
if (!profile) /* trackpoint */
|
print_accel_func(filter, profile, dpi);
|
||||||
print_accel_func_trackpoint(filter, tp_range_max);
|
|
||||||
else
|
|
||||||
print_accel_func(filter, profile, dpi);
|
|
||||||
break;
|
break;
|
||||||
case DELTA:
|
case DELTA:
|
||||||
print_ptraccel_deltas(filter, step);
|
print_ptraccel_deltas(filter, step);
|
||||||
|
|
|
||||||
|
|
@ -615,7 +615,7 @@ tools_list_device_quirks(struct quirks_context *ctx,
|
||||||
QUIRK_ATTR_PRESSURE_RANGE,
|
QUIRK_ATTR_PRESSURE_RANGE,
|
||||||
QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
|
QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
|
||||||
QUIRK_ATTR_RESOLUTION_HINT,
|
QUIRK_ATTR_RESOLUTION_HINT,
|
||||||
QUIRK_ATTR_TRACKPOINT_RANGE,
|
QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
|
||||||
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
|
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
|
||||||
};
|
};
|
||||||
enum quirk *q;
|
enum quirk *q;
|
||||||
|
|
@ -630,6 +630,7 @@ tools_list_device_quirks(struct quirks_context *ctx,
|
||||||
struct quirk_range r;
|
struct quirk_range r;
|
||||||
uint32_t v;
|
uint32_t v;
|
||||||
char *s;
|
char *s;
|
||||||
|
double d;
|
||||||
|
|
||||||
if (!quirks_has_quirk(quirks, *q))
|
if (!quirks_has_quirk(quirks, *q))
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -682,7 +683,6 @@ tools_list_device_quirks(struct quirks_context *ctx,
|
||||||
break;
|
break;
|
||||||
case QUIRK_ATTR_PALM_SIZE_THRESHOLD:
|
case QUIRK_ATTR_PALM_SIZE_THRESHOLD:
|
||||||
case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD:
|
case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD:
|
||||||
case QUIRK_ATTR_TRACKPOINT_RANGE:
|
|
||||||
case QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD:
|
case QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD:
|
||||||
quirks_get_uint32(quirks, *q, &v);
|
quirks_get_uint32(quirks, *q, &v);
|
||||||
snprintf(buf, sizeof(buf), "%s=%u", name, 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);
|
snprintf(buf, sizeof(buf), "%s=%s", name, s);
|
||||||
callback(userdata, buf);
|
callback(userdata, buf);
|
||||||
break;
|
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