如何通过Tauri与纯JS实现虚拟键盘字符插入至当前聚焦窗口?
如何通过Tauri与纯JS实现虚拟键盘字符插入至当前聚焦窗口?
嘿,我刚好折腾过类似的虚拟键盘需求,你的问题核心其实是点击虚拟键盘按键时,Tauri窗口会抢走焦点,导致原来的目标窗口(比如记事本、浏览器)失去焦点,自然收不到输入。别担心,分两种场景给你靠谱的解决方案:
一、全局虚拟键盘(给所有系统窗口用)
这种情况必须靠Rust的系统级输入模拟来实现,因为JS只能操作自己的窗口,没法跨窗口发送输入。我们可以用enigo这个跨平台的键盘模拟库,配合Tauri的自定义命令来搞定:
步骤1:Rust端配置
首先在src-tauri/Cargo.toml里添加依赖:
[dependencies] enigo = "0.2.0" # 用最新稳定版即可 tauri = { version = "1.5", features = ["api-all"] }
然后在src-tauri/src/main.rs里注册一个自定义命令,用来接收前端传过来的字符并模拟输入:
use enigo::{Enigo, KeyboardControllable, Key}; use tauri::command; // 自定义命令:接收要发送的字符,模拟系统键盘输入 #[command] fn send_input(char: &str) { let mut enigo = Enigo::new(); // 处理特殊按键(比如回车、退格) match char { "Enter" => enigo.key_click(Key::Return), "Backspace" => enigo.key_click(Key::Backspace), _ => enigo.key_sequence(char), } } fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![send_input]) .run(tauri::generate_context!()) .expect("运行Tauri应用出错"); }
步骤2:前端JS调用
给你的虚拟键盘按键绑定点击事件,点击时调用上面的Rust命令:
// 假设每个按键元素都有data-key属性存要输入的内容(普通字符或特殊按键名) document.querySelectorAll('.key-btn').forEach(btn => { btn.addEventListener('click', async () => { const keyValue = btn.dataset.key; if (keyValue) { try { await window.__TAURI__.invoke('send_input', { char: keyValue }); } catch (err) { console.error('发送输入失败:', err); } } }); });
注意事项
- 权限问题:macOS上需要给你的应用开启「辅助功能」权限(系统设置→隐私与安全性→辅助功能),否则没法模拟系统输入;Windows和Linux一般不需要额外权限。
- 特殊按键可以直接通过
Enigo的Key枚举来处理,比如Tab、Shift这些都支持。
二、应用内虚拟键盘(只给自己的Tauri应用输入框用)
如果你的虚拟键盘只给自身应用的输入框用,那可以通过控制Tauri窗口的焦点来解决,避免点击按键时抢走输入框的焦点:
步骤1:配置窗口不抢焦点
在src-tauri/tauri.conf.json里修改窗口配置,让虚拟键盘窗口默认不获取焦点:
"windows": [ { "title": "应用内虚拟键盘", "width": 500, "height": 150, "decorations": false, "alwaysOnTop": true, "focus": false, // 关键:窗口启动时不获取焦点 "transparent": true, "skipTaskbar": true } ]
步骤2:前端插入字符
因为输入框还保持着焦点,点击按键时直接找到当前聚焦的输入元素,插入字符即可:
document.querySelectorAll('.key-btn').forEach(btn => { btn.addEventListener('click', () => { const char = btn.dataset.char; if (!char) return; // 获取当前聚焦的输入元素 const activeElement = document.activeElement; if (activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA')) { // 插入字符到光标位置 const start = activeElement.selectionStart; const end = activeElement.selectionEnd; const value = activeElement.value; activeElement.value = value.substring(0, start) + char + value.substring(end); // 恢复光标位置 activeElement.selectionStart = activeElement.selectionEnd = start + char.length; // 触发输入事件,确保表单能捕获到变化 activeElement.dispatchEvent(new Event('input')); } }); });
这种方案不需要依赖Rust库,纯JS就能搞定,适合应用内的场景。
备注:内容来源于stack exchange,提问作者Commodore64
相关产品推荐
相关产品推荐

