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: 2 additions & 2 deletions openless-all/app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion openless-all/app/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "openless-app",
"private": true,
"version": "1.2.5",
"version": "1.2.6",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
81 changes: 79 additions & 2 deletions openless-all/app/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion openless-all/app/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "openless"
version = "1.2.5"
version = "1.2.6"
description = "OpenLess — local voice input that types where your cursor is"
authors = ["OpenLess"]
edition = "2021"
Expand Down Expand Up @@ -54,10 +54,12 @@ objc2-app-kit = "0.2"
[target.'cfg(target_os = "windows")'.dependencies]
windows = { version = "0.58", features = [
"Win32_Foundation",
"Win32_UI_Shell",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_WindowsAndMessaging",
"Win32_System_Threading",
] }
winreg = "0.52"

# 跨平台磨砂层(macOS NSVisualEffectView / Windows Mica)。
[target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies]
Expand Down
39 changes: 33 additions & 6 deletions openless-all/app/src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,19 +262,46 @@ pub fn open_system_settings(pane: String) -> Result<(), String> {
.map(|_| ())
.map_err(|e| e.to_string())
}
#[cfg(not(target_os = "macos"))]
#[cfg(target_os = "windows")]
{
use windows::core::PCWSTR;
use windows::Win32::UI::Shell::ShellExecuteW;
use windows::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL;

fn wide_null(value: &str) -> Vec<u16> {
value.encode_utf16().chain(std::iter::once(0)).collect()
}

let uri = match pane.as_str() {
"microphone" => "ms-settings:privacy-microphone",
"sound" => "ms-settings:sound",
"accessibility" => "ms-settings:easeofaccess",
_ => "ms-settings:",
};
std::process::Command::new("cmd")
.args(["/C", "start", "", uri])
.spawn()
.map(|_| ())
.map_err(|e| e.to_string())

let operation = wide_null("open");
let target = wide_null(uri);
let result = unsafe {
ShellExecuteW(
None,
PCWSTR(operation.as_ptr()),
PCWSTR(target.as_ptr()),
PCWSTR::null(),
PCWSTR::null(),
SW_SHOWNORMAL,
)
};

if result.0 as isize <= 32 {
Err(format!("ShellExecuteW failed: {}", result.0 as isize))
} else {
Ok(())
}
}
#[cfg(all(not(target_os = "macos"), not(target_os = "windows")))]
{
let _ = pane;
Err("open_system_settings is only supported on macOS and Windows".to_string())
}
}

Expand Down
43 changes: 42 additions & 1 deletion openless-all/app/src-tauri/src/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,10 @@ async fn end_session(inner: &Arc<Inner>) -> Result<(), String> {
}
};
if !proceed_to_insert {
log::info!("[coord] cancel detected before insert — discarding output (chars={})", polished.chars().count());
log::info!(
"[coord] cancel detected before insert — discarding output (chars={})",
polished.chars().count()
);
return Ok(());
}

Expand Down Expand Up @@ -916,6 +919,15 @@ fn hotkey_injection_dry_run_enabled() -> bool {
fn ensure_microphone_permission(inner: &Arc<Inner>) -> Result<(), String> {
use crate::permissions::{self, PermissionStatus};

#[cfg(target_os = "windows")]
{
let _ = inner;
if permissions::windows_microphone_access_explicitly_denied() {
return Err("需要麦克风权限,当前状态: Denied".to_string());
}
return Ok(());
}

let status = permissions::check_microphone();
if matches!(
status,
Expand Down Expand Up @@ -1144,6 +1156,35 @@ mod tests {
assert_eq!(state.phase, SessionPhase::Starting);
assert!(state.pending_stop);
}

#[tokio::test]
async fn repeated_pressed_edge_during_hold_session_does_not_restart() {
let coordinator = Coordinator::new();
coordinator
.inner
.prefs
.set(crate::types::UserPreferences {
hotkey: crate::types::HotkeyBinding {
trigger: HotkeyTrigger::RightControl,
mode: HotkeyMode::Hold,
},
..Default::default()
})
.unwrap();
coordinator.inner.state.lock().phase = SessionPhase::Listening;
coordinator
.inner
.hotkey_trigger_held
.store(true, Ordering::SeqCst);

handle_pressed_edge(&coordinator.inner).await;

assert_eq!(
coordinator.inner.state.lock().phase,
SessionPhase::Listening
);
assert!(coordinator.inner.hotkey_trigger_held.load(Ordering::SeqCst));
}
}

fn enabled_phrases(inner: &Arc<Inner>) -> Vec<String> {
Expand Down
4 changes: 3 additions & 1 deletion openless-all/app/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ pub fn run() {
// 否则两份 OpenLess(如 /Applications/ + dev build)会各自抓全局热键,
// 导致按一次键、两个进程同时跑流水线、文本被插入两遍。见 issue #50。
.plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| {
log::info!("[single-instance] another instance launched, focusing existing main window");
log::info!(
"[single-instance] another instance launched, focusing existing main window"
);
show_main_window(app);
}))
.plugin(tauri_plugin_shell::init())
Expand Down
Loading
Loading