Das Touchpad meines ASUS ProArt P16 hat mich von Anfang an gestört. Der Klick war mir zu weich. Schlimmer noch: Wenn ich leicht aufsetzte und dann wischte, markierte es oft Text. Unter Windows haben Filtertreiber etwas geholfen, aber nie zuverlässig.
Unter Linux klickt das Pad jetzt erst bei 260 Gramm statt bei etwa 150. Leichte Wischer starten keine Markierung mehr, und der Haptik-Puls kommt genau in dem Moment, in dem der Klick zählt. Dafür habe ich einen Abend gebraucht, mit Claude Code als Pair-Programmer.
Kein Taster, nur Firmware
Unter dem Glas sitzt ein haptisches Touchpad von PixArt. Einen mechanischen Taster hat es nicht. Die Firmware entscheidet, ab welchem Druck ein Klick vorliegt. Ein kleiner Aktor unter dem Glas spielt dann einen Puls ab, der sich wie ein Klick anfühlt.
Der HID-Descriptor des Pads nennt zwei Einstellungen: die Klickkraft von 1 bis 3 und die Puls-Intensität von 0 bis 100. Ich habe beide auf das Maximum gestellt. Der Klick war immer noch zu weich.
Außerdem wollte die Firmware ihre Einstellungen nicht zurückmelden. Jede Abfrage kam als Report 255 zurück statt als der Report, den ich angefragt hatte. Schreiben konnte ich die Werte, eine Bestätigung habe ich aber nie gesehen.
Wie fest drücke ich eigentlich?
Also habe ich aufgezeichnet, was das Pad selbst meldet. Mit jedem Touch-Report schickt es einen Kraftwert in Gramm. Ich habe zuerst langsam gedrückt, bis es klickte. Dann habe ich so fest geklickt, wie sich ein Klick für mich anfühlen soll. Zum Schluss kamen ein paar schnelle Wischer.
Die ersten beiden Aufzeichnungen waren unbrauchbar. Die eine las die falschen Bytes. Die andere lief, während niemand das Pad berührte. Danach startete die Aufnahme erst auf mein “Los” und speicherte die Rohbytes mit. Die dritte Aufzeichnung hat funktioniert.
Selbst auf der festesten Stufe klickte die Firmware bei 149 bis 161 Gramm. Ein Druck mit 133 Gramm löste noch keinen Klick aus. Meine gewollten Klicks erreichten in der Spitze 503 bis 641 Gramm.
Ein schneller Wischer kam mitten in der Bewegung auf 201 Gramm, und die Firmware wertete das als Klick. Eine Bewegung mit gedrückter Taste ist ein Drag, also markierte der Wischer Text. Das war der ganze Fehler.
Ich wollte den Klickpunkt bei etwa 250 Gramm haben. Am Ende bin ich bei 260 gelandet.
Alle Werte stammen aus einer Aufzeichnung von zwei Minuten. Der neue Klickpunkt liegt über jedem versehentlichen Klick und weit unter den Klicks, die ich wirklich will.
Ein Filter im Kernel
Unter Windows heißt so etwas Filtertreiber. Linux hat dafür HID-BPF. Das ist ein kleines Programm, das der Kernel auf jeden Report eines Geräts anwendet, bevor ein anderer Teil des Systems den Report sieht. Der Kernel auf meinem Laptop unterstützt HID-BPF schon, ich musste also nichts neu bauen.
Der Filter hält den Klick der Firmware zurück, bis die Kraft 260 Gramm erreicht. Außerdem lässt er keinen Klick beginnen, solange sich der Finger schneller als etwa einen halben Millimeter pro Report bewegt. Ein begonnener Klick hält, bis die Firmware loslässt. Absichtliches Ziehen funktioniert also weiter, auch wenn der Finger dabei etwas nachlässt.
Schon der erste Test fühlte sich besser an.
Der Puls kam zu früh
Ein Problem blieb. Die Firmware spielte ihren Puls weiterhin bei 150 Gramm, also deutlich vor dem eigentlichen Klick. Das Pad kennt aber einen Befehl, der auf Anfrage einen Puls abspielt. Den habe ich zuerst von Hand getestet. Die ersten drei Test-Pulse habe ich verpasst, weil ich abgelenkt war. Im zweiten Durchgang habe ich alle drei gespürt.
Jetzt schaltet der Filter den Puls der Firmware stumm. Stattdessen spielt er einen eigenen Puls, wenn der Klick beginnt und wenn er endet.
Die erste Version spielte allerdings gar nichts. Der Kernel verweigerte den Start des Puls-Workers mit -EPERM, weil kein laufendes Programm dessen Daten festhielt. Ich habe die Daten dann im BPF-Dateisystem gepinnt, und danach lief es.
Ich habe auch längere Pulse probiert. Das Pad nahm die neuen Längen an und ignorierte sie dann. Im normalen Betrieb habe ich drei Varianten verglichen: Slot 5, den längeren Slot 7 und die Slots 6 und 7 direkt hintereinander. Der Doppelpuls war stärker, fühlte sich aber matschig an. Slot 5 hat gewonnen.
Damit es bleibt
Mein Ansible-Setup für den Laptop baut den Filter jetzt und lädt ihn, sobald das Touchpad auftaucht. Nach jedem Resume lädt es den Filter erneut.
Im Review vor dem Merge kam noch ein ernster Fehler ans Licht. Das Touchpad meldet sich sehr früh im Bootvorgang, noch bevor udev im eigentlichen System läuft. Danach spielt udev nur ein add-Event nach. Die erste Version meiner Regel hörte aber auf bind. Beim Booten wäre der Filter also nie geladen worden. Jetzt reagiert die Regel auf beide Events.
Um 19:11 Uhr habe ich neu gestartet. 15 Sekunden nach dem Boot hing der Filter am Gerät, und die Pulse kamen. Es fühlt sich immer noch gut an.
Die Zahlen
| Messgröße | Wert |
|---|---|
| Firmware-Klick, festeste Stufe | 149 bis 161 g |
| Größter versehentlicher Klick | 212 g |
| Neuer Klickpunkt | 260 g |
| Spitze eines gewollten Klicks | 503 bis 641 g |
| Bewegungsgrenze beim Klickbeginn | 15 Einheiten pro Report (~0,5 mm) |
| Haptik-Puls | Slot 5, beim Drücken und Loslassen |
| Puls der Firmware | Intensität 0 (stumm) |
Was noch offen ist
- Ein echtes Suspend und Resume habe ich noch nicht durchlaufen. Getestet habe ich bisher nur den Resume-Hook selbst.
- Falls leichte Wischer doch wieder Text markieren, ist wahrscheinlich Tap-and-Drag in Hyprland schuld. Dort zählt ein leichtes Tippen mit anschließendem Wischen als Drag, und der Filter sieht davon nichts. Abschalten lässt sich das mit einer Zeile in der Input-Konfiguration von Hyprland.
- Das Review hat zwei geringe Risiken notiert. Das Pad kennt einen zweiten, ähnlichen Report-Typ, den ich es nie habe senden sehen. Und wenn das Schreiben der Einstellungen beim Laden scheitert, bleibt der Puls der Firmware an, und ich bekomme zwei Pulse.