Ich besitze eine USB-Tastatur, die ich eigentlich sehr mag: Das „Lenovo ThinkPad Compact USB Keyboard with TrackPoint“ (KU-1255). Es hat einen Trackpoint, was sehr praktisch ist, und tippt sich ganz nett. Allerdings sind die werten Leute bei Lenovo übers Ziel hinausgeschossen: Sie haben das Scrollen mit der mittleren Maustaste in der Hardware implementiert, und zwar falsch.
Nerviger Fehler
Die Hardware hat mehrere Modi. So kann man die mittlere Maustaste deaktivieren oder aktivieren. Aktiviert man sie, kann man die mittlere Maustaste normal benutzen. Allerdings bekommt man als Bonus, dass solange man die mittlere Maustaste gedrückt hält, vertikale Trackpoint-Bewegungen in Scroll-Ereignisse übersetzt werden. Aber nur vertikale, keine horizontale. Und dazu so grob, dass man höchstens zeilenweise, aber keineswegs pixelweise scrollen kann.
Hinzu kommt, dass beim Loslassen der Maustaste wieder Ereignis ausgelöst wird. ein mittlerer Maus-Klick.
Das macht das schöne Xorg-Feature, mit der mittleren Maustaste zu scrollen, komplett unbenutzbar.
Linux umgeht das im Kernel, aber unter Windows oder FreeBSD guckt man in die Röhre.
Lenovo erkennt das Problem nicht an, sondern hat mir lieber eine neue Tastatur geschickt, weil sie von einem Hardwareproblem ausgingen…
Reverse-Engineering der Firmware
Wohlan, ans Werk! Gucken wir doch erst einmal, was in der Tastatur drin ist: Ein Sonix SN8F2288FG. Das ist ein kleiner 8-Bit-Mikrocontroller mit 12kW ROM, 512 Bytes RAM und einer schrägen Architektur.
Auf der Lenovo-Webseite gibt es einen Updater für die Tastatur. Dort muss die
Firmware drinstecken. Laden wir ihn herunter:
tp_compact_usb_kb_with_trackpoint_fw.exe
(MD5
2c128084412b917449a2c01da3c49451
, SHA256
7116a3819ee094857d21e4671cb6cf953d582372126f0f6728f6b2421eda7bd4
) und tun wir
ihn in die Gratis-Version von IDA Pro.
Nach etwas Rumspielerei habe ich herausgefunden, dass die Firmware mit dem Byte
0x5A ge-XOR-t ist. Man suche nach
Auto .....a..2015051111591234567817EF60478521SN8F2288
, um sie zu finden.
Das Binary tut man in dissn8
, einen freien SN8-Disassembler.
Als ich anfing, musste ich einige Instruktionen hinzufügen oder ändern, damit
sie korrekt dekodiert werden.
Die Überprüfung auf Korrektheit habe ich durch Übersetzen in SN8 C Studio
sichergestellt.
Danach habe ich mich mit dem ausgedruckten Assembler-Dump hingesetzt und nachvollzogen, wie die Firmware funktioniert.
Nach einer Weile habe ich die Stelle gefunden und das “Feature”, das mich seit Jahren genervt hat, schlichtweg deaktiviert. Dazu habe ich noch die Firmware-Version erhöht, um die veränderte Firmware erkennen zu können:
--- orig/firmware-annotated-SN8CStudio.asm 2019-06-10 22:06:46.782287000 +0200
+++ patched/firmware.asm 2019-06-10 22:06:54.378983000 +0200
@@ -2188,13 +2188,16 @@
label_06d5: ; <- 06d3
CALL iic_stop
; only apply speed factor if !middle_button_pressed (i.e. scrolling):
- BTS0 flag_middle_button_pressed
- JMP tp_skip_apply_speed
+; BTS0 flag_middle_button_pressed
+; JMP tp_skip_apply_speed
+ NOP
+ NOP
CALL tp_apply_speed_x
CALL tp_apply_speed_y
CALL copy_clamp_tp_mouse_pos ; tp_mouse_d? -> mouse_d?
tp_skip_apply_speed: ; <- 06d7
- BTS1 flag_middle_button_pressed
+; BTS1 flag_middle_button_pressed
+ BSET 0x14.6 ; cool, enough space to fit that. so that button 3 is reported reported properly.
RET
MOV A, tp_mouse_dx
MOV temp_maybe_tp_dx, A
@@ -2439,8 +2442,10 @@
BCLR mouse_buttons.1
BTS0 tp_mouse_buttons.1
BSET mouse_buttons.1
- BTS0 flag_Thinkpad_preferred_scrolling
- JMP label_0792
+; BTS0 flag_Thinkpad_preferred_scrolling
+; JMP label_0792
+ NOP
+ NOP
BCLR mouse_buttons.2
BTS0 tp_mouse_buttons.2
BSET mouse_buttons.2
@@ -2462,7 +2467,8 @@
BSET flag_middle_button_pressed
JMP label_07b6
label_07a0: ; <- 079b
- BCLR mouse_buttons.2
+; BCLR mouse_buttons.2
+ NOP
MOV A, tp_mouse_buttons
AND A, #0x04
CMPRS A, 0x78
@@ -4701,7 +4707,8 @@
DW 0x0017 ; ..
DW 0x0047 ; .G
DW 0x0060 ; .`
- DW 0x0030 ; .0
+ ;DW 0x0030 ; .0
+ DW 0x0033 ; increment version
DW 0x0003 ; ..
DW 0x0001 ; ..
DW 0x0002 ; ..
Updater anpassen
Das ist der einfache Teil: XORen mit 0x5A, an die gleiche Stelle tun, und die eingebettete Versionsnummer anpassen. Dafür reicht ein Hex-Editor. Danach kann man den Updater starten, die Tastatur aktualiseren und sich endlich am Scrollen mit der mittleren Maustaste erfreuen.
Leider kann ich den gepatchten Updater nicht anbieten, aber dies ist der Patch, der angewandt werden muss:
--- orig.hex 2019-06-10 22:50:40.986155000 +0200
+++ patched.hex 2019-06-10 22:50:53.745130000 +0200
@@ -21893,7 +21893,7 @@
00057dc0 0d 0a 0d 0a 0d 0a 46 69 72 6d 77 61 72 65 20 75 |......Firmware u|
00057dd0 70 64 61 74 65 20 63 6f 6d 70 6c 65 74 65 64 0d |pdate completed.|
00057de0 0a 43 75 72 72 65 6e 74 20 46 69 72 6d 77 61 72 |.Current Firmwar|
-00057df0 65 20 56 65 72 73 69 6f 6e 3a 20 56 33 2e 33 30 |e Version: V3.30|
+00057df0 65 20 56 65 72 73 69 6f 6e 3a 20 56 33 2e 33 33 |e Version: V3.33|
00057e00 0d 0a 50 6c 65 61 73 65 20 72 65 70 6c 75 67 20 |..Please replug |
00057e10 6b 65 79 62 6f 61 72 64 00 00 00 00 50 72 6f 74 |keyboard....Prot|
00057e20 6f 63 6f 6c 20 48 61 6e 64 73 68 61 6b 65 20 45 |ocol Handshake E|
@@ -24452,8 +24452,8 @@
00074200 74 9c 5a 54 7b 9c 0f 77 39 9c 01 9c 17 20 8e dc |t.ZT{..w9.... ..|
00074210 d3 9c da 5c 88 dc fe 9c d3 9c 1f 45 fe 9c dd 9d |...\.......E....|
00074220 d3 9c 68 45 fe 9c d3 9c a5 47 5b 4e 69 45 fe 9c |..hE.....G[NiE..|
-00074230 d3 9c fd 9c 17 19 8f dc 17 11 74 9c 48 0c 81 dc |..........t.H...|
-00074240 54 92 6b 92 ed 9d 48 04 5a 54 68 44 6e 45 69 44 |T.k...H.ZThDnEiD|
+00074230 d3 9c fd 9c 17 19 8f dc 17 11 74 9c 5a 5a 5a 5a |..........t.ZZZZ|
+00074240 54 92 6b 92 ed 9d 4e 14 5a 54 68 44 6e 45 69 44 |T.k...N.ZThDnEiD|
00074250 6f 45 6e 05 bd dc 6e 44 a5 47 5b 4e 6e 45 dc 38 |oEn...nD.G[NnE.8|
00074260 6e 53 6f 05 b5 dc 6f 44 a5 47 5b 4e 6f 45 6e 44 |nSo...oD.G[NoEnD|
00074270 6f 78 dc 28 4b dd 68 44 6e 45 69 44 6f 45 6e 05 |ox.(K.hDnEiDoEn.|
@@ -24475,10 +24475,10 @@
00074370 6c 2d 2e dd 6c 49 2f dd 6c 45 69 44 6c 49 6c 44 |l-..lI/.lEiDlIlD|
00074380 48 7e dc 20 5a 54 6c 45 a5 77 6a 49 4e 0f d9 dd |H~. ZTlE.wjIN...|
00074390 49 10 49 19 df dd 49 18 49 11 2d dd 5a 54 76 1a |I.I...I.I.-.ZTv.|
-000743a0 1f 0a 76 12 76 1b 1f 0b 76 13 4e 0f c8 dd 76 18 |..v.v...v.N...v.|
+000743a0 1f 0a 76 12 76 1b 1f 0b 76 13 5a 5a 5a 5a 76 18 |..v.v...v.ZZZZv.|
000743b0 1f 08 76 10 76 44 77 5d cd dd 49 18 c0 dd 76 44 |..v.vDw]..I...vD|
000743c0 77 45 49 10 4e 0f fa dd 48 1c 76 08 48 14 ec dd |wEI.N...H.v.H...|
-000743d0 76 18 1f 44 5e 70 22 5d fd dd 49 1c ec dd 1f 44 |v..D^p"]..I....D|
+000743d0 5a 5a 1f 44 5e 70 22 5d fd dd 49 1c ec dd 1f 44 |ZZ.D^p"]..I....D|
000743e0 5e 70 22 45 49 14 22 00 e9 dd 5a 77 72 45 5e 77 |^p"EI."...ZwrE^w|
000743f0 73 45 48 14 ec dd 72 71 73 71 48 1c 5a 54 68 44 |sEH...rqsqH.ZThD|
00074400 dc 2a 94 dd 49 10 74 0d 9c dd 68 44 74 49 68 0d |.*..I.t...hDtIh.|
@@ -24728,7 +24728,7 @@
00075340 5c 74 37 75 2d 35 04 d5 0b 74 2f 45 7a 77 cd 75 |\t7u-5...t/Ezw.u|
00075350 13 d6 1a 77 cd 75 1c da 48 5a 5b 5a 5a 5a 58 5a |...w.u..HZ[ZZZXZ|
00075360 5a 5a 5a 5a 5a 5a 52 5a b5 5a 4d 5a 1d 5a 3a 5a |ZZZZZZRZ.ZMZ.Z:Z|
-00075370 6a 5a 59 5a 5b 5a 58 5a 5a 5a 5b 5a 53 5a 58 5a |jZYZ[ZXZZZ[ZSZXZ|
+00075370 69 5a 59 5a 5b 5a 58 5a 5a 5a 5b 5a 53 5a 58 5a |iZYZ[ZXZZZ[ZSZXZ|
00075380 61 5a 5a 5a 58 5a 5b 5a 5a 5a fa 5a 68 5a 53 5a |aZZZXZ[ZZZ.ZhZSZ|
00075390 5e 5a 5a 5a 5a 5a 5b 5a 59 5a 5b 5a 5b 5a 5a 5a |^ZZZZZ[ZYZ[Z[ZZZ|
000753a0 53 5a 7b 5a 5a 5a 5b 5a 5a 5a 5b 5a 78 5a 0b 5a |SZ{ZZZ[ZZZ[ZxZ.Z|