この記事は自ブログからの転載です。
元記事: Claude DesktopのEnter誤送信が鬱陶しいので、Ctrl+Enterで送信できるようにしてみた
Claude DesktopのEnter誤送信が鬱陶しいので、Ctrl+Enterで送信できるようにしてみた【日本語IME対応/2026年10月】
この記事はChatGPTなどの生成AIを利用して執筆しています。ツールの調査・実装もAIの支援を受けていますが、IMEの動作やClaude Desktop上での操作は手元の環境で検証しました。
2026年10月9日時点の記録です。 Claude Desktopの非公開実装に依存した非公式ツールであり、今後の更新への対応を保証するものではありません。
日本語でClaudeを使っていると、Enterキーでやらかしませんか。
日本語変換を確定しようとしてEnterを押したら、そのままメッセージまで送信してしまう。変換の途中だったり、まだ文章が完成していなかったりするので、地味に面倒くさいんですよね。
Microsoft TeamsやChatGPTなどでは、普段からCtrl+Enterで送信する操作に慣れています。なので、Claudeだけ入力欄の挙動が違うのが、どうにも気持ち悪い。
ということで、Enterで改行、Ctrl+Enterで送信するツールを作りました。日本語IMEの変換確定は邪魔しません。ついでにClaudeの画面内でキーを変更できるようにもしています。
最初はAutoHotkeyでどうにかするつもりだったのですが、IMEの状態判定が予想以上に厄介で、最終的にはElectron内部のWeb画面へ拡張機能を読み込ませる方法に落ち着きました。
この記事では、まず導入方法と結論を掲載し、そのあとでAutoHotkeyによる調査、Electronのapp.asar解析、WebExtensionの読み込み方法、Tiptapのキーイベント処理まで書いていきます。
最初に結論
作成したのは Claude Ctrl+Enter という非公式のClaude Desktop向けツールです。
GitHub: zawa356/claude_ctrl-enter
ダウンロード: 最新のReleases
詳しい導入方法: README(日本語)
| 操作 | 導入後の初期設定 |
|---|---|
Enter |
改行 |
Ctrl+Enter |
送信 |
IME変換中のEnter
|
変換候補の確定。送信も改行もしない |
/コマンドやメンション候補表示中のEnter
|
Claude本来の候補選択 |
サイドバーの「⌨ キー設定」から有効・無効を切り替えたり、送信キーと改行キーをEnter、Ctrl+Enter、Shift+Enter、Alt+Enterの中から選び直したりできます。設定は再起動後も保持されます。
実際の操作感としては、特別な機能が増えたというより、ほかのチャットアプリと同じ感覚で普通に文章を入力できるようになった、というものです。今回ほしかったのはまさにそれなので十分です。
対応環境
| 項目 | 2026年10月9日時点の状況 |
|---|---|
| Windows 10 / 11 | Claude DesktopのMSIX版向け。Windows実機で検証 |
| 検証したClaude |
2.26454.2、2.31226.0(共通ローダー移行後は後者で確認) |
| Linux | Claude Desktopベータ向けスクリプトあり。実機未確認、CIテストのみ |
| macOS | 未対応 |
| インストール権限 | Windowsでは管理者権限不要 |
Claude本体のclaude.exeやapp.asar、Microsoft Storeアプリのインストール先には手を加えません。
導入方法(Windows)
-
最新のReleasesから
claude-ctrl-enter-<バージョン>.zipをダウンロードして展開します。 - 中にある
install.batを実行します。診断情報を確認し、続行を求められたらYを入力します。 - Claude Desktopをタスクトレイから完全に終了させます。単にウィンドウを閉じるだけでは不十分な場合があります。
- いつものClaudeのアイコンから起動し直します。
- 左サイドバーのプロフィール欄の上に「⌨ キー設定 有効」と出ているか確認します。
これでEnterは改行、Ctrl+Enterは送信になります。インストール後も専用ランチャーやショートカットは不要です。
Windowsが未署名のbatファイルについて警告する場合があります。内容を確認したうえで実行してください。インストーラーやPowerShellスクリプトもリポジトリで公開しています。
元に戻す: uninstall.batを実行し、Claude Desktopを完全終了して起動し直します。キーだけ一時的に元へ戻したい場合は「キー設定を有効にする」をオフにする方法もあります。
診断: diagnose.batは読み取り専用です。動かないときは、まずこれで導入状況を確認できます。
配布版の導入・更新手順は今後変わる可能性があるため、実際にインストールするときはREADMEを優先してください。
なぜAutoHotkeyではなく、Electronの中に実装したのか
ここから先は技術的な話です。
「Ctrl+Enterを押したら送信するだけ」なら、Windowsのキーリマップで終わるように思えます。自分も最初はそう考えてAutoHotkey v2を使い始めました。
しかし、問題の中心にあったのはCtrl+Enterではなく日本語IMEの変換確定でした。
1. Enterには別の役割がある
日本語入力中のEnterは、状況によって違う意味になります。
- 変換候補の選択・確定
- 未確定文字列の確定
- 変換が終わったあと、通常の入力欄で行う改行
- Claudeが割り当てている送信
さらに、句読点や「@」のような全角記号、候補ウィンドウ、キー入力のタイミングも関係します。
Windows側で単純にEnterを別のキーへ変換すると、IMEが必要としているEnterまで奪ってしまう可能性があります。
なので、まずはWindowsからIMEの変換状態をどこまで取得できるかを調べました。
2. AutoHotkey + UI AutomationでIMEイベントを調べる
AutoHotkey v2とUI Automationを使い、Claude Desktopの入力欄に対して、次のイベントを監視する試作を作りました。
| イベント | 調査上の意味 |
|---|---|
TextEditTextChanged / Composition(2)
|
IME変換中に観測されたイベント |
TextEditTextChanged / Finalized(3)
|
確定を検出できるか試すためのイベント |
TextChanged(20015) |
テキストが変更されたことを示すイベント |
調査スクリプトはAutoHotkey v2のUIAライブラリを使用したもので、入力キー自体は変更せず、イベントの時刻と種類だけをログに残す診断用でした。変換文字列や入力内容は記録していません。
実際に使用したスクリプトでは、おおむね次のようにハンドラーを登録しています(コードは要点のみ。実行にはAutoHotkey v2とUIA-v2ライブラリ、およびコールバック・後始末の実装が必要です)。
#Requires AutoHotkey v2.0
#Include Lib\UIA.ahk
el := UIA.GetFocusedElement()
; 変換・確定関連の通知を観測
hComp := UIA.CreateTextEditTextChangedEventHandler(OnComposition)
hFinal := UIA.CreateTextEditTextChangedEventHandler(OnComposition)
hText := UIA.CreateAutomationEventHandler(OnTextChanged)
UIA.AddTextEditTextChangedEventHandler(hComp, el, 2, 1)
UIA.AddTextEditTextChangedEventHandler(hFinal, el, 3, 1)
UIA.AddAutomationEventHandler(hText, el, 20015, 1)
ここで期待していたのは「Compositionで変換中へ入り、Finalizedで変換終了が分かる」という素直な状態遷移です。
しかし、実際の通知はそう簡単ではありませんでした。
2-1. 観測できたイベントの順序
2026年10月8日のログから、代表的な部分を抜粋すると次のような形です。
2719 ms | RAW Composition(2)
2719 ms | STATE=COMPOSING (Composition observed)
2719 ms | RAW TextChanged(20015)
2719 ms | MATCH Composition -> TextChanged
3328 ms | RAW TextChanged(20015)
3328 ms | STATE=PENDING_TEXT
3500 ms | UNMATCHED TextChanged
3500 ms | STATE=IDLE_INFERRED (Unpaired TextChanged (NOT guaranteed))
※ログのSTATE=...は診断スクリプト自身が推定した状態です。Windowsが「IMEは終了した」と保証したものではありません。
CompositionとTextChangedが同時、または十数ミリ秒の差で届く例がありました。一方でTextChangedだけが単独で届く場面もあります。
そこで、CompositionとTextChangedを150ms以内の時間差で照合し、対応しないTextChangedがあったら変換終了を推測する分類器まで作っています。
しかし、これでは「変換終了を確実に検出できた」とは言えません。実際のログでも状態名はIDLE_INFERRED、理由はNOT guaranteedです。
この結果は、AutoHotkeyやUI Automation全般でIME判定が絶対にできない、という証明ではありません。少なくとも今回のイベントと判定方式だけでは、誤送信を防ぐための十分に確実な状態判定にならなかった、という話です。
本来の目的は、キー操作を楽にすることです。判定器のタイミング調整を延々と続けるより、もう少し入力欄に近いところで処理した方がよさそうです。
3. Claude Desktopの中身はElectron
ということで、別の方向から攻めることにしました。
Claude DesktopのUIはElectron上で動いています。つまり、Webページ側のDOMやキーボードイベントにアクセスできれば、WindowsのIME状態を外側から推定するより、入力欄が直接受け取っているイベントに基づいて判断できます。
ただし、公式のClaudeアプリを壊してまでキー操作を直したいわけではありません。
ここでの制約は最初から次のとおりでした。
-
claude.exeやapp.asarを改変しない - Microsoft Storeの署名付きMSIXを壊さない
- いつものアイコンから普通に起動できる
- 新しい専用ランチャーを使わせない
- 不要になったら解除できる
この条件を満たす方法を探します。
3-1. app.asarを読み取り専用で調べる
最初にWindows側でパッケージ情報を確認しました。
Get-AppxPackage -Name '*Claude*' |
Select-Object Name, Version, PackageFamilyName, InstallLocation
調査した2.26454.2では、app/resources/app.asarが存在しました。app.asarはElectronでよく使われるアーカイブ形式です。
本体を変更しないよう、作業用のフォルダーへコピーしてから解析しました。実例として、コピー後の作業フォルダーで次を実行すれば、パッケージ情報を読み出せます。
# ここでは作業用フォルダーに app.asar をコピー済みとする
npx --yes @electron/asar extract-file .\app.asar package.json
Get-Content .\package.json -Raw | ConvertFrom-Json |
Select-Object name, version, main
当時の結果は次のようなものでした。
name version main
---- ------- ----
@ant/desktop 2.26454.2 .vite/build/index.pre.js
npxを使う場合はNode.js/npmが必要です。また、ソースはminifyされた大きなバンドルなので、何かを検索すればすぐ意味が分かるというものでもありません。
起点のindex.pre.jsから呼び出し先を追い、mainView.js、mainWindow.js、各index.chunk-*.jsを調べました。外側のウィンドウとチャット本体が別に構成され、通常のチャットはhttps://claude.aiを読み込むことが分かりました。
この時点で重要なのは、入力欄の送信処理そのものは、MSIXのネイティブ部分を改造しなくても操作できそうだったことです。
3-2. 開発者ツールで入力欄を確認
調査時にはClaudeの「ヘルプ」→「トラブルシューティング」から開発者モードを有効にし、入力欄にフォーカスした状態でCtrl+Alt+Iを押してDevToolsを開きました。
※これは開発時にDOMを調べるための操作です。公開版のインストールに開発者モードを有効化する必要はありません。初期試作と現在の導入要件を混同しないようにします。
コンソールで入力欄を見ると、次のような要素が見つかりました。
<div class="tiptap ProseMirror" contenteditable="true" role="textbox">...</div>
説明用に属性を抜粋しています。実際のDOMにはほかにも属性があります。
さらに、次のようなコマンドで確認できます。
const el = document.querySelector('.tiptap.ProseMirror[contenteditable="true"]');
console.log('editor:', !!el?.editor);
console.log('hardBreak:', typeof el?.editor?.commands?.setHardBreak);
console.log('view composing:', el?.editor?.view?.composing);
当時の環境ではel.editorが存在し、editor.commands.setHardBreak()を利用できました。
つまり、単にEnterというキーイベントを合成するのではなく、入力エディターの正規の改行コマンドを直接呼び出せるわけです。
3-3. 送信は内部APIよりもボタンを利用する
続いて送信処理も調べました。
Tiptap/ProseMirrorのプラグインやキーマップを見れば内部の送信コマンドも見つかるかと思いましたが、バンドルされた関数や閉じたスコープが多く、確実な呼び出し経路を特定できませんでした。
そこで無理に内部APIを追うのはやめて、Claudeが表示している送信ボタンを利用する方式にしました。
実機で確認したのは次の属性です。
<button data-testid="chat-input-send" aria-label="メッセージを送信">...</button>
aria-labelの日本語はローカライズで変わるかもしれませんが、data-testidは当時のDOMで識別に使える値でした。
とはいえ、画面のどこかにある送信ボタンを単純にquerySelector()して押すのは危険です。過去のメッセージ編集欄など、別の入力欄が開いている可能性があります。
現在の実装は、操作対象のエディターに対応する、表示中の送信ボタンが一意に特定できた場合だけクリックします。複数候補があったり、ボタンが無効だったりする場合は送信しません。
この「曖昧だったら送らない」は、誤送信を防ぐツールとして重要な判断でした。
4. キー操作の実装
ここからは現在の実装を見ていきます。主要部分はextension/keys.jsにあります。
4-1. keydownをキャプチャ段階で処理する
拡張機能はwindowにkeydownのリスナーを登録し、capture: trueで受け取ります。
// extension/keys.jsの構造を抜粋
const controller = new AbortController();
const options = { capture: true, signal: controller.signal };
const selector = '.tiptap.ProseMirror[contenteditable="true"]';
window.addEventListener('keydown', e => {
const el = e.target instanceof Element ? e.target.closest(selector) : null;
if (!el || e.key !== 'Enter') return;
// ここでIME状態・キー設定・候補メニューを判定する
}, options);
キャプチャ段階で判定することで、Claude本来のEnter送信処理よりも前に介入できます。
なお、キーが入力欄以外にある場合は基本的に何もしません。ダイアログ操作や別のUIにまで干渉するためのツールではないからです。
4-2. IMEの変換中はブラウザー本来の確定操作を残す
特に重要なのが次の判定です。
// extension/keys.jsより要点を抜粋
if (state.composing || e.isComposing || e.keyCode === 229 || editor?.view?.composing) {
e.stopImmediatePropagation();
return;
}
判定には複数の情報を使っています。
| 判定 | 役割 |
|---|---|
compositionstart / compositionend
|
入力欄単位でIMEの合成状態を追跡 |
event.isComposing |
キーイベント自身が持つ合成中フラグ |
keyCode === 229 |
IME処理を示すことがある互換情報 |
editor.view.composing |
Tiptap/ProseMirror側の変換状態 |
変換中はClaude側の送信ハンドラーへの伝播を止めますが、preventDefault()は呼びません。IME自身による候補確定はそのまま動かしたいからです。
加えて、compositionend直後の100ms以内に届いたEnterは抑止する処理もあります。これは変換完了直後のイベントで意図せず改行・送信しないようにするための安全側の対策です。
100msという値があらゆる日本語IMEで最適だと証明したわけではありません。あくまで今回の実装における保護策であり、IMEやバージョンの組み合わせによって追加検証の余地はあります。
4-3. 改行はTiptap、送信は対応するボタン
IME以外の通常のキー入力であれば、設定に応じて処理を分岐します。
// 実装から処理の要点を再構成した例
if (action === 'newline') {
editor.commands.setHardBreak();
} else if (action === 'send') {
const button = sendButtonFor(el);
if (!button || button.disabled || button.getAttribute('aria-disabled') === 'true') {
return;
}
button.click();
}
改行にsetHardBreak()を使うため、Webエディターの内部状態を無視したDOM直書きや、合成Enterキーの投げ直しをしなくて済みます。
送信は送信ボタンに任せるので、Claudeの内部送信関数の名前や引数を推測する必要がありません。ただし、今後DOM構造や送信ボタンの識別子が変われば動作しなくなる可能性はあります。
4-4. /コマンドの候補選択を壊さない
試作中にもう1つ問題が出ました。
スラッシュコマンドやメンションの候補一覧を出しているときは、Enterが「選択する」という操作に使われます。何も考えずにすべてのEnterを改行にすると、候補を選べません。
公開版では、この点を修正しました。TiptapのSuggestion系プラグインの状態と、実際に表示されているメニューを両方確認し、候補が開いているときの通常EnterはClaudeへ渡すようにしています。
// extension/keys.js より
const active = editor.state.plugins.some(
p => /suggestion|mention/i.test(p.key) &&
p.getState(editor.state)?.active === true
);
実際のコードではこの判定に加えて、[role="menu"],[role="listbox"]の表示状態も確認しています。
このような細部は、最初にEnterを改行にできた時点では見落としがちです。「想定したキーだけ動く」と「普段の文章入力を邪魔せず使える」は、なかなか別物でした。
5. 一時パッチを毎回実行するわけにもいかない
ここまでの挙動は、当初DevToolsのConsoleへJavaScriptを入力する一時的な方法で検証しました。
しかし、ページを読み込み直したら消えてしまいます。毎回コンソールへ貼り付けて使うのでは、さすがに本末転倒です。
そこで、Claude Desktopに通常起動時からWebExtensionを読み込ませる方法を探しました。
5-1. 使わなかった方式
Electronなら何でもできそうですが、今回のClaudeでは使えない、あるいは使いたくない方法がありました。
| 方法 | 採用しなかった理由 |
|---|---|
app.asarの直接改造 |
MSIXの署名・整合性や今後の更新を考えると避けたい。公式アプリを改変したくない |
--remote-debugging-port等を使う起動 |
Claude側に関連引数の検査があり、通常起動を拒否する経路を解析で確認。専用ランチャーも必要になる |
NODE_OPTIONSによる起動フック |
対象バイナリではElectron fuseによって関連機能が無効 |
| Claudeメニューの「拡張機能をインストール」 | MCP/DXT系の仕組みであり、任意のChrome content scriptを読み込む入口とは確認できなかった |
重要なのは、Electron一般の機能とこのClaude Desktopで実際に使える機能を混同しないことです。
5-2. REACT_PROFILE=1という読み込み経路を発見
app.asar内のJavaScriptを調べていたところ、React DevToolsに関するコードを見つけました。
当時の対象ビルドでは、起動時に次の環境変数を確認しています。
REACT_PROFILE=1
この値が設定されていると、メインウィンドウ生成前にloadReactDevTools()が実行され、特定の拡張フォルダーをsession.defaultSession.loadExtension()へ渡す構造でした。
%APPDATA%\Claude\extensions\fmkadmapgofadopljbjfkapdkoienihi\
fmkadmapgofadopljbjfkapdkoienihiはReact Developer Toolsの拡張IDとして使われる文字列です。ただし、今回の仕組みではその名前のフォルダーを読み込み先として利用しているだけで、React DevToolsそのものを入れる必要はありません。また、そのフォルダー名と実際に割り当てられるChromium内部の拡張IDが同一であると証明した、という話でもありません。
この経路のポイントは、Claudeの実行ファイルを変更しなくて済むこと。Windowsのユーザー環境変数と、ユーザーデータに置いた拡張だけで済みます。
ただし、これは非公開の実装を利用した方法です。Anthropicが将来この経路を削除・変更すれば、当然使えなくなります。
5-3. MV3拡張にする
最終的な拡張はManifest V3で、2つのcontent scriptを使います。
{
"manifest_version": 3,
"content_scripts": [
{
"matches": ["https://claude.ai/*"],
"js": ["keys.js"],
"run_at": "document_start",
"world": "MAIN",
"all_frames": false
},
{
"matches": ["https://claude.ai/*"],
"js": ["settings-ui.js"],
"run_at": "document_start",
"all_frames": false
}
],
"permissions": ["storage"]
}
※拡張全体のname、version、descriptionなどは省略しています。完全な定義はextension/manifest.jsonを参照してください。
keys.jsはWebページのJavaScriptと同じMAIN worldで動き、TiptapのエディターAPIを呼びます。一方settings-ui.jsは通常の拡張用の実行環境で動き、chrome.storage.localを使って設定を保存します。
両者の設定は、ページルートの属性data-claude-enter-settingsとカスタムイベントclaude-enter-settings-changedで受け渡します。保存済みの設定を読み込むまで、未知の送信キーで誤って送信しないようにするガードもあります。
実装はdocument_startから開始します。試作版のdocument_idleでは起動直後に元のEnter処理が動く余地があったため、公開版で早期読み込みに変更しました。
6. 設定UIもClaudeの画面に置く
キーの割り当てを変えるたびにスクリプトを修正するのは面倒なので、設定UIも作りました。
最初はClaudeの「ファイル」「編集」のようなネイティブメニューへ項目を追加したかったのですが、今回使うWebExtension側から素直に操作できるものではありません。
そこで、左サイドバーのプロフィール欄の上に「⌨ キー設定」を追加しています。
右下へ固定のバッジを表示する試作もありましたが、モデル選択などと重なって邪魔だったので撤去しました。やっぱり、自分用のツールでも普段の画面を邪魔するのは嫌です。
設定画面では次のことができます。
- 送信・改行キーの変更
- 有効/無効の切り替え
- 初期値への復帰
- 保存済み設定の読み込み、再起動後の復元
- 想定外の画面構造や送信ボタンの判定失敗を知らせる状態表示
設定画面はShadow DOMを使っており、Claude本体のCSSと衝突しにくいようにしています。また、送信と改行に同じキーを設定しないよう検査しています。
設定UIの実装を見ると、サイドバーのdata-testid="user-menu-button"などを手掛かりに挿入位置を確認しています。この部分も当然Claudeの画面構造に依存するため、変更されれば追従が必要です。
7. 実機検証とテストの範囲
開発時点では、主にWindowsのClaude Desktopで次を確認しています。
| 検証項目 | 結果 |
|---|---|
| IME変換中の確定Enter | 変換確定を維持、誤送信なし |
| 全角記号・句読点を含む日本語入力 | 実機で基本動作を確認 |
| Enterによる改行 | 動作確認 |
| Ctrl+Enterによる送信 | 動作確認 |
| 別チャットへの移動 | 設定したキー操作を維持 |
| サイドバーからのキー変更/有効・無効 | 動作確認 |
| 完全終了・通常起動後の設定保持 | 動作確認 |
/コマンド等の候補選択 |
初期の問題を修正し、公開版で対応 |
| Linux Desktop | 自動試験のみで、実機検証なし |
また、Node.js上の模擬環境でキーイベント処理をテストし、Playwrightを使って設定UIの表示や保存の振る舞いも確認しています。公開用インストーラーはPowerShellのテストも整備しました。
ただし、模擬テストが通ったことと、すべてのIME・すべてのClaudeバージョンで正常に動くことは別です。テスト対象外の画面や複数ウィンドウなどでは、想定外の挙動が残る可能性があります。
8. もう1つツールを作ったら、読み込み先が競合した
ここまででCtrl+Enter自体は実用になりました。
ところが、その後にChatとCoworkの分離UIを戻す拡張も開発しました。
そのツールも、同じREACT_PROFILE経由でClaude DesktopにChrome拡張を読み込ませたい。つまり、1つしかないReact DevTools用の拡張枠を取り合うことになります。
せっかく作ったのに、一方をインストールするともう一方が消えるのは困ります。
8-1. 共通ローダーを作る
そこで、別プロジェクトとしてclaude-desktop-webextを作りました。
各ツールは普通のMV3拡張フォルダーをそれぞれ保持し、共通ローダーが1つのManifestにまとめてClaude Desktopへ読ませる構造です。
claude-ctrl-enter(キー操作) ──┐
├─> claude-desktop-webext
claude-split-ui(分離UI) ─────┘ │
▼
1つの生成MV3 manifest
│
▼
Claude DesktopのReact DevTools読み込み枠
Windowsでの保存先は次のとおりです。
%LOCALAPPDATA%\ClaudeDesktopWebExt\web-extensions\claude-ctrl-enter\
%LOCALAPPDATA%\ClaudeDesktopWebExt\web-extensions\claude-split-ui\
%APPDATA%\Claude\extensions\fmkadmapgofadopljbjfkapdkoienihi\
↑ ローダーが生成する読み込み先
Ctrl+Enterはorder: 50、先に起動時の通信をフックするSplit UIはorder: 10にしています。
ローダーは導入・更新・解除と、バックアップ・ロールバックを担当します。複数拡張のマニフェストや権限を安全に統合できる範囲だけ対応しており、Chrome拡張なら何でも使えるわけではありません。
似た目的でClaude-WebExtension-Launcherというプロジェクトもありましたが、あちらは改変したClaudeを使う方式です。こちらは公式のMSIX版Claudeをそのまま使うことを優先しました。
8-2. 既存の設定を引き継げるか
Ctrl+Enter 0.4.0から共通ローダーへ移行しています(2026年10月9日の0.4.1は主にドキュメントとローダーのリリース版への更新です)。
WindowsのClaude 2.31226では、旧0.3.0の環境から更新し、保存していたキー設定が残ることを確認しました。さらにSplit UIを同時導入した状態で、分離UI、サイドバーのキー設定、Enter改行、Ctrl+Enter送信がすべて動作しています。
これで普段使いのClaudeに必要な2つの不満を、同時に解消できました。
9. AIを使って開発した感想
今回、コードの実装やテスト、調査メモの整理にはChatGPTなどのAIをかなり使いました。
特に印象的だったのは、一度で正解の実装が出てくるわけではないことです。
AutoHotkeyのIME状態判定では、イベントが取得できているというだけでは十分ではありません。IDLE_INFERREDを「確定している状態」と扱ってしまえば、一番避けたい誤送信につながります。
Electronの調査でも、最初に検索したバンドルで拡張読み込み経路が見つからなかったからといって、存在しないわけではありませんでした。別のchunkまで調べることでloadReactDevTools()が見つかっています。
AIが候補を出し、スクリプトを組み、検証項目を増やす。その結果を実機で確かめて、ダメなら原因を戻って調べる。この繰り返しです。
Ctrl+Enter自体は小さな機能ですが、入力中のIMEを壊さず、誤送信せず、Claude更新時にも戻せるようにするには、意外と検討することがありました。
10. 注意点と今後
本ツールはClaude Desktop内部の非公開の読み込み経路と、Web画面のDOM・エディターAPIに依存しています。
- Anthropic公式の機能ではなく、将来の互換性は保証できません。
- Claudeの更新で
REACT_PROFILEの読み込み経路が使えなくなる可能性があります。 -
data-testidやTiptapのAPIが変更されればキー操作が動かなくなる可能性があります。 -
REACT_PROFILEはユーザー環境変数なので、他の開発環境と競合する場合があります。 - 本物のReact DevToolsや未知の拡張が既存の読み込み先にある場合、インストーラーは上書きせず停止する設計です。
- Linux版は配布していますが実機未検証、macOSは未対応です。
- 未送信のメッセージがある場合は、導入・解除後の再起動前に保存してください。インストーラーはClaudeを強制終了しません。
万一動かなくなった場合に備えて、uninstall.batとdiagnose.batを用意しています。最新状況や既知の制約はGitHubで確認してください。
まとめ
「ClaudeでもCtrl+Enterで送信したい」。それだけのつもりで始めたのに、AutoHotkeyでIMEイベントを追い、ElectronのASARを調べ、React DevToolsの読み込み経路を見つけ、WebExtensionを作り、最後は複数拡張を共存させる共通ローダーまで作ることになりました。
なかなか遠回りした気もしますが、いまは日本語変換も、普通のEnter改行も、Ctrl+Enter送信も違和感なく使えています。
便利な追加機能というより、マイナスだった使い勝手をゼロに戻すためのツールですね。
とはいえ、毎日使う入力欄に余計なストレスがなくなるのは、やっぱり大事だと思います。
