Skip to content

Commit d5d87dd

Browse files
committed
feat: 支持 Windows 平台不抢占其他窗口焦点
1 parent 4881c81 commit d5d87dd

File tree

10 files changed

+316
-43
lines changed

10 files changed

+316
-43
lines changed

Cargo.lock

Lines changed: 95 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ tauri-plugin-eco-autostart.workspace = true
4343

4444
[target."cfg(target_os = \"macos\")".dependencies]
4545
tauri-nspanel.workspace = true
46+
rdev = { git = "https://github.com/Narsil/rdev", features = ["unstable_grab"] }
4647

4748
[features]
4849
cargo-clippy = []
Lines changed: 152 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,157 @@
1-
use tauri::{AppHandle, WebviewWindow};
1+
use rdev::{grab, Event, EventType, Key};
2+
use std::{
3+
sync::atomic::{AtomicBool, Ordering},
4+
thread::spawn,
5+
};
6+
use tauri::{AppHandle, Emitter, WebviewWindow};
7+
8+
static CTRL_PRESSED: AtomicBool = AtomicBool::new(false);
9+
static SHIFT_PRESSED: AtomicBool = AtomicBool::new(false);
10+
11+
#[derive(Clone, serde::Serialize)]
12+
#[serde(rename_all = "camelCase")]
13+
struct DispatchEvent {
14+
code: &'static str,
15+
key_code: u32,
16+
}
217

318
pub fn platform(
4-
_app_handle: &AppHandle,
5-
_main_window: WebviewWindow,
19+
app_handle: &AppHandle,
20+
main_window: WebviewWindow,
621
_preference_window: WebviewWindow,
722
) {
23+
let app_handle = app_handle.clone();
24+
25+
spawn(move || {
26+
let callback = move |event: Event| -> Option<Event> {
27+
match event.event_type {
28+
EventType::KeyPress(key) => {
29+
match key {
30+
Key::ControlLeft | Key::ControlRight => {
31+
CTRL_PRESSED.store(true, Ordering::Relaxed)
32+
}
33+
Key::ShiftLeft | Key::ShiftRight => {
34+
SHIFT_PRESSED.store(true, Ordering::Relaxed)
35+
}
36+
_ => {}
37+
}
38+
39+
if let Ok(true) = main_window.is_visible() {
40+
if handle_hotkey(&app_handle, key) {
41+
return None;
42+
}
43+
}
44+
45+
Some(event)
46+
}
47+
48+
EventType::KeyRelease(key) => {
49+
match key {
50+
Key::ControlLeft | Key::ControlRight => {
51+
CTRL_PRESSED.store(false, Ordering::Relaxed)
52+
}
53+
Key::ShiftLeft | Key::ShiftRight => {
54+
SHIFT_PRESSED.store(false, Ordering::Relaxed)
55+
}
56+
_ => {}
57+
}
58+
Some(event)
59+
}
60+
61+
_ => Some(event),
62+
}
63+
};
64+
65+
if let Err(err) = grab(callback) {
66+
eprintln!("rdev grab error: {:?}", err);
67+
}
68+
});
69+
}
70+
71+
fn handle_hotkey(app_handle: &AppHandle, key: Key) -> bool {
72+
use Key::*;
73+
74+
let ctrl_pressed = CTRL_PRESSED.load(Ordering::Relaxed);
75+
let shift_pressed = SHIFT_PRESSED.load(Ordering::Relaxed);
76+
77+
let event = match key {
78+
// 预览
79+
Space => Some(DispatchEvent {
80+
code: "Space",
81+
key_code: 32,
82+
}),
83+
// 选择上一个
84+
UpArrow => Some(DispatchEvent {
85+
code: "ArrowUp",
86+
key_code: 38,
87+
}),
88+
// 选择下一个
89+
DownArrow => Some(DispatchEvent {
90+
code: "ArrowDown",
91+
key_code: 40,
92+
}),
93+
// 粘贴
94+
Return => Some(DispatchEvent {
95+
code: "Enter",
96+
key_code: 13,
97+
}),
98+
// 选择上一个分组
99+
Tab if shift_pressed => Some(DispatchEvent {
100+
code: "Tab",
101+
key_code: 9,
102+
}),
103+
// 选择下一个分组
104+
Tab => Some(DispatchEvent {
105+
code: "Tab",
106+
key_code: 9,
107+
}),
108+
// 滚动到顶部
109+
Home => Some(DispatchEvent {
110+
code: "Home",
111+
key_code: 36,
112+
}),
113+
// 删除条目
114+
Backspace => Some(DispatchEvent {
115+
code: "Backspace",
116+
key_code: 8,
117+
}),
118+
Delete => Some(DispatchEvent {
119+
code: "Delete",
120+
key_code: 46,
121+
}),
122+
// 收藏条目
123+
KeyD if ctrl_pressed => Some(DispatchEvent {
124+
code: "KeyD",
125+
key_code: 68,
126+
}),
127+
// 搜索框聚焦
128+
KeyF if ctrl_pressed => Some(DispatchEvent {
129+
code: "KeyF",
130+
key_code: 70,
131+
}),
132+
// 固定窗口
133+
KeyP if ctrl_pressed => Some(DispatchEvent {
134+
code: "KeyP",
135+
key_code: 80,
136+
}),
137+
// 打开偏好设置
138+
Comma if ctrl_pressed => Some(DispatchEvent {
139+
code: "Comma",
140+
key_code: 188,
141+
}),
142+
// 隐藏窗口
143+
KeyW if ctrl_pressed => Some(DispatchEvent {
144+
code: "KeyW",
145+
key_code: 87,
146+
}),
147+
_ => None,
148+
};
149+
150+
if let Some(ev) = event {
151+
let _ = app_handle.emit("dispatch-event", ev);
152+
153+
return true;
154+
}
155+
156+
false
8157
}

src-tauri/src/plugins/paste/src/commands/macos.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::process::Command;
99
use std::sync::Mutex;
1010
use std::thread;
1111
use tauri::{command, AppHandle, Runtime, WebviewWindow};
12-
use tauri_plugin_eco_window::{set_macos_panel, MacOSPanelStatus, MAIN_WINDOW_TITLE};
12+
use tauri_plugin_eco_window::{set_ns_panel, NsPanelStatus, MAIN_WINDOW_TITLE};
1313

1414
static PREVIOUS_WINDOW: Mutex<Option<i32>> = Mutex::new(None);
1515

@@ -82,7 +82,7 @@ pub fn get_previous_window() -> Option<i32> {
8282
// 粘贴
8383
#[command]
8484
pub async fn paste<R: Runtime>(app_handle: AppHandle<R>, window: WebviewWindow<R>) {
85-
set_macos_panel(&app_handle, &window, MacOSPanelStatus::Resign);
85+
set_ns_panel(&app_handle, &window, NsPanelStatus::Resign);
8686

8787
let script = r#"tell application "System Events" to keystroke "v" using command down"#;
8888

src-tauri/src/plugins/window/src/commands/not_macos.rs renamed to src-tauri/src/plugins/window/src/commands/linux.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
use super::{shared_hide_window, shared_show_window};
21
use tauri::{command, AppHandle, Runtime, WebviewWindow};
32

43
// 显示窗口
54
#[command]
65
pub async fn show_window<R: Runtime>(_app_handle: AppHandle<R>, window: WebviewWindow<R>) {
7-
shared_show_window(&window);
6+
let _ = window.show();
7+
let _ = window.unminimize();
8+
let _ = window.set_focus();
89
}
910

1011
// 隐藏窗口
1112
#[command]
1213
pub async fn hide_window<R: Runtime>(_app_handle: AppHandle<R>, window: WebviewWindow<R>) {
13-
shared_hide_window(&window);
14+
let _ = window.hide();
1415
}
1516

1617
// 显示任务栏图标

0 commit comments

Comments
 (0)