📮

Bing Chat 等の「文字変換!あっ、途中で送信された..orz」を防ぐChrome拡張を作ってみた

2023/04/19に公開

ニッチなChrome拡張を作ってみたので紹介です。

🛡️ 作ったもの

最近LLMサービスの台頭で、海外のチャット形式のサイトを触る機会が増えました。
ただ、その時に困るのがIMEの文字変換に対応しておらず、文字変換確定のEnterで入力内容が送信されることです。

代表的なものには Bing ChatChatPDFです。MacのEdgeやChromeでBing Chatを使った人は何度もこの問題に遭遇したことがあると思います。

そこで、この問題を解決するIME Submit BlockerというChrome拡張を作ってみました。

以下動画のように、この拡張機能を入れるとどのようなサイトでもIMEの文字変換確定のEnterで入力内容が送信されなくなります

https://www.youtube.com/watch?v=hKHRTvYDO2Y

Chrome Web StoreとEdge Add-onsにも公開しているのでぜひ使ってみてください。
(良かったらChrome Web StoreのレビューかGitHubのStarをもらえると泣いて喜びます😭)

https://chrome.google.com/webstore/detail/ime-submit-blocker/apmppndmejpolkldpeeipcejcbjfpblo?hl=ja&authuser=0

🛠️ 実装のポイント

実装時の工夫を紹介します。
以下で説明するコードはすべてGitHubのリポジトリで公開しています。

https://github.com/kawamataryo/ime-submit-blocker

Plasmo での爆速開発

今回はじめてPlasmoというフレームワークを使って、Chrome拡張機能を作ってみました。PlasmoはChrome拡張機能を効率的に開発するための各種ツールを提供してくれるフレームワークです。

https://www.plasmo.com/

Plasmoの特徴は以下の通りです。

  • React, Vue, SvelteでのUI構築
  • Chrome, Edge, Firefoxなど複数ブラウザへの対応
  • HMRによる開発効率の向上
  • MessagingやLocalStoreなどのブラウザの API を簡単に利用できるラッパーの提供

実際に開発してみて、はじめてRailsでWebアプリを使ったときのような快適さを感じました。Chrome拡張機能の開発は、地味に環境構築やAPIの理解に時間がかかるのですが、そこに時間を取られることなくスムーズに開発できて良かったです。

isComposingでIMEの文字変換確定かどうかを判定

IMEの文字変換確定のEnterかどうかの判定は、isComposingというAPIを使っています。

https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/isComposing

isComposingはKeyboardEventが持つReadonlyのプロパティで、IMEの文字変換中かどうかを表します。IMEの文字変換中のEnter の場合は、isComposingがtrueになります。それをdocumentのcapturingフェイズで判定して、stopPropagationとpreventDefaultを行うことで、IMEの文字変換中のEnterでの入力内容送信を防いでいます。

https://github.com/kawamataryo/ime-submit-blocker/blob/main/src/lib/preventEnterOnIME.ts#L17-L51

Shadow DOM を考慮したイベントの購読

Bing ChatのようなWebComponentsのShadow DOMを使っているサイトでは、通常のdocument.addEventListenerのみでは入力欄のイベントをすべて取得できません。そのため、Shadow DOMを考慮した実装を行う必要があります。

今回の実装ではWebComponentsをタグ名の正規表現で取得し、そのShadow Rootに存在するWebComponentsを再帰的に取得することで、すべてのRootNodeのkeyup, keydown イベントを購読しています。

そうすることでほぼすべてのサイトのすべての入力欄での誤送信を防ぎます。

https://github.com/kawamataryo/ime-submit-blocker/blob/main/src/lib/preventEnterOnIME.ts#L1-L15

chrome.history.onVisited.addListener を利用した SPA 対応

SPAでのページ遷移時にも入力欄にイベントを再アタッチするために、chrome.history.onVisited.addListener を利用しています。

https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/history/onVisited

これはExtensionのbackground Service Workerで登録しているのですが、ページ遷移の度に引数で渡したコールバック関数が呼び出されます。そこで、content scriptにメッセージを送信して、content script側でイベントを再アタッチするようにしています。

https://github.com/kawamataryo/ime-submit-blocker/blob/main/src/background.ts#L4-L13

AbortSignal を利用したキャンセルの実装

手動でもON/OFFを制御できるようにするために、 AbortSignal を使っています。

https://developer.mozilla.org/ja/docs/Web/API/AbortSignal

AbortSignalはFetch APIの中断やEventListenerの購読停止に利用できます。今回は、グローバルに定義したAbortControllerのSignalを各EventListenerでのイベント登録時に引数で渡して、キャセルの実行時にAbortControllerのabortメソッドを呼び出すことで、イベントの購読を停止しています。

https://github.com/kawamataryo/ime-submit-blocker/blob/main/src/content.ts#L18-L21

💁‍♂️ おわりに

以上「IME Submit Blocker」の紹介でした!使ってもらえると嬉しいです!!
何か不具合あれば、気軽にIssueを立ててください。

https://github.com/kawamataryo/ime-submit-blocker/issues

Plasmoを試してみたり、普段使わないAPIを使ったりと勉強になりました。Plasmoの開発体験はとても良かったので今後も使っていきたいです。

Discussion