blog · git · desktop · images · contact


lariza bekommt vielleicht JS-Userskripte – und dadurch einen Follow Mode

2020-02-24

In der README von lariza steht:

Background information
----------------------

 What lariza is and what it's not

  ...

  Especially, it's very likely that lariza will never have a "follow
  mode" like dwb, luakit or others have. I've used these browsers for
  quite some time and I've also used Firefox extensions that add a
  "follow mode". The point is, "follow mode" doesn't work anymore. This
  was a good thing ten years ago. Today, a lot of websites make heavy
  use of JavaScript or hovering. You NEED some kind of pointing device.
  I found using "follow mode" to be very frustrating today, because you
  still have to reach for the mouse all the time. So, you might as well
  just optimize your mousing workflow.

„Ten years ago“ bezieht sich auf 2004 und war vielleicht damals schon zu optmistisch.

Jedenfalls könnte sich das ändern.

2019 war ein „Jahr des Schmerzes“. Ja, klingt ein bisschen dramatisch. :) Das ganze Jahr über hatte ich es mit Schmerzen in den Handgelenken zu tun und anderen Problemen in dieser Gegend. Das ist immer noch ein bisschen ungeklärt alles und auch noch nicht ganz vorbei. Das Ding ist aber, dass es mir derzeit wirklich schwer fällt, die Maus zu benutzen. Wie da oben aber schon steht, zwingt lariza einen eigentlich genau dazu und deswegen habe ich dann aufgehört, den Browser zu benutzen. Bin zurück zu Firefox, was seine eigenen Bugs hat, und dann zu Chromium – mit Vimium als Plugin.

Vimium hat ein paar nette Shortcuts, aber vor allen Dingen auch einen „Follow Mode“. Das ist so viel komfortabler als Mausbenutzung oder ein Touchscreen. Meiner Ansicht nach sollte jeder Browser (jede UI allgemein?) sowas eingebaut haben und es sollte der Standard sein, wie wir im Web navigieren, aber nungut.

Jedenfalls ist es sprichwörtlich schmerzhaft, lariza in der aktuellen Form zu benutzen. Ich will das Projekt nicht aufgeben, also muss man da was tun.

Eine kleine Vorschau.

larizas Follow Mode

Man drücke einen Hotkey (derzeit f), um Link Hints zu aktivieren:

1.png

Man beachte, dass die Labels rechts neben den eigentlichen Links sitzen, was anders als in anderen Implementierungen ist – darauf kommen wir noch zu sprechen. Die Labels sehen dann wie kleine Pfeilchen aus, um die Verwirrung hoffentlich ein bisschen zu lindern.

Den Rest kennt man: Man tippt ein paar der Zeichen der Labels ein, um die Auswahl immer weiter einzuschränken. Als nächstes habe ich h gedrückt:

2.png

In hellem Grün die aktuelle Auswahl. Ich könnte jetzt Enter drücken, um den Link zu öffnen. Man beachte, dass das eigentliche Element nochmal hervorgehoben ist – auch darauf kommen wir noch zurück.

Dann d gedrückt:

3.png

Jetzt ist nur noch ein Label übrig, man muss aber trotzdem Enter zum Bestätigen der Auswahl drücken. Yep, auch darüber sprechen wir noch.

Zur Implementierung des Follow Mode

WebKit trennt den C-/GTK-Code von allem, was in der eigentlichen Webseite passiert. Mit anderen Worten, man kommt von C aus nicht an das DOM der Seite ran. Man muss JavaScript benutzen. lariza lässt daher schon ein kurzes Stückchen JS laufen, um die Liste der URLs für RSS-/Atom-Feeds zu bekommen.

Daraus ergeben sich ein paar Probleme.

Zuerst einmal muss natürlich auch der Follow Mode in JS geschrieben sein. Man muss ja ans DOM und das geht nur mit JS. Die Bauchschmerzen hier entstehen nicht dadurch, dass „JavaScript eine blöde Sprache“ sei, sondern dadurch, dass es eine fast komplett getrennte Welt ist – ein großer Bruch zwischen C/GTK und dieser JS-Welt. Es ist im Wesentlichen ein zweites Programm, das irgendwie mit dem ersten kommunizieren muss. Sein Code läuft asynchron zum Hauptprogramm, Input-Events sind ganz andere und so weiter.

Habe ich so gemacht, dass ich ein generisches „Userkript“-Feature eingebaut habe, so ähnlich wie surf das hat. Anders als surf führt lariza aber nach dem Laden einer Seite einfach alle Dateien aus, die sich in einem bestimmten Verzeichnis befinden.

Um ehrlich zu sein, ist der Follow Mode auch so ziemlich das einzige, wofür man Userskripte in meinen Augen sinnvollerweise einsetzen kann. Man kann jetzt an eigene Keybinds denken, aber da bitte erstmal weiterlesen. Okay, man kann mit Userskripten vielleicht noch auf lästigen Webseiten bestimmte Elemente löschen. Das war’s dann aber, glaube ich, auch. Vielleicht bin ich auch nicht kreativ genug. Trotzdem war dieser Ansatz der am wenigsten invasivste – der Diff ist winzig und lariza selbst weiß auch gar nichts von einem Follow Mode. Es sagt WebKit nur, dass es ein bisschen JavaScript ausführen soll. Wie wir gleich sehen werden, funktioniert das so einigermaßen, ist aber weit entfernt von einer perfekten Lösung und vielleicht nicht einmal eine gute.

Was ich schon nicht hinbekommen habe, ist, meine eigenen Skripte gegenüber denen der Webseite zu isolieren. Heißt also, wenn man nicht in den Userskripten alles in eine anonyme Funktion wrappt, wie unten gezeigt, dann kann die Webseite deine Variablen auslesen und beeinflussen! Oder du kannst Variablen im Code der Webseite kaputtmachen. Ziemlich nervig – und sieht auch so aus, als wäre das bei Browsern wie Chromium anders.

(function() {

    // Configuration
    var charset = "sdfghjklertzuivbn".split("");
    var key_follow = "f";
    var key_follow_new_win = "F";

    function update_highlights_or_abort()
    {
        ...
    }

    ...

}());

Das kann man nun zwar mit dieser anonymen Funktion umgehen, aber wenn es um Key-Handler geht, wird es viel schlimmer. Man kämpft nämlich gegen die Webseite an. Das Firefox-Plugin Vim Vixen hat das Problem auch (und verliert den Kampf – Key-Handler der Webseite und des Plugins triggern beide). Nur Vimium scheint dieses Problem meistens nicht zu haben, allerdings enthält dessen Code auch Kommentare wie: „Wir laufen so früh wie möglich, damit die Webseite vor uns keine Keys abfangen kann.“ Vielleicht ist es auch nur Chromium, was sich etwas geschickter dabei anstellt, die beiden Welten zu trennen. Keine Ahnung. Wenn ich so darüber nachdenke, fallen mir letztlich auch ein paar Webseiten ein, die ich auf der Arbeit nutzen muss, bei denen selbst Vimium versagt.

Das ist schon ganz schön mies. Ich konnte auch keinen Weg finden, das zu vermeiden. Vermutlich wird man eine ganz eigene JS API bauen müssen, um das Thema sauber zu lösen, damit lariza-Skripte ihre Event-Handler darüber registrieren können und nicht über das normale document.addEventListener() gehen müssen. Jeder Tastendruck würde dann zuerst an unsere eigenen Handler geschickt und, falls diese nichts damit anfangen können, auf dem normalen Wege zur Webseite. Habe ich bisher noch nicht so gemacht, weil es recht aufwändig ist (und weil es noch andere Dinge gibt, die kräftig in die Hose gehen, daher weiß ich noch gar nicht, ob sich der Aufwand überhaupt lohnen würde). Stattdessen haben wir jetzt folgenden Workaround:

Wird der Follow Mode aktiviert, dann erstellen wir ein verstecktes input-Feld und fokussieren es. Gibt man dann die Buchstaben der Labels ein, wird eigentlich in dieses Feld reingetippt. Albern, scheint aber zu funktionieren – zumindest für die Eingabe der Labels. Sollte eine Webseite schon die f-Taste zum initialen Aktivieren des Follow Modes ohne Fokus der Input-Box für sich beanspruchen, ist man wieder aufgeschmissen. Hatte kurz darüber nachgedacht, daraus ein Alt + f zu machen, aber das ist nicht sehr angenehm.

Noch ein Rückschlag war die Performance von element.getBoundingClientRect() in WebKit: Diese Funktion kann benutzt werden, um die sichtbare Position eines Elements zu berechnen. Idealerweise könnten wir damit die Labels „perfekt“ platzieren, nämlich genau bei den Elementen, auf die sie verweisen. Ist aber zu langsam. Viel zu langsam. Auf Webseiten mit vielen Links dauert die Erstellung aller Labels einige Sekunden auf meinem i7, der mit 3.4 GHz läuft. Die genannte Funktion scheint aber in Chromium schnell zu sein und Vimium benutzt sie auch, weshalb dieses Plugin sehr gute Ergebnisse erzielt.

Wir können’s aber nicht benutzen. Als Workaround platzieren wir jetzt die Labels so nahe wie möglich am referenzierten Element im DOM und hoffen dann, dass sie schon irgendwo in der Nähe auftauchen werden. Für <a>-Elemente werden sie als Kind hinzugefügt. Deswegen tauchen sie rechts davon auf.

Funktioniert aber auf „fancy“ Webseiten oft nicht richtig. Manchmal erscheinen die Labels einfach an der falschen Stelle. Deswegen wird das von einem Label referenzierte Element noch einmal bei der Auswahl hervorgehoben. Und deswegen ist auch das finale Drücken von Enter zum Öffnen eines Links notwendig, denn – jenachdem, wie fies die Webseite ist – man erwischt sonst oft aus Versehen einfach ein völlig falsches Element.

Und natürlich passiert all das tief im DOM der Seite. Das CSS der Webseite greift also auch für unsere Labels. Manchmal erscheinen sie daher in Großbuchstaben, weil die Webseite das so will. Oder sie haben ein kleines Icon, weil die Webseite das :before-Pseudoelement benutzt. Oder andere Elemente überdecken unsere Labels, weil, tja, die Webseite das so will. Das führt uns schließlich zum nächsten Abschnitt.

Ein Follow Mode in dieser Form kann nur unvollständig sein

Man schaue sich nur die Bugtracker von Vimium oder Vim Vixen an. Selbst diese Plugins funktionieren nicht immer. Vimium ist eigentlich verdammt gut, aber trotzdem, manchmal geht’s nicht.

Ist keine Überraschung. Webseiten sind keine passiven Dokumente. Jedenfalls heute nicht mehr. Es sind Applikationen. Und als Programmierer eines Follow Mode kämpft man ständig gegen sie an. Man kann sich das so vorstellen: Man denke an ein normales in C geschriebenes Programm für X11 und dann hat man ein anderes Program, das im selben Adressraum läuft und versucht, alle „klickbaren“ Elemente zu finden. Du weißt, wo der Ziel-Framebuffer ist, und es gibt eine kleine „API“, um grundlegende Elemente wie Buttons zu finden. Im Wesentlichen hat man aber keine Ahnung, was alles klickbar ist, weil jeder Pixel aufgrund von irgendwelchem Code klickbar gemacht sein könnte. Und dann muss man gegen das interne Fokussystem der Anwendung kämpfen. Und gegen ihr Eventsystem. Und überhaupt. Ich weiß jetzt nicht, ob das der bestmögliche Vergleich ist, aber so ungefähr fühlt sich das an. Das kann vielleicht für einfachere Programme wie leafpad noch funktionieren, aber nicht für sowas wie Blender. Es wird immer eine unvollständige Lösung sein.

Die wichtigsten Beispiele:

Ich behaupte, wenn man das sauber lösen will, muss man das in der Rendering-Engine selbst machen. Oder am besten vereinfacht man das Web wieder und entfernt die ganzen feschen Features, die oftmals ohnehin keine Verbesserung von irgendwas bringen.

Aus genau diesen Gründen habe ich damals keinen Follow Mode für lariza gebaut und auch nie geplant gehabt. Wenn ich nicht diese Probleme mit den Handgelenken hätte, wäre mir meine Zeit viel zu schade, um mich damit auseinanderzusetzen, aber, ja, hab’s dann doch gemacht, weil es besser ist als gar nichts.

Abschließende Gedanken

Wahrscheinlich wird lariza höchstens das Feature der Userskripte bekommen. Ich bin noch nicht sicher, ob ich follow_mode.js bundlen oder in ein eigenes Repo packen werde. Außerdem muss ich das alles noch weiter testen und ausprobieren. Vielleicht werfe ich es doch wieder weg, falls es einfach nicht gut genug ist.

Ich würde auch gerne vermeiden, lariza in noch so einen „vi-artigen Browser“ zu verwandeln. Davon gibt’s genug. Außerdem ist das super viel Arbeit. Im Moment ist lariza klein und das ist sehr gut so.

Aber … ja, der Follow Mode macht einige Designkonzepte von lariza kaputt. Plötzlich gibt es einen Mix aus „alle Browser-Hotkeys werden in C behandelt und sind mit Alt gepräfixt“ und „drücke f, um einen besonderen Modus in der JavaScript-Welt zu aktivieren“. Fühlt sich wie eine Mischung aus Emacs und vi an. Einfach nicht sauber. Ich habe da dann das Bedürfnis, die existierenden Hotkeys aufzuräumen und ein paar Konzepte anzupassen, aber dann wäre man eben bei genau einem vi-artigen Browser.

Um ehrlich zu sein, hätte ich den Follow Mode gerne als rein optionales Feature. Schon alleine, weil er so wackelig ist und oft kaputt geht.

Trotz aller Hürden macht (mir – in der derzeitigen Situation) die Benutzung des Browsers gleich viel mehr Spaß, wenn es einen Follow Mode gibt. :) Es ist so eine typische 80%-Lösung, aber wenn es funktioniert, dann ist es toll und sehr angenehm.

Comments?