← Alle Notizen
Praxisnotiz · Sprachwerkzeuge

Ein Diktierkürzel, das weiß, wann es weiter zuhören soll

Wie ich Voxtype, Hyper+W und Hyprland-Submaps zu einem zuverlässigen Sprachablauf für Agenten-Chats kombiniert habe.

Omarchy ist ein Arch-Linux- und Hyprland-System mit klaren Designentscheidungen, das seine Konfiguration als lesbaren Quelltext mitliefert. Genau dort wird Open Source mit Agenten besonders interessant. Den alten Linux-Aufwand aus Fehlersuche, Forenrecherche und zusammengesetzter Konfiguration kann man jetzt delegieren. Ich bekomme ein rasend schnelles Betriebssystem von jemandem, der den Stack kennt und liebt, samt Rezept. Ein Agent kann dieses Rezept untersuchen und an mich anpassen. Dieses Kürzel ist ein Beispiel für das Verhalten, das ich wollte.

Aktuelle Modelle greifen auf Funktionen des Compositors wie Submaps zurück. Opus 4.5 schien diesen Schritt bei mir nicht zu machen. OmarchySTT deckte einfaches Diktieren ab. Seine Grenzen erreichte ich, als eine Taste eine Haltefunktion, eine dauerhafte Schleife und eigene Steuerungen je Modus unterstützen sollte.

Ich wollte ein Voxtype-Kürzel mit zwei Modi: zum normalen Diktieren halten oder kurz antippen, um eine freihändige Schleife mit einem Agenten-Chat zu starten.

Das Ergebnis nutzt Hyper+W, ein kleines Steuerungsskript und zwei Hyprland-Submaps.

Die Einrichtung

Eingabe Ergebnis
Hyper+W eine Sekunde halten Aufnehmen, beim Loslassen transkribieren und einfügen
Hyper+W antippen Fortlaufendes Diktieren im Agenten-Chat starten
Enter Transkribieren, einfügen, absenden und erneut aufnehmen
Super antippen Transkribieren, einfügen, absenden und stoppen
Erneut Hyper+W Transkribieren und ohne Absenden einfügen, dann stoppen
Escape Abbrechen
F12 Den Ausgangszustand wiederherstellen

Hyper bedeutet Super+Shift+Control+Alt. Vier physische Tasten sind dafür unhandlich. Tastaturfans legen diese Kombination deshalb meist auf eine sonst kaum genutzte Taste, häufig Caps Lock. Unter Linux ist Kanata ein verbreitetes Werkzeug dafür. Karabiner-Elements übernimmt diese Rolle unter macOS.

Die physische Umbelegung ist optional. Hyprland sieht nur die resultierende Kombination der Modifikatortasten.

Warum Submaps

Eine Hyprland-Submap ist ein vorübergehender Tastaturmodus, ähnlich einem Vim-Modus auf Ebene des Compositors.

Voxtype kann Audio transkribieren, sollte aber nicht global die Enter-Taste einer beliebigen Wayland-Anwendung abfangen. Hyprland steuert ohnehin die Tastatureingaben. Deshalb lasse ich es während der Aufnahme die Steuerungstasten abfangen:

Standard
  Hyper+W
      ↓
voxtype_recording
  Enter / Escape / Super / Hyper+W sind Steuerungstasten
      ↓ Transkription abgeschlossen
voxtype_suppress
  gehaltene Modifikatortasten stören das Einfügen nicht
      ↓
Standard

Damit wird der klassische Wettlauf verhindert, bei dem Enter ein leeres Eingabefeld absendet, bevor die Transkription fertig ist.

Minimale Konfiguration

Ich habe Voxtypes eigenes Tastenkürzel deaktiviert und Einfügen über die Zwischenablage statt simulierter Texteingabe verwendet:

# ~/.config/voxtype/config.toml
[hotkey]
enabled = false

[output]
mode = "paste"
paste_keys = "shift+insert"
restore_clipboard = false
pre_type_delay_ms = 100
auto_submit = false

pre_recording_command = "/home/USER/.local/bin/voxtype-paradict submap voxtype_recording"
pre_output_command = "/home/USER/.local/bin/voxtype-paradict submap voxtype_suppress"
post_output_command = "/home/USER/.local/bin/voxtype-paradict submap reset"

wl-copy verwaltet die Zwischenablage; wtype sendet Shift+Insert. Das Absenden bleibt im Steuerungsskript, sodass normales Diktieren durch Halten niemals Enter sendet.

Die Hyprland-Seite liegt in ~/.config/hypr/bindings.lua. Entscheidend ist nicht der genaue Lua-Wrapper, sondern das Trennen von Drücken und Loslassen und das Erhalten der Loslass-Bindung über Submaps hinweg:

local HYPER = "SUPER + SHIFT + CTRL + ALT"
local controller = "/home/USER/.local/bin/voxtype-paradict"

hl.bind(HYPER, "W", "exec", controller .. " press")
hl.bindr(HYPER, "W", "exec", controller .. " release", {
  submap_universal = true,
})

hl.define_submap("voxtype_recording", function()
  -- Hyprland 0.56.2 silently omits symbolic RETURN in this named submap.
  hl.bind(
    "code:36",
    hl.dsp.exec_cmd(controller .. " submit-continue")
  )
end)

Unter Hyprland 0.56.2 wurde eine symbolische RETURN-Bindung innerhalb der benannten Aufnahme-Submap stillschweigend ausgelassen. hyprctl configerrors blieb leer, die Konfigurationsprüfung erkannte das also nicht. code:36 bindet die physische Haupt-Enter-Taste. Die Enter-Taste des Ziffernblocks braucht eine separate Bindung. Nach jedem Neuladen sollte man hyprctl binds prüfen und sicherstellen, dass die Bindung unter voxtype_recording vorhanden ist.

Das Steuerungsskript unterscheidet Antippen und Halten anhand monotoner Zeit, serialisiert Übergänge mit flock, wartet auf Voxtype-Zustandsänderungen und setzt Hyprland bei jedem Fehler zurück.

Fehler durch die Reihenfolge beim Loslassen

Eine Submap löst die Weiterleitung, aber nicht jeden Sonderfall mit Modifikatortasten. Ich brauchte drei zusätzliche Schutzmechanismen:

  • Universelles Loslassen: Die Aufnahme ändert die aktive Submap, bevor W losgelassen wird.
  • Verzögerte Super-Aktivierung: Das Loslassen der Hyper-Kombination darf nicht wie eine absichtliche Beendigung durch Super aussehen. Nach einem Antippen ignoriere ich Super-Loslassereignisse für 400 ms.
  • Ausgabeunterdrückung: Die Transkription kann fertig sein, während eine Modifikatortaste noch gedrückt ist. Die Unterdrückungs-Submap fängt diese Tasten während Einfügen und Absenden ab.

Die festhängende Aktivierung

Eine Reihenfolge störte die Schleife weiterhin. Wenn ich Hyper vor W losließ, betrachtete Hyprland das spätere Loslassen von W nicht mehr als Hyper+W-Ereignis. Das Steuerungsskript behielt seine Aktivierungsmarkierung, sodass Super und Enter festzuhängen schienen.

Die Lösung: Beide Loslassereignisse dürfen die Aktivierung abschließen. Wenn Super losgelassen wird, während die Hyper+W-Markierung noch existiert, übernimmt das Steuerungsskript diese Markierung und führt denselben Übergang für Antippen oder Halten aus wie beim Loslassen von W. Bei diesem Ereignis sendet es noch nichts ab. Ein späteres einzelnes Super oder Enter behält dadurch seine vorgesehene Bedeutung.

Zusammen machen diese Schutzmechanismen die Reihenfolge beim Loslassen der Modifikatortasten irrelevant. Genau diesen Teil machen die meisten Diktierkürzel falsch.

Die Wiederherstellung ist bewusst einfach:

~/.local/bin/voxtype-paradict recover
systemctl --user restart voxtype.service

Agentenanweisungen zum Kopieren

Richte Voxtype auf meinem Omarchy-System wie folgt ein:

- Nutze die installierten Omarchy-/Hyprland-Konventionen. Prüfe vor Änderungen
  das laufende System, aktuelle Bindungen, Voxtype-Version und -Konfiguration
  sowie die passende Befehlshilfe. Bearbeite niemals /usr/share/omarchy,
  sondern nur die Konfiguration des Benutzers.
- Sichere jede geänderte Datei. Erhalte unabhängige Tastenkürzel. Prüfe aktuelle
  Bindungen mit `omarchy menu keybindings --print` und entferne ausdrücklich
  widersprüchliche Hyper+W- oder Standard-Voxtype-Bindungen vor dem Ersetzen.
- Hyper bedeutet Super+Shift+Control+Alt. Binde Drücken und Loslassen von
  Hyper+W in ~/.config/hypr/bindings.lua. Ändere meine physische Hyper-/Caps-
  Lock-Umbelegung nur auf Wunsch; möglicherweise übernimmt Kanata sie bereits.
- Hyper+W mindestens eine Sekunde halten: währenddessen aufnehmen, beim
  Loslassen transkribieren und ohne Absenden einfügen.
- Hyper+W antippen: weiter aufnehmen. Enter muss in diesem Modus transkribieren,
  einfügen, einmal absenden und sofort erneut aufnehmen. Einzelnes linkes oder
  rechtes Super muss transkribieren, einfügen, absenden und stoppen. Erneutes
  Hyper+W muss transkribieren, ohne Absenden einfügen und stoppen. Escape
  bricht ab. F12 stellt den Ausgangszustand wieder her.
- Deaktiviere Voxtypes eigenes Tastenkürzel. Konfiguriere die Ausgabe über die
  Zwischenablage mit mode="paste", paste_keys="shift+insert",
  restore_clipboard=false, pre_type_delay_ms=100 und auto_submit=false.
  Prüfe, dass wl-copy und wtype vorhanden sind.
- Implementiere ein kleines Steuerungsskript unter
  ~/.local/bin/voxtype-paradict und zwei Hyprland-Submaps:
  voxtype_recording für Steuerungstasten und voxtype_suppress für sicheres
  Einfügen bei noch gehaltenen Modifikatortasten.
- Binde unter Hyprland 0.56.2 die physische Haupt-Enter-Taste in
  voxtype_recording als code:36 statt als symbolisches RETURN. Ergänze die
  Enter-Taste des Ziffernblocks nur bei Bedarf.
- Mache die Hyper+W-Loslass-Bindung universell über Submaps hinweg. Füge nach
  dem Antippen eine Aktivierungsverzögerung von 400 ms hinzu, damit das
  Loslassen der auslösenden Hyper-Kombination nicht die Super-Stoppfunktion
  auslöst. Serialisiere Übergänge mit flock, nutze monotone Zeit, warte auf
  Voxtype-/Hyprland-Zustandsänderungen und setze beides bei Fehlern zurück.
- Prüfe mit `hyprctl reload` und `hyprctl configerrors`. Prüfe danach
  `hyprctl binds` und bestätige code:36 in voxtype_recording. Starte den
  Voxtype-Benutzerdienst neu und berichte über die endgültigen Bindungen,
  Dateien, Sicherungen und den Wiederherstellungsbefehl. Teste Einfügen und
  Absenden nicht im aktiven Agententerminal, sondern in einem entbehrlichen
  Textfeld, oder überlasse mir diesen abschließenden interaktiven Test.

Die nützliche Aufgabenteilung ist einfach: Voxtype steuert Audio, Hyprland steuert Tasten und das Steuerungsskript steuert den Zustand.

Ergänze die Notizen

Kommentare werden erst geladen, wenn du sie anzeigen lässt. Der Kommentardienst nutzt Browser-Speicher für Einstellungen und Entwürfe sowie Cookies bei einer Anmeldung. Keine Werbung oder Analyse. Mit „Kommentare anzeigen“ erlaubst du diesen Speicher für die Kommentarfunktion.Datenschutzdetails.