Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/features/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,10 @@ General // settings
│ ├── Menu lists real inputs only // never Hex Microphone
│ └── Open menu covers the controls beneath it; click elsewhere dismisses
├── Advanced ▸ (Dictation header) -> rows at the end of the Dictation card
│ ├── Open while Release when idle or Double-tap only (Hold) is on
│ ├── Open while Release when idle, Double-tap only (Hold), or sharing is on
│ └── Collapse -> drops a pending release confirmation
├── Share dictation shortcut with other apps (Advanced, Windows, off)
│ └── On -> the hook passes the shortcut's key-down/up on instead of consuming it
├── Microphone mode (Advanced)
│ ├── Keep ready (fast) -> Open while idle; pre-roll available
│ └── Release when idle -> Open on press; no pre-roll; startup delay
Expand Down
5 changes: 4 additions & 1 deletion docs/windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ speaking and release Space to transcribe and paste. In **Toggle** mode, press
`Ctrl+Space` to start and again to finish. Only Escape cancels; holding a
modifier on its own does nothing. Hex consumes the chord while it matches, so
applications and input methods no longer see `Ctrl+Space`; rebind it in Settings
if you rely on that chord elsewhere. In Hold mode, tap the shortcut twice within
if you rely on that chord elsewhere. To let another app use the same key, such as
a Discord push-to-talk key, turn on **Share dictation shortcut with other apps**
under Advanced: Hex still reacts to it but passes its key-down and key-up on,
which can also trigger that binding in other apps. In Hold mode, tap the shortcut twice within
300 ms to lock recording, then press it again to finish. Paste Last defaults to
`Ctrl+Alt+V`. Settings changes apply live or through an automatic listener
restart.
Expand Down
4 changes: 4 additions & 0 deletions src/app_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,9 @@ pub struct AppSettings {
pub enable_on_launch: bool,
/// Paste with Ctrl-Shift-V for terminals (Linux).
pub paste_with_shift: bool,
/// Let other apps see the dictation shortcut's key presses too
/// (Windows), so a push-to-talk key can drive both.
pub share_dictation_shortcut: bool,
/// The interface language code; `None` follows the system language.
pub ui_language: Option<String>,
pub indicator_position: IndicatorPosition,
Expand Down Expand Up @@ -1400,6 +1403,7 @@ impl Default for AppSettings {
experimental: ExperimentalSettings::default(),
enable_on_launch: true,
paste_with_shift: false,
share_dictation_shortcut: false,
ui_language: None,
indicator_position: IndicatorPosition::default(),
updates: UpdateSettings::default(),
Expand Down
5 changes: 5 additions & 0 deletions src/control/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ const KEYS: &[Key] = &[
Kind::Bool,
"Paste with Ctrl-Shift-V for terminals (Linux)",
),
key(
"share_dictation_shortcut",
Kind::Bool,
"Let other apps see the dictation shortcut too (Windows)",
),
optional(
"ui_language",
Kind::Choice(&["en", "pl", "zh", "ja", "de", "es", "uk"]),
Expand Down
2 changes: 2 additions & 0 deletions src/desktop_i18n.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@ const TRANSLATIONS: &[(&str, [&str; 6])] = &[
("Opens only while holding the shortcut. Disables pre-roll and commands.", ["Otwiera się tylko podczas przytrzymania skrótu. Wyłącza wstępne nagrywanie i polecenia.", "仅在按住快捷键时打开。会停用预录音和命令。", "ショートカットを押している間だけ開きます。プリロールとコマンドは無効になります。", "Öffnet sich nur, solange das Kürzel gehalten wird. Deaktiviert Vorlauf und Befehle.", "Solo se abre mientras mantienes el atajo. Desactiva la pregrabación y los comandos.", "Вмикає мікрофон лише під час утримання комбінації клавіш. Вимикає попереднє захоплення аудіо й команди."]),
("Opens the microphone on shortcut press without pre-roll and turns Commands off.", ["Otwiera mikrofon po naciśnięciu skrótu, bez wstępnego nagrywania, i wyłącza polecenia.", "按下快捷键时打开麦克风,不预录音,并关闭命令。", "ショートカットを押したときにプリロールなしでマイクを開き、コマンドをオフにします。", "Öffnet das Mikrofon beim Drücken des Kürzels ohne Vorlauf und schaltet Befehle aus.", "Abre el micrófono al pulsar el atajo, sin pregrabación, y desactiva los comandos.", "Вмикає мікрофон після натискання комбінації клавіш без попереднього захоплення аудіо та вимикає команди."]),
("Opens the microphone on shortcut press without pre-roll. Commands remain off.", ["Otwiera mikrofon po naciśnięciu skrótu, bez wstępnego nagrywania. Polecenia pozostają wyłączone.", "按下快捷键时打开麦克风,不预录音。命令保持关闭。", "ショートカットを押したときにプリロールなしでマイクを開きます。コマンドはオフのままです。", "Öffnet das Mikrofon beim Drücken des Kürzels ohne Vorlauf. Befehle bleiben aus.", "Abre el micrófono al pulsar el atajo, sin pregrabación. Los comandos siguen desactivados.", "Вмикає мікрофон після натискання комбінації клавіш без попереднього захоплення аудіо. Команди залишаються вимкненими."]),
("Share dictation shortcut with other apps", ["Udostępniaj skrót dyktowania innym aplikacjom", "将听写快捷键共享给其他应用", "ディクテーションのショートカットを他のアプリと共有", "Diktierkürzel für andere Apps freigeben", "Compartir el atajo de dictado con otras aplicaciones", "Ділитися сполученням клавіш диктування з іншими програмами"]),
("Lets apps such as Discord detect the same key", ["Umożliwia aplikacjom takim jak Discord wykrywanie tego samego klawisza", "允许 Discord 等应用检测同一个按键", "Discord などのアプリが同じキーを検出できるようにします", "Ermöglicht Apps wie Discord, dieselbe Taste zu erkennen", "Permite que aplicaciones como Discord detecten la misma tecla", "Дозволяє програмам на кшталт Discord бачити ту саму клавішу"]),
("Paste with Ctrl+Shift+V so terminals accept it", ["Wklejaj przez Ctrl+Shift+V, aby terminale to przyjmowały", "使用 Ctrl+Shift+V 粘贴,以便终端接受", "端末で受け付けられるよう Ctrl+Shift+V で貼り付け", "Mit Strg+Umschalt+V einfügen, damit Terminals es annehmen", "Pegar con Ctrl+Mayús+V para que los terminales lo acepten", "Вставляти за допомогою Ctrl+Shift+V, щоб термінали приймали текст"]),
("Permissions needed", ["Wymagane uprawnienia", "需要权限", "権限が必要です", "Berechtigungen erforderlich", "Se necesitan permisos", "Потрібні дозволи"]),
("Preparing voice commands", ["Przygotowywanie poleceń głosowych", "正在准备语音命令", "音声コマンドを準備中", "Sprachbefehle werden vorbereitet", "Preparando los comandos de voz", "Підготовка голосових команд"]),
Expand Down
5 changes: 5 additions & 0 deletions src/rune_ui/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ pub(super) struct Capabilities {
pub(super) listener_control: bool,
/// Paste with Ctrl-Shift-V for terminals.
pub(super) terminal_paste: bool,
/// The dictation shortcut can pass through to other apps (Windows).
pub(super) share_shortcut: bool,
/// The experimental Hex Microphone virtual driver (macOS).
pub(super) hex_microphone: bool,
/// The window sees dictation events, so the tour can end with a
Expand Down Expand Up @@ -73,6 +75,7 @@ impl Capabilities {
dock_icon: false,
listener_control: true,
terminal_paste: true,
share_shortcut: false,
hex_microphone: false,
practice_dictation: false,
fun: false,
Expand All @@ -91,6 +94,7 @@ impl Capabilities {
dock_icon: true,
listener_control: false,
terminal_paste: false,
share_shortcut: false,
hex_microphone: true,
practice_dictation: true,
fun: true,
Expand All @@ -109,6 +113,7 @@ impl Capabilities {
dock_icon: false,
listener_control: true,
terminal_paste: false,
share_shortcut: true,
hex_microphone: false,
practice_dictation: false,
fun: false,
Expand Down
18 changes: 18 additions & 0 deletions src/rune_ui/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1495,6 +1495,7 @@ fn advanced_in_use(settings: &AppSettings) -> bool {
settings.release_microphone_while_idle
|| (double_tap_only_applies(settings) && settings.double_tap_only)
|| settings.updates.channel.is_some()
|| settings.share_dictation_shortcut
}

fn double_tap_only_applies(settings: &AppSettings) -> bool {
Expand Down Expand Up @@ -1612,6 +1613,23 @@ fn advanced_rows(ui: &Ui, p: Paint) -> Vec<CardRow> {
}),
),
];
if ui.platform.caps.share_shortcut {
rows.push(
toggle_row(
p,
"share-dictation-shortcut",
tr("Share dictation shortcut with other apps"),
tr("Lets apps such as Discord detect the same key"),
settings.share_dictation_shortcut,
|ui: &mut Ui| {
ui.advanced = Some(true);
let enabled = !ui.settings.share_dictation_shortcut;
ui.update(|settings| settings.share_dictation_shortcut = enabled);
},
)
.into(),
);
}
rows.extend(update_channel_row(ui, p).map(CardRow::from));
rows
}
Expand Down
7 changes: 7 additions & 0 deletions src/windows_dictation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub struct WindowsDictationConfig {
pub double_tap_lock: bool,
pub double_tap_only: bool,
pub shortcut_mode: crate::dictation::ShortcutMode,
pub share_dictation_shortcut: bool,
pub while_dictating: crate::app_settings::RecordingAudioBehavior,
pub release_microphone_while_idle: bool,
pub feedback_volume: u8,
Expand Down Expand Up @@ -92,6 +93,7 @@ impl WindowsDictationConfig {
double_tap_lock: settings.double_tap_lock,
double_tap_only: settings.double_tap_only,
shortcut_mode: settings.shortcut_mode,
share_dictation_shortcut: settings.share_dictation_shortcut,
while_dictating: settings.recording_audio_behavior,
release_microphone_while_idle: settings.release_microphone_while_idle,
feedback_volume: if settings.sound_effects {
Expand Down Expand Up @@ -145,6 +147,7 @@ pub fn run(
double_tap_lock,
double_tap_only,
shortcut_mode,
share_dictation_shortcut,
while_dictating,
release_microphone_while_idle,
feedback_volume,
Expand Down Expand Up @@ -208,6 +211,7 @@ pub fn run(
double_tap_lock,
double_tap_only,
shortcut_mode,
share_dictation_shortcut,
};
let mut hotkey = shortcuts.start()?;
let mut while_dictating = while_dictating;
Expand Down Expand Up @@ -286,6 +290,7 @@ pub fn run(
double_tap_lock: next_config.double_tap_lock,
double_tap_only: next_config.double_tap_only,
shortcut_mode: next_config.shortcut_mode,
share_dictation_shortcut: next_config.share_dictation_shortcut,
};
if next_shortcuts != shortcuts {
// The old hook goes first; one keyboard hook runs at a time.
Expand Down Expand Up @@ -872,6 +877,7 @@ struct Shortcuts {
double_tap_lock: bool,
double_tap_only: bool,
shortcut_mode: crate::dictation::ShortcutMode,
share_dictation_shortcut: bool,
}

impl Shortcuts {
Expand All @@ -885,6 +891,7 @@ impl Shortcuts {
self.double_tap_lock,
self.double_tap_lock && self.double_tap_only,
self.shortcut_mode,
self.share_dictation_shortcut,
)
}
}
Expand Down
10 changes: 7 additions & 3 deletions src/windows_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ struct CallbackState {
escape_down: bool,
double_tap_enabled: bool,
double_tap_only: bool,
/// Pass the dictation key on to other apps instead of consuming it.
share_trigger: bool,
capture: CaptureState,
dirty: bool,
}
Expand Down Expand Up @@ -385,6 +387,7 @@ impl WindowsHotkeyMonitor {
double_tap_enabled: bool,
double_tap_only: bool,
shortcut_mode: ShortcutMode,
share_trigger: bool,
) -> Result<Self> {
binding.validate()?;
let trigger_vk = binding.key.as_deref().map(virtual_key).transpose()?;
Expand Down Expand Up @@ -412,6 +415,7 @@ impl WindowsHotkeyMonitor {
escape_down: false,
double_tap_enabled,
double_tap_only,
share_trigger,
capture: CaptureState {
toggle: shortcut_mode == ShortcutMode::Toggle,
..CaptureState::default()
Expand Down Expand Up @@ -601,13 +605,13 @@ unsafe extern "system" fn keyboard_hook(code: i32, wparam: WPARAM, lparam: LPARA
} else if state.trigger_vk == Some(event.vkCode) {
if is_down {
if state.trigger_down {
suppressed = true;
suppressed = !state.share_trigger;
} else if !state.dirty
&& !state.voice_capture.active
&& state.modifiers.matches(&state.binding)
{
state.trigger_down = true;
suppressed = true;
suppressed = !state.share_trigger;
let was_locked = state.capture.locked;
if let Some(action) = state.capture.press(
state.double_tap_enabled,
Expand All @@ -622,7 +626,7 @@ unsafe extern "system" fn keyboard_hook(code: i32, wparam: WPARAM, lparam: LPARA
}
} else if state.trigger_down {
state.trigger_down = false;
suppressed = true;
suppressed = !state.share_trigger;
if let Some(action) =
state.capture.release(state.double_tap_enabled, event.time)
{
Expand Down