surf-Browser mit neuen Tastenkürzeln versehen
Der Browser surf kann durch Bearbeiten der Datei config.h u.a. um neue Tastenkürzel erweitert werden, was allerdings nicht wirklich dokumentiert ist.
Vor kurzem bin ich auf Gentoo Linux umgestiegen. Mein erster Eindruck soweit: Man muss viel kompilieren. Sehr viel. Abgesehen davon bin ich aber nunmehr systemd-frei unterwegs, was die langen Kompilationszeiten wieder wettmachen sollte.
Als Browser habe ich mich für den Moment für surf entschieden, weil dieser Browser ab Werk eine annehmbare Tastaturbedienung vorsieht, die ich selbst mit Addons in Firefox nicht erreichen konnte. Abgesehen davon ist surf auch erfreulich klein. Die Kompilationszeit von Webkit allerdings sollte man nicht unterschätzen.
Das Ebuild für surf unterstützt die besondere USE-Flagge
savedconfig
, die es erlaubt, die standardmäßige config.h
-Datei mit
einer eigenen zu ersetzen. Im Fall von surf definiert diese Datei
insbesondere die Tastenkürzel, die in der Standardkonfiguration recht
gewöhnungsbedürftig sind (sie sehen für mich Emacs-Nutzer aus, als
wäre ein Vi-Nutzer dafür verantwortlich gewesen).
Um eine eigene config.h
zu verwenden und diese Tastenkürzel durch
eigene zu ersetzen, geht man wie folgt vor.
Zunächst ist surf überhaupt erst einmal zu installieren.
# emerge --ask www-client/surf
Danach teilt man Portage mit, dass eine eigene config.h
anstelle
der standardmäßig in surf mitgelieferten zu verwenden ist. Dies
geschieht durch Zuteilung der savedconfig
-USE-Flagge an das
entsprechende Ebuild, was widerum durch Bearbeitung von
/etc/portage/package.use
zu erreichen ist; ich organisiere diese
Konfiguration als Verzeichnis, daher war das Erstellen einer neuen
Datei /etc/portage/package.use/surf
mit folgendem Inhalt
erforderlich:
www-client/surf savedconfig
Dabei wird davon ausgegangen, dass savedconfig
nicht bereits als
globale USE-Flagge gesetzt ist.
Sodann kann die config.h
bearbeitet werden, die Portage bei der
ursprünglichen Installation von surf in
/etc/portage/savedconfig/www-client/surf-<version>
abgelegt hat.
In dieser Datei lassen sich diverse Standardeinstellungen bearbeiten, für diesen Artikel relevant sind ausschließlich die Tastenkürzel, die sich ihrerseits in zwei Abschnitte unterteilen, deren erster mit dieser Zeile beginnt:
#define SETPROP(p, q) { \
Die Struktur ist so gedacht, dass man im Bereich der
#define
-Direktiven Aufrufe an externe Programme kodiert. Dies
ermöglicht es, im zweiten Teil der Tastenkürzelkonfiguration auf die
hier definierten Makros zurückzugreifen und diesen schön formatiert zu
halten; ein zwingendes Erfordernis ist die Einhaltung dieser Struktur
jedoch nicht. Sie ist aber aus Übersichtlichkeitsgründen
empfehlenswert.
Die Makros selbst definieren jeweils ein Array von Strings, dessen einzelne
Elemente später als Argumente für den einzelnen Programmaufruf genutzt
werden. In der Regel wird man als Programm /bin/sh
aufrufen, um
unter Durchsuchung der Umgebungsvariable PATH
ein beliebiges
Programm aufrufen zu können.
Die Argumente für die Makros sind frei wählbar und werden während der Auflösung im zweiten Teil der Konfiguration einfach ersetzt. Es ergibt sich grundsätzlich folgende Struktur:
#define MAKRO { .v = (char* []){ "/bin/sh", "-c", \ "PROGRAMM ARG1 ARG2 ...", SUBST1, SUBST2, ..., NULL } }
Die nach den Strings folgenden Parameter SUBST1
usw. dienen der
Interpolation von Werten in die eigentlichen Strings; die Liste der
Ersetzungen ist mit NULL
zu beenden. Der besondere Wert winid
gibt
dabei die Window-ID der laufenden Instanz von surf an (zu deren
Gebrauch sogleich).
Die von surf standardmäßig definierten Makros SETPROP
und DOWNLOAD
sind komplizierter aufgebaut, was aber nur daran liegt, dass sie
(unnötigerweise) Argumente annehmen und recht komplexe Befehle
absetzen. Als Beispiel für ein neues Tastenkürzel, welches eine
Websuche mithilfe von DuckDuckGo startet, könnte das Makro etwa
so aussehen:
#define SEARCH { .v = (char *[]){ "/bin/sh", "-c", "search $0", \ winid, NULL } }
Dies ruft ein Programm search
auf und übergibt ihm als erstes und
einziges Argument die Window-ID von surf (man beachte, wie $0
durch
das erste Argument nach den Strings, winid
, ersetzt wird). Das
Programm search
existiert freilich noch nicht, in diesem Beitrag
soll es mithilfe eines kleinen Ruby-Skripts realisiert werden, welches
man als /usr/local/bin/search
speichert (Ausführbarmachen mit chmod a+x
/usr/local/bin/search
nicht vergessen) und folgenden Inhalt hat:
#!/usr/bin/ruby require "uri" wid=ARGV[0].strip term = `echo " " | dmenu -p Duckduckgo: ` .strip exit 0 if term.empty? target = "https://duckduckgo.com/?q=#{URI.escape(term)}" system "xprop -id #{wid} -f _SURF_GO 8s -set _SURF_GO #{target}"
Natürlich hätte man auch ein gewöhnliches Shell-Skript benutzen
können, aber dann wäre es schwierig geworden, den Suchbegriff in das
für URLs nötige Format zu überführen. Ruby bietet mit der
URI-Bibliothek jedoch eine Methode URI.escape
an, die die
notwendigen Ersetzungen (insbesondere von Abständen durch %20
)
vornimmt.
Nachdem diese Bibliothek per require "uri"
eingebunden wurde, ruft
das Skript zunächst das übergebene Kommandozeilenargument ab, bei dem
es sich wie bekannt um die Window-ID von surf handelt. Anschließend
ruft es das sehr universell einsetzbare Programm dmenu
auf, welches
den Nutzer nach einem Suchbegriff fragt; leider ist es mir nicht
gelungen, dmenu
ohne Suchwortliste auf der Standardeingabe zu
starten (die in diesem Kontext einfach keinen Sinn macht). Daher habe
ich dmenu
einfach ein einzelnes Leerzeichen als Suchwort übergeben,
was vielleicht nicht elegant ist, aber funktioniert. Vorschläge zur
Verbesserung nehme ich gern entgegen.
Bricht der Nutzer die Eingabe in dmenu
ab, gibt das Programm nichts
aus. In diesem Fall wird auch das Skript beendet und tut nichts
weiter.
Hat der Nutzer dagegen eine Eingabe vorgenommen, wird diese zunächst
mithilfe von URI.escape
in ein URL-freundliches Format überführt und
dann in eine URL eingesetzt, die unmittelbar die Suchfunktion von
DuckDuckGo aufruft.
Die letzte Zeile ist die eigentlich interessante: Hier wird die so
konstruierte URL wieder an surf übergeben. surf bietet dafür einen
wohl einzigartigen Mechanismus an: X11-Properties. Dazu muss man
wissen, dass auf einem X-System jedes Fenster eine beliebige Liste von
Eigenschaften (Properties) besitzt, die sozusagen Meta-Informationen
über das Fenster enthalten. So ist etwa der Fenstertitel in der
Eigenschaft WM_NAME
enthalten. Jedes Fenster darf beliebig viele
Eigenschaften haben und neue definieren, nur ein begrenzter Satz ist
durch die EWMH (extended window manager hints)
standardisiert. Mithilfe des Programms xprop
können diese
Eigenschaften sowohl ausgelesen als auch geschrieben werden.
surf bietet nun vor allem drei relevante Eigenschaften in seinem Fenster an:
- WM_NAME
- Dies ist der Fenstertitel. Entspricht einem Präfix von surf selbst,
das mit einem Balken | abschließt, der vom Inhalt des
<title>
-Tags gefolgt wird. - _SURF_URI
- Diese nicht standardisierte Eigenschaft enthält die URI der Webseite, die surf gerade anzeigt.
- _SURF_GO
- Wird in diese nicht standardisierte Eigenschaft geschrieben, ruft
surf die hier hinterlegte URI auf. Will man also erreichen, dass surf
eine Seite aufruft, schreibt man deren URI hier hinein. In der Folge
werden
_SURF_URI
undWM_NAME
automatisch aktualisiert und die neue Webseite dem Nutzer angezeigt.
Die besondere Eigenart von _SURF_GO
macht sich obiges Skript zu
Nutze, um surf direkt auf DuckDuckGo zu schicken. Der Parameter -id
gibt an, welches Fenster xprop
bearbeiten soll, -f
gibt den
Typ für eine Eigenschaft an. Da _SURF_GO
gesetzt werden soll, wird
auch deren Typ festgelegt, und zwar auf 8s
— das scheint ein
gewöhnlicher String zu sein. Ich habe das nicht weiter kontrolliert,
sondern einfach aus der Definition des bereitgestellten Makros
SETPROP
kopiert. Die Manpage von xprop(1) jedenfalls gibt dazu
nichts her. Schließlich wird mit -set
verlangt, dass die Eigenschaft
_SURF_GO
auf den nachfolgenden Wert geändert wird, bei dem es sich
um die vollständige URI zur Suchfunktion von DuckDuckGo
handelt. Sobald surf die Änderung der Eigenschaft bemerkt, ruft es die
neue Seite auf und der Nutzer sieht die Ergebnismaske von DuckDuckGo.
Nachdem dieses Skript abgespeichert wurde, muss es noch an ein
Tastenkürzel in surf gebunden werden. Dies geschicht im zweiten Teil
der Konfiguration in config.h
, der langen Liste nach dieser Zeile:
static Key keys[] = {
Jeder Eintrag der Liste folgt einem einfachen Schema:
{ Modifier, Haupttaste, Typ, Ziel },
Die verschiedenen Aktionstypen lassen sich der bestehenden config.h
ohne weiteres entnehmen. Modifier
bezeichnet die
Modifikationstasten, also etwa Umschalt und Strg (das Makro MODKEY
zeigt standardmäßig auf die Strg-Taste). Die zulässigen Werte für die
Haupttasten lassen sich der Datei
/usr/include/gtk-2.0/gdk/gdkkeysyms-compat.h
entnehmen.
Für dieses Beispiel relevant ist nur der Aktionstyp spawn
, der ein
externes Programm startet. Folgende Zeile kann daher der Konfiguration
hinzugefügt werden:
{ MODKEY, GDK_d, spawn, SEARCH },
Damit wird für die Tastenkombination Strg+d SEARCH
aufgerufen. Dieses Makro wurde weiter oben bereits definiert; es ruft
das Skript search
auf. Damit sind die erforderlichen Änderungen
vorgenommen.
Zuletzt muss surf neu kompiliert werden. Da die USE-Flagge bereits angepasst wurde, genügt dazu:
# emerge www-client/surf
Auf diese Weise lassen sich beliebige neue Befehle in surf einbauen und bestehende verändern.
Valete.