Hintergrund: Warum die Tastatur?

Ich bin schon lange ein Freund der Tastaturbedienung und meide eher die Maus bzw. das Touchpad, weil ich mit der Tastatur schneller eine größere Vielzahl an Funktionen erreichen kann. Für viele Programme habe ich daher immer versucht eine Variante zu finden, die sich so gut wie möglich über die Tastatur bedienen lässt: Window-Manager (früher IceWM, heute Awesome, mit Wayland 🤔), Mailprogramm (Neomutt), Schreibprogramm (früher Jed, jetzt Emacs).

Für den Browser ist dies etwas schwieriger, da viele Elemente nur über die Maus erreichbar sind, obwohl ich überwiegend lese und seltener mit den Seiten interaggiere. Früher habe ich Conkeror verwendet, der Firefox als Unterbau verwendet hat und darauf eine tastaturfreundliche Oberfläche gebaut hat sogar mit einem Minibuffer wie im Emacs, mit dem man leicht Funktionen über ihren Namen aufrufen konnte. Das praktische an Conkeror war auch, dass er mit einer Javascript-Datei konfiguriert werden konnte, was damals schon die Nutzung mehrerer Profile sehr vereinfacht hat, weil ich entsprechende Abfragen und Verzweigungen einbauen konnte.

Leider kam irgendwann das Ende, weil Firefox den Zugriff auf den Unterbau XULrunner nicht mehr ermöglicht hat. Ich bin dann zum richtigen Firefox gewechselt und habe mit der Erweiterung Keysnail weitergemacht. Dieser fehlte zwar der Minibuffer, aber die wichtigsten Tastenkürzel von Emacs waren umgesetzt, sodass ich nicht viel darüber nachdenken musste, in welchem Programm ich war. Und Keysnail hatte ebenfalls eine Konfigurationsdatei, die es ermöglicht hat, neue Funktionen zu schreiben.

Die Erweiterbarkeit ist eine der wichtigsten Eigenschaften von Programmen für mich. Sei es mit Emacs, Awesome, Keysnail oder der Zsh – wenn ich merke, dass ich irgendwelche Schritte wiederholt durchführe oder mir Ideen kommen, wie ich etwas angenehmer gestalten könnte, dann möchte ich etwas tun und meine Ideen umsetzen können – alles andere ist auf die Dauer frustrierend. Daher achte ich bei der Wahl essentieller Programme darauf, dass ich eine Möglichkeit zum Anpassen und Erweitern habe. – Das als kleiner Einschub.

Leider kam mit Firefox 57 auch für Keysnail das Ende, denn Firefox hat die Schnittstelle für die Add-ons gewechselt, womit viele Add-ons nicht mehr funktioniert und viele Entwickler die Entwicklung eingestellt haben. Ich habe mich dann noch drei Jahre mit dem Nicht-Aktualisieren meines Firefox 56 dahingerettet, aber über die Zeit hin haben diverse Seiten wie Element, Zeit-Online, WhatsApp, YouTube, Crates.io Stück für Stück nicht mehr funktioniert. Parallel zu dem veralteten Hauptbrowser hatte ich schon lange in anderen Profilen Fiefox-Nightly, Firefox-Developer und die aktuelle Version genutzt. Aber die meisten Seiten habe ich weiterhin mit meinem Hauptbrowser besucht.

Mir war klar, dass dies nicht ewig geht, nur leider fehlte mir lange der Ersatz. Ich hatte zwar irgendwann schon einmal Surfingkeys (Firefox-Add-on, Chrome-Add-on) ausprobiert, aber irgendwie kam ich damit nicht zurecht. Heute habe ich mich noch einmal daran probiert und muss sagen, mein erster Eindruck war eine völlige Fehleinschätzung. Surfingkeys ist absolut klasse.

Eigene Funktionen für Tastenkürzel definieren

Eine Funktion, die ich mir für Keysnail gebastelt hatte und die ich sehr häufig nutze, ist das Kopieren des Titels und der URL einer Seite als Markdown-Link. Damit kann ich sehr leicht für eine Webseite einen Link zum Einfügen in ein Markdown-Dokument erstellen. Dies war also die Bewährungsprobe für Surfingkeys und nach längerem Suchen habe ich auch die Stelle zum Eintragen gefunden.

Für eigene Funktionen muss man in den Settings von Surfingkeys den Advanced mode aktivieren. Damit bekommt man einen kleinen Editor unterhalb des Hakens angezeigt, mit dem man seine Erweiterungen programmieren kann. Die Funktion für den Markdown-Link ist einfach und ich habe sie der Tastenfolge c m zugewiesen:

mapkey('cm', 'Copy markdown link of current page', function() {
    Clipboard.write(
        '['
        + document.title.replace('[', '\\[').replace(']', '\\]')
        + '](' + window.location.href + ')'
    );
})

Damit war das Wichtigste gezeigt: die Konfigurier- und Erweiterbarkeit. Dann ging es ans Entdecken der Funktionen von Surfingkeys.

Grundsätzliches zu den Tastenbelegungen

Der Entwickler von Surfingkeys ist (leider) ein vi/vim-Liebhaber, weshalb sich die Bedienung an vi anlehnt. Das heißt, es gibt einen Command-Modus, indem eine andere Tastenbelegung gilt als im Visual-Modus und im Eingabe-Modus. Ich selbst bin mit dieser Denkweise nie warm geworden, aber grundsätzlich gilt: mit v aktiviert man den Visual-Modus und mit Esc geht man wieder zurück zum Command-Modus. Jede Funktion im Visual-Modus lässt sich also auch als Folge von Tastendrücken verstehen, womit ich als Emacs-Liebhaber wiederum kein Problem1 habe.

  1. “Hey dad! Do you see how this man can twist his fingers? Amazing, isn't it?” “No son, not really. He's been using Emacs for ten years.” 

Ob man sich gerade im Visual-Modus befindet, kann man an einer kleinen Markierung am unteren, linken Fensterrand sehen. Dort erscheinen auch andere Meldungen, sodass man immer mal wieder in diese Ecke blicken sollte.

So ganz allgemein erachte ich die Verwendung von einfachen Tasten als sinnvoll, da man beim normalen Lesen keine Eingaben tätigt. Daher ist die Anlehnung an vi bzw. auch less treffender als die permanente Nutzung der Strg wie im Emacs – ein Browser ist eben kein Editor.

Die Liste alle Tastenbelegungen kann man sich mit ? anzeigen lassen. Mit p kann man für kurze Zeit die Tastenbelegungen von Surfingkeys deaktivieren und mit Alt-p1 bis zum Drücken von Esc. Dies ist auf einigen Seiten wie YouTube oder GitHub nützlich, weil die Seiten (der Player) selbst eine Tastaturbedienung mit ähnlichen Tasten vorsieht, wie sie auch Surfingkeys nutzt.

  1. Diese Tastenkombination habe ich gewählt. Im Original ist es Alt‑i

Grenzen von Surfingkeys

Gleich zu Anfang muss ich sagen, dass Surfingkeys leider nicht unter allen Umständen funktioniert. Während Keysnail zum Beispiel auch in der Adresszeile funktionierte, gibt es für Surfingkeys Beschränkungen, die Anpassungen nicht überall erlauben. Zum einen sind Anpassungen auf den Spezialseiten about:… und Fehlerseiten nicht möglich, dann erlaubt Firefox keine Veränderung auf Seiten von addons.mozilla.org und zum anderen wird Surfingkeys in jedem Tab erst nach dem Laden aktiv, weshalb während des Ladens die Tastaturanpassung (z. B. Schließen oder Wechsel des Tabs) nicht funktioniert.

Weiterhin habe ich Zustände beobachtet, in denen Surfingkeys wie abgestürzt erschien, also nicht mehr reagierte. Erklären kann ich den Zustand nicht, aber es funktionierte die Tastaturanpassung nicht mehr. Wobei dies auch selten vorkommt.

Man muss sich also auch weiterhin die gängigen Tastenkombinationen wie Strg-w zum Schließen oder Strg-l für die Adresszeile merken. Da auch nicht immer erkennbar ist, ob Surfingkeys aktiv ist, habe ich es tunlichst vermieden Strg-w oder gar Strg-q zu belegen, obwohl dies überraschender Weise möglich ist. Dafür habe ich aber Strg-s belegt, weil dies die Tastenkombination ist, die sich mir am stärksten eingebrannt hat und die mich immer wieder beim Firefox aufschreien lässt.

Meine Tastaturbelegung

Die Tastaturbelegung von Surfingkeys ist sehr umfangreich, aber ich empfinde sie als nicht sehr einprägsam, weshalb ich mir meine eigene Tastenbelegung erstellt habe. Diese weicht in Teilen stark von der Originalbelegung ab, aber ich habe auch Belegungen beibehalten, sodass es eine Mischung geworden ist. Zusätzlich dazu gelten auch noch einige Standardbelegungen wie Strg-Tab zum Tabwechseln oder Strg-c zum Kopieren.

Ich bin es auch von Emacs gewöhnt, dass man die Funktion einer Taste durch ein Prefix-Argument verändern kann. Im Emacs kann man dieses mit Alt-1…9 angeben, aber bei Surfingkeys braucht man nur die Ziffern 1…9 nutzen. Zu 100 % funktioniert es zwar nicht, denn man muss mindestens eine 2 angeben, aber vielleicht finde ich dafür noch eine Lösung. Als kleines Beispiel habe ich mit Umschalt-f das öffnen eines Links in einem neuen Tab, mit 2 Umschalt-f lassen sich mehrere Links wählen.

Grundsätzlich habe ich auch immer versucht die einfache Taste für den aktuellen und die Kombination mit der Umschalttaste für einen neuen Tab zu verwenden; f folgt einem Link im aktuellen Tab, Umschalt-f folgt in einem neuen Tab.

Nutzung meiner Konfiguration

Wer meine Konfiguration nutzen möchte, muss in den Settings des Surfingkeys-Menüs den Advanced mode aktivieren und in die Eingabezeile Load settings from die Adresse https://jo-so.de/2021-01/Surfingkeys.js eintragen und auf Save klicken.

Navigation innerhalb der Seite

Neben den üblichen Tasten zur Navigation gibt es noch w und d um jeweils eine halbe Bildschirmseite nach oben bzw. unten (down) zu gehen. Beim Lesen von Texten finde ich das wesentlich angenehmer als eine komplette Bildschirmseite zu springen, ähnlich wie es auf der Kommandozeile auch less bietet.

Das Scrollen der Seite erfolgt dabei von Haus aus gleitend, was ich als nicht angenehm entfinde. Daher habe ich in den Einstellungen settings.smoothScroll = false; hinzugefügt, damit der Wechsel sprunghaft passiert. Es lässt sich wohl auch noch die Schrittweite der Bewegungen mit settings.scrollStepSize = …; festlegen, aber dies habe ich nicht angepasst.

Weiterhin nutze ich oft den Sprung zum Seitenanfang mit < und > zum Seitenende. Eine komplette Seite weiter kann man mit der Leertaste springen und eine Seite zurück mit b.

Navigation zwischen den Tabs

Da ich häufig zwischen linkem und rechtem Tab wechsle, habe ich mir diese Funktionen auf die Tasten e und r (right) gelegt. Mit t kann man der Liste aller Tabs anhand des Titels oder der URL einen auswählen.

Aktionen für Tabs

Den aktuellen Tab kann man mit x schließen und mit Umschalt-x den zuletzt geschlossenen Tab wieder öffnen. Mit Umschalt-r lässt sich der Tab neu laden (engl. reload) und mit Umschalt-d duplizieren. Der neue Tab öffnet sich dann im Hintergrund, aber mit einem Prefix (z. B. 2 D) öffnet sich der neue Tab im Vordergrund.

Mit dem Anfang Umschalt-t gibt es Aktionen für andere Tabs. Mit T x lassen sich Tabs schließen: T x e der linke, T x r der rechte, T x x der aktuelle, T x E alle linken und T x R alle rechten.

Im Menü von uBlock origin gibt es den Blitz zum Löschen von Teilen aus der Webseite. Bereits von Conkeror kenne ich diese Funktion und daher habe ich sie mir mit Surfingkeys jetzt nachgebaut. Mit Strg-d kann man ein Element auswählen, das aus der Seite entfernt wird. Mit einem Prefix-Argument (z. B. 2 Strg-d) lassen sich mehrere Elemente hintereinander löschen.

Links anwählen

Um einen Link »anzuklicken«, ihm also zu folgen, kann man mit f über eingeblendete Kürzel den gewünschten Link auswählen. Sollte es nur einen Link auf der Seite geben, wird dieser sofort angesprungen. Mit Umschalt-f wird der Link in einem neuen Tab geöffnet oder – auf der Ergebnisseite von Suchanfragen nutze ich dies gern – mit einem Prefix-Argument 2 Umschalt-f kann man mehrere Links im Hintergrund öffnen.

Eine Adresse ansteuern

Unter dem Anfang g (engl. go-to) habe ich Adresswechsel für den aktuellen Tab und unter Umschalt-g für einen neuen Tag angeordnet. Will man eine neue Adresse öffnen, so geht dies mit g g bzw. G G für einen neuen Tab. Mit g # geht man zur aktuellen Adresse ohne das Fragment, mit g ? ohne die aktuellen Parameter, mit g ^ geht man eine Verzeichnisebene nach oben und mir g / zum Hauptverzeichnis.

Mit g c bzw. G c lässt sich die URL in der Zwischenablage (engl. clipboard) ansteuern. Mit g b (engl. go back) und Umschalt-b kann man in der Historie zurück gehen und mit g f (engl. go forward) kann man sich in der Historie vorwärts bewegen.

Sprungmarken

Ebenfalls von less kenne ich Sprungmarken, die wie Lesezeichen für Positionen innerhalb der Seiten sind. Mit m und einer weiteren selbstgewählten Taste kann man sich an der aktuellen Position eine Markierung setzen. Mit ' und eben dieser Taste kann man zu der Position zurück. Mit der Folge g m bekommt man die Liste der definierten Marken und kann sie ebenfalls ansteuern.

Kopieren

Wie eingangs angesprochen, kopiere ich auch häufe einen Verweis auf die aktuelle Seite. Solche Kopierfunktionen beginnen mit c (engl. copy). Für die Adresse des aktuellen Tabs ist es c c, mit c h nur der Servername und mit c m die Adresse und der Titel als Markdown-Link. Mit c t lässt sich der Titel der Seite kopieren.

Mit c e lässt sich der Text eines Elementes kopieren und mit c i der Verweis auf ein Element mit einer ID. Vor allem die letzte Funktion ist nützlich, weil nicht immer entsprechende Verweise existieren, die sich kopieren lassen. Bisher verwende ich immer die Erweiterung Webdeveloper, um diese Verweise einblenden zu lassen, aber mit dieser Funktion von Surfingkeys geht es mit der Tastatur nun schneller.

Mit c l lässt sich die Adresse eines Verweises kopieren und mit c Umschalt-l der Text und die Adresse als Markdown-Link.

Ein Textabschnitt einer Seite lässt sich wie folgt kopieren: Mit v (engl. visual caret) wechselt man in den Cursor-Modus und kann eine Stelle auswählen. Dort wird dann ein Cursor angezeigt und man kann mit w und b ein Wort vorwärts bzw. rückwärts springen. Dies bestimmt den Anfang der Markierung und durch ein weiteres Mal v kann man in den Markierungsmodus (engl. visual range) wechseln. Dort kann wieder mit w, b und anderen Tasten hin- und herspringen und den Bereich vergrößern. Am Ende kann man den Text mit y (engl. yank) kopieren. Zum Schluss kann man den Markierungsmodus mit Esc und den Cursor-Modus mit einem weiteren Esc verlassen.

Dies ist genau die Bedienung von Vim, mit der ich nie warm geworden bin, aber ich brauche diese Funktion so selten, dass ich es dann immer irgendwie schaffe.

Suche

Surfingkeys kommt mit einer eigenen Suchfunktion, die an das Verhalten von Vim angelehnt ist. Mit / (und zusätzlich Strg-s 😀) öffnet sich rechts unten ein kleines Feld, in das man seinen Begriff eingeben kann. Mit Enter beginnt die Suche und man kann mit n und Umschalt-n vorwärts bzw. rückwärts durch die Treffen springen. Dies finde ich wesentlich angenehmer als Umschalt-Strg-g bei der Firefox-Suche.

Übersetzungen mit Linuguee

Eine sehr interessante Funktion ist die Übersetzung innerhalb der Seite. Mit Q öffnet sich ein Eingabefeld, in das man ein Wort eingeben kann, wobei die Liste der Vervollständigungen die Wörter der Seite sind. Aber man kann auch jedes andere Wort eingeben. Für die Eingabe schlägt Surfingkeys dann die Übersetzung nach. Natürlich muss man dafür einen Übersetzer einrichten. Ich habe mir eine entsprechende Funktion für Linguee gebastelt und den Code bei Advanced mode in den Settings eingefügt.

Weiterhin lässt sich die Übersetzung eines Wortes vom Cursor-Modus (visual caret) mit v und der Taste q aufrufen. Danach lässt sich die Übersetzung wieder mit Esc ausblenden.

Front.registerInlineQuery({
    url: "https://www.linguee.de/deutsch-englisch/search?il=DE&tool=opensearch&query=",
    parseResult: function(res) {
        const doc = new DOMParser().parseFromString(res.text, "text/html");
        const dict = doc.querySelector('#dictionary');

        // translation_group: less common translations
        // example_lines: example usage snippets
        // openTriangle: triangle open buttons for the head lines
        // a.audio: link for audio example
        // a.expand_i: link for more examples
        dict.querySelectorAll('.translation_group, .example_lines, .openTriangle, a.audio, a.expand_i')
            .forEach(e => e.remove());

        dict.querySelectorAll('a')
            .forEach(e => e.replaceWith.apply(e, e.childNodes));

        const nodesToDrop = [];
        dict.childNodes.forEach(el => {
            if (el.nodeName === 'H1' && el.id !== 'wikipedia-header') {
                const new_el = doc.createElement('span');
                new_el.innerText = el.innerText.replaceAll(/^.*\(|\)$/g, '');
                el.replaceWith(new_el);
            } else if (
                el.classList && (
                    el.classList.contains('isForeignTerm')
                        || el.classList.contains('isMainTerm'))
            ) {
                const ul = doc.createElement('ul');
                el.querySelectorAll('.lemma').forEach(lem => {
                    const li = doc.createElement('li');
                    li.append.apply(li, lem.querySelector('h2').childNodes);

                    lem.querySelectorAll('.tag_trans')
                        .forEach(trans => li.append(trans, ','));

                    ul.append(li);
                });
                el.replaceWith(ul);
            } else {
                nodesToDrop.push(el);
            }
        });

        nodesToDrop.forEach(el => el.remove());

        dict.querySelectorAll('*').forEach(el => {
            el.getAttributeNames().forEach(at => {
                if (at !== 'class')
                    el.attributes.removeNamedItem(at);
            });
        });

        return dict.innerHTML;
    }
});

Javascript-Code in der Seite ausführen

Da Surfingkeys richtig Javascript-Code im Kontext der Webseite ausführt, kann man dies auch für andere Anpassungen nutzen. Zum Beispiel stört mich immer, dass bei den Xing-Meldungen die eigentliche Seite in einem iFrame geöffnet wird. Mit Surfingkeys kann ich – in guter, alter Conkeror-Manier – ein wenig nachhelfen und das gewünschte Verhalten erzeugen:

if (window.origin === "https://www.xing-news.com") {
    const art = document.getElementById('article');
    if (art && art.src) {
        // load the iframe in the whole tab
        window.location.href = art.src;
    }
}

Weitere Informationsquellen