Example output of the tool is below: ::
- $ sudo libinput measure touchpad-pressure
- Ready for recording data.
- Pressure range used: 8:10
- Palm pressure range used: 65535
- Place a single finger on the touchpad to measure pressure values.
- Ctrl+C to exit
-
- Sequence 1190 pressure: min: 39 max: 48 avg: 43 median: 44 tags: down
- Sequence 1191 pressure: min: 49 max: 65 avg: 62 median: 64 tags: down
- Sequence 1192 pressure: min: 40 max: 78 avg: 64 median: 66 tags: down
- Sequence 1193 pressure: min: 36 max: 83 avg: 70 median: 73 tags: down
- Sequence 1194 pressure: min: 43 max: 76 avg: 72 median: 74 tags: down
- Touchpad pressure: 47 min: 47 max: 86 tags: down
+ $ sudo libinput measure touchpad-pressure
+ Using Synaptics TM2668-002: /dev/input/event21
+
+ This is an interactive tool
+
+ Place a single finger on the touchpad to measure pressure values.
+ Check that:
+ - touches subjectively perceived as down are tagged as down
+ - touches with a thumb are tagged as thumb
+ - touches with a palm are tagged as palm
+
+ If the touch states do not match the interaction, re-run
+ with --touch-thresholds=down:up using observed pressure values.
+ See --help for more options.
+
+ Press Ctrl+C to exit
+
+ +-------------------------------------------------------------------------------+
+ | Thresh | 70 | 60 | 130 | 100 | |
+ +-------------------------------------------------------------------------------+
+ | Touch | down | up | palm | thumb | min | max | p | avg | median |
+ +-------------------------------------------------------------------------------+
+ | 178 | x | x | | | 75 | 75 | 0 | 75 | 75 |
+ | 179 | x | x | | | 35 | 88 | 0 | 77 | 81 |
+ | 180 | x | x | | x | 65 | 113 | 0 | 98 | 98 |
+ | 181 | x | x | | x | 50 | 101 | 0 | 86 | 90 |
+ | 182 | x | x | | | 40 | 80 | 0 | 66 | 70 |
+ | 183 | x | | | | 43 | 78 | 78 | |
+ ...
The example output shows five completed touch sequences and one ongoing one.
For each, the respective minimum and maximum pressure values are printed as
-well as some statistics. The ``tags`` show that sequence was considered
-logically down at some point. This is an interactive tool and its output may
-change frequently. Refer to the **libinput-measure-touchpad-pressure(1)** man
-page for more details.
+well as some statistics. The ``down`` column show that each sequence was
+considered logically down at some point, two of the sequences were considered
+thumbs. This is an interactive tool and its output may change frequently. Refer
+to the **libinput-measure-touchpad-pressure(1)** man page for more details.
By default, this tool uses the :ref:`device-quirks` for the pressure range. To
narrow down on the best values for your device, specify the 'logically down'
sys.exit(1)
+class TableFormatter(object):
+ ALIGNMENT = 3
+
+ def __init__(self):
+ self.colwidths = []
+
+ @property
+ def width(self):
+ return sum(self.colwidths) + 1
+
+ def headers(self, args):
+ s = '|'
+ align = self.ALIGNMENT - 1 # account for |
+
+ for arg in args:
+ # +2 because we want space left/right of text
+ w = ((len(arg) + 2 + align) // align) * align
+ self.colwidths.append(w + 1)
+ s += ' {:^{width}s} |'.format(arg, width=w - 2)
+
+ return s
+
+ def values(self, args):
+ s = '|'
+ for w, arg in zip(self.colwidths, args):
+ w -= 1 # width includes | separator
+ if type(arg) == str:
+ # We want space margins for strings
+ s += ' {:{width}s} |'.format(arg, width=w - 2)
+ elif type(arg) == bool:
+ s += '{:^{width}s}|'.format('x' if arg else ' ', width=w)
+ else:
+ s += '{:^{width}d}|'.format(arg, width=w)
+
+ if len(args) < len(self.colwidths):
+ s += '|'.rjust(self.width - len(s), ' ')
+ return s
+
+ def separator(self):
+ return '+' + '-' * (self.width - 2) + '+'
+
+
+fmt = TableFormatter()
+
+
class Range(object):
"""Class to keep a min/max of a value around"""
def __init__(self):
def _str_summary(self):
if not self.points:
- return "{:78s}".format("Sequence: no pressure values recorded")
-
- s = "Sequence {} pressure: "\
- "min: {:3d} max: {:3d} avg: {:3d} median: {:3d} tags:" \
- .format(
- self.tracking_id,
- self.prange.min,
- self.prange.max,
- self.avg(),
- self.median()
- )
- if self.was_down:
- s += " down"
- if self.was_palm:
- s += " palm"
- if self.was_thumb:
- s += " thumb"
+ return fmt.values([self.tracking_id, False, False, False, False,
+ 'No pressure values recorded'])
+
+ s = fmt.values([self.tracking_id, self.was_down, True, self.was_palm,
+ self.was_thumb, self.prange.min, self.prange.max, 0,
+ self.avg(), self.median()])
return s
def _str_state(self):
- s = "Touchpad pressure: {:3d} min: {:3d} max: {:3d} tags: {} {} {}" \
- .format(
- self.points[-1].pressure,
- self.prange.min,
- self.prange.max,
- "down" if self.is_down else " ",
- "palm" if self.is_palm else " ",
- "thumb" if self.is_thumb else " "
- )
+ s = fmt.values([self.tracking_id, self.is_down, not self.is_down,
+ self.is_palm, self.is_thumb, self.prange.min,
+ self.prange.max, self.points[-1].pressure])
return s
libevdev.EV_KEY.BTN_TOOL_QUINTTAP
]
if event.code in tapcodes and event.value > 0:
- print("\rThis tool cannot handle multiple fingers, "
- "output will be invalid", file=sys.stderr)
+ print('\r\033[2KThis tool cannot handle multiple fingers, '
+ 'output will be invalid')
def handle_abs(device, event):
try:
s = device.current_sequence()
s.finalize()
- print("\r{}".format(s))
+ print("\r\033[2K{}".format(s))
except IndexError:
# If the finger was down at startup
pass
try:
s = device.current_sequence()
s.append(Touch(pressure=event.value))
- print("\r{}".format(s), end="")
+ print("\r\033[2K{}".format(s), end="")
except IndexError:
# If the finger was down at startup
pass
def loop(device):
- print("Ready for recording data.")
- print("Pressure range used: {}:{}".format(device.down, device.up))
- print("Palm pressure range used: {}".format(device.palm))
- print("Thumb pressure range used: {}".format(device.thumb))
- print("Place a single finger on the touchpad to measure pressure values.\n"
- "Ctrl+C to exit\n")
+ print('This is an interactive tool')
+ print()
+ print("Place a single finger on the touchpad to measure pressure values.")
+ print('Check that:')
+ print('- touches subjectively perceived as down are tagged as down')
+ print('- touches with a thumb are tagged as thumb')
+ print('- touches with a palm are tagged as palm')
+ print()
+ print('If the touch states do not match the interaction, re-run')
+ print('with --touch-thresholds=down:up using observed pressure values.')
+ print('See --help for more options.')
+ print()
+ print("Press Ctrl+C to exit")
+ print()
+
+ headers = fmt.headers(['Touch', 'down', 'up', 'palm', 'thumb', 'min', 'max', 'p', 'avg', 'median'])
+ print(fmt.separator())
+ print(fmt.values(['Thresh', device.down, device.up, device.palm, device.thumb]))
+ print(fmt.separator())
+ print(headers)
+ print(fmt.separator())
while True:
for event in device.events():
loop(device)
except KeyboardInterrupt:
- pass
+ print('\r\033[2K{}'.format(fmt.separator()))
+ print()
+
except (PermissionError, OSError):
print("Error: failed to open device")
except InvalidDeviceError as e: