feat(热键工具): 1. 新增热键查询工具 2. 支持查询热键占用情况 3. 提供自动定位占用者和监控模式 4. 添加常见热键程序列表
This commit is contained in:
1 parent
55a308a927
commit
2f97391743
2 files changed
+508
No files matched your search
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "hotkey"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
winreg = "0.52"
|
||||
windows = { version = "0.56", features = ["Win32_Foundation", "Win32_UI_Shell", "Win32_System_Registry", "Win32_System_SystemServices", "Win32_UI_Input_KeyboardAndMouse", "Win32_System_Diagnostics_ToolHelp", "Win32_System_Threading", "Win32_UI_WindowsAndMessaging"] }
|
||||
@@ -0,0 +1,499 @@
|
||||
use clap::Parser;
|
||||
use std::collections::HashSet;
|
||||
use std::process::Command;
|
||||
use windows::Win32::Foundation::{BOOL, HWND, LPARAM, TRUE};
|
||||
use windows::Win32::System::Diagnostics::ToolHelp::{CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS};
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::{MOD_ALT, MOD_CONTROL, MOD_SHIFT, MOD_WIN, RegisterHotKey, UnregisterHotKey};
|
||||
use windows::Win32::UI::WindowsAndMessaging::{EnumWindows, GetWindowThreadProcessId, IsWindowVisible};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "hotkey")]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(
|
||||
about = "⌨️ 热键查询工具 - 查看当前用户下的热键配置",
|
||||
long_about = "⌨️ 热键查询工具\n\n查看当前用户下注册的热键配置,以及查询特定热键被哪个程序占用。\n\n示例:\n hotkey - 列出所有常见热键的占用情况\n hotkey alt+q - 查询 Alt+Q 被哪个程序占用\n hotkey alt+q --find - 自动逐个关闭候选程序,精确定位占用者"
|
||||
)]
|
||||
struct Args {
|
||||
/// 查询特定热键,格式如: alt+q, ctrl+c, win+e
|
||||
#[arg(value_name = "HOTKEY")]
|
||||
hotkey: Option<String>,
|
||||
|
||||
/// 自动逐个关闭候选程序来精确定位占用者
|
||||
#[arg(short, long)]
|
||||
find: bool,
|
||||
|
||||
/// 持续监控热键状态,直到热键释放
|
||||
#[arg(short, long)]
|
||||
watch: bool,
|
||||
}
|
||||
|
||||
// 常见注册全局热键的程序(按可能性排序)
|
||||
const KNOWN_HOTKEY_APPS: &[&str] = &[
|
||||
// 聊天软件
|
||||
"Weixin.exe", "WeChatAppEx.exe", "QQ.exe", "TIM.exe", "DingTalk.exe", "AliWorkbench.exe",
|
||||
// 快捷键工具
|
||||
"AutoHotkey.exe", "AutoHotkey64.exe", "AutoHotkeyA32.exe", "AutoHotkeyU32.exe", "AutoHotkeyU64.exe",
|
||||
"PowerToys.exe", "PowerToys.QuickAccess.exe", "PowerToys.KeyboardManagerEngine.exe",
|
||||
"Listary.exe", "Wox.exe", "uelauncher.exe",
|
||||
// 截图/录屏
|
||||
"Snipaste.exe", "ShareX.exe", "obs64.exe", "DingTalkDingCapture.exe", "SunloginClient.exe",
|
||||
// 输入法
|
||||
"SogouCloud.exe", "ctfmon.exe", "ChsIME.exe", "TextInputHost.exe",
|
||||
// 翻译
|
||||
"Doubao.exe", "YoudaoDict.exe", "Lingoes.exe",
|
||||
// 系统工具
|
||||
"Nahimic3.exe", "RTSS.exe", "LogiBolt.exe", "GamingServices.exe",
|
||||
// 远程控制
|
||||
"ToDesk.exe", "rustdesk.exe", "AnyDesk.exe",
|
||||
// 其他
|
||||
"GestureSign.exe", "StrokesPlus.xml", "MultiCommander.exe",
|
||||
];
|
||||
|
||||
fn parse_hotkey(input: &str) -> Option<(u32, u32)> {
|
||||
let parts: Vec<&str> = input.split('+').collect();
|
||||
if parts.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut modifiers = 0u32;
|
||||
let mut vk_code = 0u32;
|
||||
|
||||
for part in parts {
|
||||
let part = part.trim().to_lowercase();
|
||||
match part.as_str() {
|
||||
"alt" => modifiers |= MOD_ALT.0,
|
||||
"ctrl" | "control" => modifiers |= MOD_CONTROL.0,
|
||||
"shift" => modifiers |= MOD_SHIFT.0,
|
||||
"win" | "meta" | "super" => modifiers |= MOD_WIN.0,
|
||||
key => {
|
||||
if key.len() == 1 {
|
||||
let c = key.chars().next().unwrap();
|
||||
vk_code = if c.is_ascii_alphabetic() {
|
||||
c.to_ascii_uppercase() as u32
|
||||
} else if c.is_ascii_digit() {
|
||||
c as u32
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
} else {
|
||||
vk_code = match &*key {
|
||||
"f1" => 0x70, "f2" => 0x71, "f3" => 0x72, "f4" => 0x73,
|
||||
"f5" => 0x74, "f6" => 0x75, "f7" => 0x76, "f8" => 0x77,
|
||||
"f9" => 0x78, "f10" => 0x79, "f11" => 0x7A, "f12" => 0x7B,
|
||||
"space" => 0x20, "enter" => 0x0D, "tab" => 0x09,
|
||||
"backspace" => 0x08, "delete" => 0x2E, "insert" => 0x2D,
|
||||
"home" => 0x24, "end" => 0x23, "pageup" => 0x21, "pagedown" => 0x22,
|
||||
"left" => 0x25, "right" => 0x27, "up" => 0x26, "down" => 0x28,
|
||||
_ => return None,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if vk_code == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((modifiers, vk_code))
|
||||
}
|
||||
|
||||
fn check_hotkey_occupied(modifiers: u32, vk_code: u32) -> bool {
|
||||
unsafe {
|
||||
let result = RegisterHotKey(
|
||||
HWND(0),
|
||||
1,
|
||||
windows::Win32::UI::Input::KeyboardAndMouse::HOT_KEY_MODIFIERS(modifiers),
|
||||
vk_code,
|
||||
);
|
||||
if result.is_err() {
|
||||
true
|
||||
} else {
|
||||
let _ = UnregisterHotKey(HWND(0), 1);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_hotkey_string(modifiers: u32, vk_code: u32) -> String {
|
||||
let mut parts = Vec::new();
|
||||
if (modifiers & MOD_ALT.0) != 0 { parts.push(String::from("Alt")); }
|
||||
if (modifiers & MOD_CONTROL.0) != 0 { parts.push(String::from("Ctrl")); }
|
||||
if (modifiers & MOD_SHIFT.0) != 0 { parts.push(String::from("Shift")); }
|
||||
if (modifiers & MOD_WIN.0) != 0 { parts.push(String::from("Win")); }
|
||||
|
||||
let key = if vk_code >= 0x41 && vk_code <= 0x5A {
|
||||
(vk_code as u8 as char).to_string()
|
||||
} else if vk_code >= 0x30 && vk_code <= 0x39 {
|
||||
(vk_code as u8 as char).to_string()
|
||||
} else if vk_code >= 0x70 && vk_code <= 0x7B {
|
||||
format!("F{}", vk_code - 0x6F)
|
||||
} else {
|
||||
match vk_code {
|
||||
0x20 => "Space", 0x0D => "Enter", 0x09 => "Tab", 0x08 => "Backspace",
|
||||
0x2E => "Delete", 0x2D => "Insert", 0x24 => "Home", 0x23 => "End",
|
||||
0x21 => "PageUp", 0x22 => "PageDown", 0x25 => "Left", 0x27 => "Right",
|
||||
0x26 => "Up", 0x28 => "Down", _ => "",
|
||||
}.to_string()
|
||||
};
|
||||
|
||||
parts.push(key);
|
||||
parts.join("+")
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ProcessEntry {
|
||||
pid: u32,
|
||||
name: String,
|
||||
}
|
||||
|
||||
fn get_visible_window_processes() -> Vec<ProcessEntry> {
|
||||
let mut processes = Vec::new();
|
||||
let mut seen_pids: HashSet<u32> = HashSet::new();
|
||||
|
||||
unsafe {
|
||||
let data = (&mut processes, &mut seen_pids);
|
||||
let data_ptr = &data as *const _ as *mut ();
|
||||
let _ = EnumWindows(Some(enum_windows_callback), LPARAM(data_ptr as isize));
|
||||
}
|
||||
|
||||
processes.sort_by(|a: &ProcessEntry, b: &ProcessEntry| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
|
||||
processes.dedup_by(|a, b| a.name == b.name);
|
||||
processes
|
||||
}
|
||||
|
||||
unsafe extern "system" fn enum_windows_callback(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
unsafe {
|
||||
if !IsWindowVisible(hwnd).as_bool() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
let data = &mut *(lparam.0 as *mut (&mut Vec<ProcessEntry>, &mut HashSet<u32>));
|
||||
let (processes, seen_pids) = data;
|
||||
|
||||
let mut pid = 0u32;
|
||||
GetWindowThreadProcessId(hwnd, Some(&mut pid));
|
||||
|
||||
if seen_pids.contains(&pid) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// 获取进程名
|
||||
let snapshot = match CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) {
|
||||
Ok(h) => h,
|
||||
Err(_) => return TRUE,
|
||||
};
|
||||
|
||||
let mut pe32 = PROCESSENTRY32 {
|
||||
dwSize: std::mem::size_of::<PROCESSENTRY32>() as u32,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if Process32First(snapshot, &mut pe32).is_ok() {
|
||||
loop {
|
||||
if pe32.th32ProcessID == pid {
|
||||
let len = pe32.szExeFile.iter().position(|&c| c == 0).unwrap_or(pe32.szExeFile.len());
|
||||
let name = String::from_utf8_lossy(std::slice::from_raw_parts(
|
||||
pe32.szExeFile.as_ptr() as *const u8,
|
||||
len,
|
||||
)).to_string();
|
||||
if !name.is_empty() {
|
||||
processes.push(ProcessEntry { pid, name });
|
||||
}
|
||||
break;
|
||||
}
|
||||
if Process32Next(snapshot, &mut pe32).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
seen_pids.insert(pid);
|
||||
}
|
||||
TRUE
|
||||
}
|
||||
|
||||
fn is_known_hotkey_app(name: &str) -> bool {
|
||||
KNOWN_HOTKEY_APPS.iter().any(|&app| name.eq_ignore_ascii_case(app))
|
||||
}
|
||||
|
||||
fn kill_process(pid: u32) -> bool {
|
||||
Command::new("taskkill")
|
||||
.args(["/PID", &pid.to_string(), "/F"])
|
||||
.output()
|
||||
.map(|o| o.status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn start_process(name: &str) -> bool {
|
||||
Command::new("cmd")
|
||||
.args(["/C", "start", "", name])
|
||||
.output()
|
||||
.map(|o| o.status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn find_hotkey_owner(modifiers: u32, vk_code: u32) {
|
||||
let hotkey_display = get_hotkey_string(modifiers, vk_code);
|
||||
|
||||
if !check_hotkey_occupied(modifiers, vk_code) {
|
||||
println!("✅ 热键 {} 未被占用", hotkey_display);
|
||||
return;
|
||||
}
|
||||
|
||||
println!("🔍 正在查找占用 {} 的程序...\n", hotkey_display);
|
||||
println!("策略: 逐个关闭候选程序,每次关闭后检查热键是否释放");
|
||||
println!(" 如果释放,则该程序就是占用者,会自动重启它\n");
|
||||
|
||||
// 构建候选列表:已知热键程序优先
|
||||
let all_procs = get_visible_window_processes();
|
||||
let mut candidates: Vec<ProcessEntry> = Vec::new();
|
||||
let mut others: Vec<ProcessEntry> = Vec::new();
|
||||
|
||||
for proc in all_procs {
|
||||
// 跳过自身和关键系统进程
|
||||
if proc.name.eq_ignore_ascii_case("hotkey.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("explorer.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("svchost.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("csrss.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("lsass.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("services.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("smss.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("wininit.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("winlogon.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("dwm.exe")
|
||||
|| proc.name.eq_ignore_ascii_case("System")
|
||||
|| proc.name.eq_ignore_ascii_case("Registry")
|
||||
|| proc.name.eq_ignore_ascii_case("Memory Compression")
|
||||
|| proc.name.eq_ignore_ascii_case("Secure System")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if is_known_hotkey_app(&proc.name) {
|
||||
candidates.push(proc);
|
||||
} else {
|
||||
others.push(proc);
|
||||
}
|
||||
}
|
||||
|
||||
// 已知热键程序排在前面
|
||||
candidates.extend(others);
|
||||
|
||||
if candidates.is_empty() {
|
||||
println!("❌ 没有找到可测试的候选程序");
|
||||
return;
|
||||
}
|
||||
|
||||
println!("📋 候选程序列表(已知热键程序优先):");
|
||||
for (i, proc) in candidates.iter().enumerate() {
|
||||
let tag = if is_known_hotkey_app(&proc.name) { " [已知热键程序]" } else { "" };
|
||||
println!(" {}. {} (PID: {}){}", i + 1, proc.name, proc.pid, tag);
|
||||
}
|
||||
println!();
|
||||
|
||||
let mut closed_apps: Vec<(u32, String)> = Vec::new();
|
||||
let mut found = false;
|
||||
|
||||
for (i, proc) in candidates.iter().enumerate() {
|
||||
let tag = if is_known_hotkey_app(&proc.name) { " [已知热键程序]" } else { "" };
|
||||
println!("[{}/{}] 正在关闭 {} (PID: {}){}...", i + 1, candidates.len(), proc.name, proc.pid, tag);
|
||||
|
||||
if !kill_process(proc.pid) {
|
||||
println!(" ⚠️ 无法关闭,跳过");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 等待进程完全退出
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
|
||||
if !check_hotkey_occupied(modifiers, vk_code) {
|
||||
println!("\n🎯 找到了!占用 {} 的程序是: {} (PID: {})", hotkey_display, proc.name, proc.pid);
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
println!(" ❌ 关闭后热键仍被占用,继续...");
|
||||
closed_apps.push((proc.pid, proc.name.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
// 重启已关闭的程序
|
||||
if !closed_apps.is_empty() {
|
||||
println!("\n♻️ 正在重启之前关闭的程序...");
|
||||
for (_, name) in &closed_apps {
|
||||
if start_process(name) {
|
||||
println!(" ✅ 已重启 {}", name);
|
||||
} else {
|
||||
println!(" ⚠️ 无法重启 {}", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
println!("\n❌ 未能找到占用者。可能被系统服务或驱动级程序占用。");
|
||||
}
|
||||
}
|
||||
|
||||
fn watch_hotkey(modifiers: u32, vk_code: u32) {
|
||||
let hotkey_display = get_hotkey_string(modifiers, vk_code);
|
||||
|
||||
if !check_hotkey_occupied(modifiers, vk_code) {
|
||||
println!("✅ 热键 {} 未被占用", hotkey_display);
|
||||
return;
|
||||
}
|
||||
|
||||
println!("👁️ 正在监控热键 {} 的状态...", hotkey_display);
|
||||
println!(" 关闭占用的程序后,将自动检测到释放\n");
|
||||
|
||||
let mut last_procs = get_visible_window_processes();
|
||||
loop {
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||
|
||||
if !check_hotkey_occupied(modifiers, vk_code) {
|
||||
// 检查哪些进程消失了
|
||||
let current_procs = get_visible_window_processes();
|
||||
let current_names: HashSet<String> = current_procs.iter().map(|p| p.name.clone()).collect();
|
||||
let disappeared: Vec<&ProcessEntry> = last_procs.iter()
|
||||
.filter(|p| !current_names.contains(&p.name))
|
||||
.collect();
|
||||
|
||||
println!("\n🎯 热键 {} 已释放!", hotkey_display);
|
||||
if !disappeared.is_empty() {
|
||||
println!("📋 最近关闭的程序(可能的占用者):");
|
||||
for proc in disappeared {
|
||||
println!(" - {} (PID: {})", proc.name, proc.pid);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新进程列表
|
||||
last_procs = get_visible_window_processes();
|
||||
print!(".");
|
||||
std::io::Write::flush(&mut std::io::stdout()).ok();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_common_hotkeys() -> Vec<(String, bool)> {
|
||||
let common_hotkeys = [
|
||||
(MOD_ALT.0 | MOD_CONTROL.0, 0x44, "Alt+Ctrl+D"),
|
||||
(MOD_ALT.0, 0x51, "Alt+Q"),
|
||||
(MOD_ALT.0, 0x46, "Alt+F"),
|
||||
(MOD_ALT.0, 0x43, "Alt+C"),
|
||||
(MOD_CONTROL.0, 0x43, "Ctrl+C"),
|
||||
(MOD_CONTROL.0, 0x56, "Ctrl+V"),
|
||||
(MOD_CONTROL.0, 0x58, "Ctrl+X"),
|
||||
(MOD_CONTROL.0, 0x46, "Ctrl+F"),
|
||||
(MOD_CONTROL.0, 0x53, "Ctrl+S"),
|
||||
(MOD_CONTROL.0, 0x4E, "Ctrl+N"),
|
||||
(MOD_CONTROL.0, 0x57, "Ctrl+W"),
|
||||
(MOD_CONTROL.0, 0x54, "Ctrl+T"),
|
||||
(MOD_WIN.0, 0x45, "Win+E"),
|
||||
(MOD_WIN.0, 0x44, "Win+D"),
|
||||
(MOD_WIN.0, 0x52, "Win+R"),
|
||||
(MOD_WIN.0, 0x4C, "Win+L"),
|
||||
(MOD_WIN.0, 0x54, "Win+T"),
|
||||
(MOD_WIN.0, 0x41, "Win+A"),
|
||||
(MOD_WIN.0, 0x53, "Win+S"),
|
||||
(MOD_ALT.0, 0x42, "Alt+B"),
|
||||
(MOD_ALT.0, 0x54, "Alt+T"),
|
||||
(MOD_ALT.0, 0x56, "Alt+V"),
|
||||
(MOD_ALT.0, 0x57, "Alt+W"),
|
||||
(MOD_CONTROL.0 | MOD_SHIFT.0, 0x43, "Ctrl+Shift+C"),
|
||||
(MOD_CONTROL.0 | MOD_SHIFT.0, 0x56, "Ctrl+Shift+V"),
|
||||
(MOD_CONTROL.0, 0x41, "Ctrl+A"),
|
||||
(MOD_CONTROL.0, 0x4B, "Ctrl+K"),
|
||||
(MOD_ALT.0, 0x53, "Alt+S"),
|
||||
(MOD_ALT.0, 0x4E, "Alt+N"),
|
||||
(MOD_ALT.0, 0x50, "Alt+P"),
|
||||
];
|
||||
|
||||
let mut results: Vec<(String, bool)> = common_hotkeys.iter().map(|&(m, v, name)| {
|
||||
(name.to_string(), check_hotkey_occupied(m, v))
|
||||
}).collect();
|
||||
|
||||
results.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
results
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = Args::parse();
|
||||
|
||||
if let Some(hotkey_str) = &args.hotkey {
|
||||
match parse_hotkey(hotkey_str) {
|
||||
Some((modifiers, vk_code)) => {
|
||||
let hotkey_display = get_hotkey_string(modifiers, vk_code);
|
||||
|
||||
if args.find {
|
||||
find_hotkey_owner(modifiers, vk_code);
|
||||
} else if args.watch {
|
||||
watch_hotkey(modifiers, vk_code);
|
||||
} else {
|
||||
let occupied = check_hotkey_occupied(modifiers, vk_code);
|
||||
|
||||
if occupied {
|
||||
println!("❌ 热键 {} 已被占用", hotkey_display);
|
||||
|
||||
let procs = get_visible_window_processes();
|
||||
|
||||
// 优先显示已知热键程序
|
||||
let mut known = Vec::new();
|
||||
let mut other = Vec::new();
|
||||
for proc in &procs {
|
||||
if is_known_hotkey_app(&proc.name) {
|
||||
known.push(proc);
|
||||
} else {
|
||||
other.push(proc);
|
||||
}
|
||||
}
|
||||
|
||||
if !known.is_empty() {
|
||||
println!("\n🔴 高度可疑(已知会注册热键的程序):");
|
||||
for (i, proc) in known.iter().enumerate() {
|
||||
println!(" {}. {} (PID: {})", i + 1, proc.name, proc.pid);
|
||||
}
|
||||
}
|
||||
|
||||
if !other.is_empty() {
|
||||
println!("\n🟡 其他运行中的程序:");
|
||||
for (i, proc) in other.iter().enumerate() {
|
||||
println!(" {}. {} (PID: {})", i + 1, proc.name, proc.pid);
|
||||
}
|
||||
}
|
||||
|
||||
println!("\n💡 使用以下命令精确定位:");
|
||||
println!(" hotkey {} --find 自动逐个关闭程序定位占用者(会自动重启)", hotkey_str);
|
||||
println!(" hotkey {} --watch 持续监控,手动关闭程序后自动检测", hotkey_str);
|
||||
} else {
|
||||
println!("✅ 热键 {} 未被占用,可以使用", hotkey_display);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
eprintln!("❌ 无效的热键格式: {}", hotkey_str);
|
||||
eprintln!("💡 正确格式示例: alt+q, ctrl+c, win+e, alt+ctrl+delete");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("⌨️ 热键查询工具\n");
|
||||
println!("正在检测当前系统中的热键占用情况...\n");
|
||||
|
||||
let hotkeys = check_common_hotkeys();
|
||||
|
||||
println!("{:<30} {:<12}", "热键", "状态");
|
||||
println!("{}", "-".repeat(45));
|
||||
|
||||
for (key, occupied) in hotkeys {
|
||||
let status = if occupied { "🔴 已占用" } else { "🟢 可用" };
|
||||
println!("{:<30} {:<12}", key, status);
|
||||
}
|
||||
|
||||
println!("\n💡 提示:");
|
||||
println!(" hotkey <热键> 查询特定热键占用情况");
|
||||
println!(" hotkey <热键> --find 自动定位占用者(逐个关闭后检测,会自动重启)");
|
||||
println!(" hotkey <热键> --watch 监控模式(手动关闭程序后自动检测释放)");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user