TauriアプリのCtrl+Sはsave handlerの前にpreventDefaultする
TauriアプリのfrontendはWebView内で動きます。つまり、desktop appでもブラウザ由来のkeyboard behaviorが残ります。
よくあるのが Ctrl+S です。save handlerを実装したのに、押すとnativeの「Save Page As」dialogが出る。アプリがshortcutを完全には奪えていません。
多くの場合、足りないのは event.preventDefault() です。
症状: desktop appなのにSave Pageが出る
症状はこうです。
Ctrl+Sでprojectを保存したい- handler自体は呼ばれていることもある
- それでもWebViewがsave-page dialogを出す
- ユーザーにはブラウザっぽい挙動に見える
これは小さな技術問題ではなく、editor系desktop appの品質問題です。
shortcutを捕まえてdefaultを止める
app全体のshortcut handlerを置きます。
document.addEventListener("keydown", (event) => {
const mod = event.ctrlKey || event.metaKey;
if (mod && event.key.toLowerCase() === "s") {
event.preventDefault();
saveCurrentDocument();
}
});
Windows/Linuxは ctrlKey、macOSは metaKey です。
重要なのは、ブラウザ標準挙動を置き換えるshortcut branchでは必ず preventDefault() を呼ぶことです。
handlerだけ呼んでも不十分
これは不十分です。
if ((event.ctrlKey || event.metaKey) && event.key === "s") {
saveCurrentDocument();
}
app handlerが走っても、browser defaultも走ります。結果として「保存はされたがSave Page dialogも出る」という二重挙動になります。
関連shortcutも同じ方針にする
file actionは同じ形で扱います。
document.addEventListener("keydown", (event) => {
const mod = event.ctrlKey || event.metaKey;
const key = event.key.toLowerCase();
if (mod && key === "s" && !event.shiftKey) {
event.preventDefault();
saveCurrentDocument();
}
if (mod && key === "o") {
event.preventDefault();
openProject();
}
if (mod && event.shiftKey && key === "s") {
event.preventDefault();
saveAs();
}
});
shortcut mapは明示的にします。隠れたshortcutはテストしにくく、ユーザーにも伝わりません。
UIにshortcutを表示する
shortcutがあるactionは、近くに表示します。
<button onClick={saveCurrentDocument}>
Save <kbd>Ctrl</kbd><kbd>S</kbd>
</button>
macOS向けには Cmd 表示へ切り替えると自然です。
pluginを使う場合
少数のapp shortcutなら、frontendの keydown handlerで十分なことが多いです。
広範囲のbrowser shortcutをまとめて抑止したいなら、tauri-plugin-prevent-default のようなpluginを使えます。ただし、app固有のcommandは明示しておくほうが、UIとtestが安定します。
検証チェック
Ctrl+Sで保存され、Save Page dialogが出ない- macOS対応なら
Cmd+Sも動く - input focus中の編集shortcutを壊していない
- React component内で登録したhandlerはunmount時に外す
- UI表示と実際のshortcutが一致する
- native dialog regressionを手動または自動で確認する