アプリがフォーカスされていない状態でもキーボードやマウスのイベントを取得したい場合(グローバルホットキーや入力監視など)、rdev クレートを使用します。
※ 単にアプリ内の入力を扱いたい場合は、JavaScript の window.addEventListener('keydown') で十分です。このレシピは OS レベルのフックについて解説します。
1. 依存関係の追加
src-tauri ディレクトリに移動して、以下のコマンドを実行します。
cargo add rdev
2. 実装(Rust 側)
rdev の listen 関数はブロッキングするため、別スレッドで実行してイベントをフロントエンドに送信します。
src-tauri/src/lib.rs
use rdev::{listen, Event, EventType};
use tauri::{AppHandle, Emitter};
#[tauri::command]
fn start_input_listener(app: AppHandle) {
std::thread::spawn(move || {
let callback = move |event: Event| {
match event.event_type {
EventType::KeyPress(key) => {
let _ = app.emit("input-event", format!("KeyPress: {:?}", key));
}
EventType::KeyRelease(key) => {
let _ = app.emit("input-event", format!("KeyRelease: {:?}", key));
}
EventType::ButtonPress(btn) => {
let _ = app.emit("input-event", format!("ButtonPress: {:?}", btn));
}
EventType::ButtonRelease(btn) => {
let _ = app.emit("input-event", format!("ButtonRelease: {:?}", btn));
}
_ => {} // MouseMove などは大量に来るので無視
}
};
if let Err(error) = listen(callback) {
eprintln!("Error: {:?}", error);
}
});
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![start_input_listener])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
3. 実装(フロントエンド側)
リスナーの開始とイベント受信
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
// イベントリスナーを登録
async function setupInputListener() {
// Rust からのイベントを受信
await listen<string>('input-event', (event) => {
console.log('入力イベント:', event.payload);
});
// リスナーを開始
await invoke('start_input_listener');
console.log('入力監視を開始しました');
}
// 使用例
setupInputListener();
4. 注意点
- セキュリティ: キーロガーとして振る舞うため、セキュリティソフトに誤検知される可能性があります。
- 権限: macOS では「アクセシビリティ」権限の許可が必要です。Linux では X11/Wayland の設定依存があります(Wayland では機能しない場合が多いです)。