MacのSafariでClaude.aiを快適に使う:日本語入力時のEnterキー問題を解決するUserScript
はじめに
最近AIアシスタントとして注目を集めている「Claude.ai」ですが、MacのSafariで利用する際に日本語入力で困ったことはありませんか?特に日本語変換確定時のEnterキー押下が、意図せずメッセージを送信してしまう問題は多くのユーザーを悩ませています。
この記事では、その問題を解決するためのTampermonkeyスクリプトを紹介します。Safari特有の日本語入力とClaude.aiの相性問題を解消し、ストレスフリーな体験を実現しましょう。
問題の詳細
なぜ問題が発生するのか?
日本語などの変換入力が必要な言語では、IME(Input Method Editor)を使用して入力し、Enterキーで確定します。しかしClaude.aiをはじめとするチャットUIでは、Enterキーがメッセージ送信のショートカットとして機能しています。
これにより以下の問題が発生します:
- 日本語入力中にEnterで変換を確定すると、同時にメッセージが送信されてしまう
- 文章の途中で送信されるため、会話が分断される
- 特にSafariではこの問題が顕著(Chromeなどでは対策が施されている場合も)
解決策:UserScriptの導入
今回紹介するUserScriptは、Safari上のClaude.aiで日本語入力時のEnterキー競合を解決します。
スクリプトの機能
- 日本語入力中のEnterキーによるフォーム送信を防止
- 入力確定後の一定時間(デフォルト300ms)は送信をブロック
- 送信ボタンクリック時の誤送信も防止
- Claude.aiのUIが変更されても動的に対応
使用方法
- SafariにTampermonkey拡張機能をインストール
- 新規スクリプトを作成し、以下のコードを貼り付け
- 保存して有効化
- Claude.aiを開き、快適な日本語入力を体験
完全なコード
以下のコードをTampermonkeyの新規スクリプトとして保存してください:
// ==UserScript==
// @name Claude.ai用日本語入力修正(Safari用)
// @namespace http://tampermonkey.net/
// @version 1.2
// @description MacOSのSafariでClaude.aiを使用する際に日本語入力時のEnterキー競合を解決
// @author You
// @match https://*.claude.ai/*
// @match https://claude.ai/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// フラグとタイムスタンプの保存用
let isComposing = false;
let lastCompositionEndTime = 0;
const THRESHOLD_MS = 300; // 日本語確定後の送信防止時間(ミリ秒)
// Enter送信が有効かをチェックする
function isEnterSubmitAllowed() {
// 現在入力中か、または入力確定から閾値時間以内ならfalse
if (isComposing) return false;
const now = Date.now();
if (now - lastCompositionEndTime < THRESHOLD_MS) return false;
return true;
}
// キーイベントの完全なインターセプト(キャプチャフェーズで)
function interceptKeyEvents() {
document.addEventListener('keydown', function(event) {
// Enterキーで、ShiftKeyが押されていない場合
if (event.key === 'Enter' && !event.shiftKey) {
// 日本語入力中または直後なら、イベントを完全にキャンセル
if (!isEnterSubmitAllowed()) {
event.stopImmediatePropagation();
event.preventDefault();
return false;
}
}
}, true); // キャプチャフェーズが重要
// 入力開始イベント
document.addEventListener('compositionstart', function(event) {
isComposing = true;
console.log('日本語入力開始');
}, true);
// 入力確定イベント
document.addEventListener('compositionend', function(event) {
isComposing = false;
lastCompositionEndTime = Date.now();
console.log('日本語入力確定');
}, true);
}
// テキストエリア固有の処理
function setupTextareas() {
// Claude.aiの入力欄を取得(標準的なテキストエリアとプロンプト入力欄の両方を対象)
const inputElements = document.querySelectorAll('textarea, [contenteditable="true"], [role="textbox"]');
inputElements.forEach(input => {
// 既に処理済みの場合はスキップ
if (input.getAttribute('japanese-fix-applied')) return;
// 入力要素固有のkeydownハンドラ
input.addEventListener('keydown', function(event) {
if (event.key === 'Enter' && !event.shiftKey && !isEnterSubmitAllowed()) {
event.stopImmediatePropagation();
event.preventDefault();
console.log('入力欄でのEnterキーブロック');
return false;
}
}, true);
// 入力要素特有のcomposition処理
input.addEventListener('compositionstart', function() {
isComposing = true;
console.log('入力欄で日本語入力開始');
}, true);
input.addEventListener('compositionend', function() {
isComposing = false;
lastCompositionEndTime = Date.now();
console.log('入力欄で日本語入力確定');
}, true);
// 処理済みマーク
input.setAttribute('japanese-fix-applied', 'true');
});
}
// 送信ボタンをオーバーライドする関数
function overrideSendButton() {
// 一定間隔で送信ボタンを検索
setInterval(() => {
// Claude.aiの送信ボタンを探す(複数のセレクタをカバー)
const sendButtons = document.querySelectorAll('button[type="submit"], button[aria-label*="send"], button[aria-label*="Send"], button.send-button, form button');
sendButtons.forEach(button => {
// 既に処理済みならスキップ
if (button.getAttribute('japanese-fix-applied')) return;
// クリックイベントリスナーを上書き
const originalClick = button.onclick;
button.onclick = function(event) {
// 入力中なら送信をブロック
if (!isEnterSubmitAllowed()) {
event.stopImmediatePropagation();
event.preventDefault();
console.log('送信ボタンクリックをブロック');
return false;
}
// そうでなければ通常の処理を実行
if (originalClick) return originalClick.call(this, event);
return true;
};
// 処理済みマーク
button.setAttribute('japanese-fix-applied', 'true');
});
}, 1000);
}
// フォーム送信を直接制御
function overrideFormSubmission() {
// フォーム送信の監視
document.addEventListener('submit', function(event) {
if (!isEnterSubmitAllowed()) {
event.stopImmediatePropagation();
event.preventDefault();
console.log('フォーム送信をブロック');
return false;
}
}, true);
// Claude.aiで可能性のあるカスタム送信処理をインターセプト
const originalFetch = window.fetch;
window.fetch = function(...args) {
if (!isEnterSubmitAllowed() && args[0] && typeof args[0] === 'string' &&
(args[0].includes('/api/') || args[0].includes('/conversation'))) {
console.log('fetch APIによる送信をブロック', args[0]);
return new Promise(() => {}); // 処理をブロック
}
return originalFetch.apply(this, args);
};
}
// DOM変更の監視
function observeDOM() {
const observer = new MutationObserver((mutations) => {
setupTextareas();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
// 初期化関数
function initialize() {
console.log('Claude.ai日本語入力修正スクリプトを初期化');
interceptKeyEvents();
setupTextareas();
overrideSendButton();
overrideFormSubmission();
observeDOM();
}
// ページ読み込み時に実行
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialize);
} else {
initialize();
}
// 早期実行(document-startで)
interceptKeyEvents();
overrideFormSubmission();
})();
スクリプトの解説
このスクリプトは以下の主要な機能で構成されています:
1. 日本語入力状態の追跡
let isComposing = false;
let lastCompositionEndTime = 0;
const THRESHOLD_MS = 300; // 日本語確定後の送信防止時間(ミリ秒)
// Enter送信が有効かをチェックする
function isEnterSubmitAllowed() {
// 現在入力中か、または入力確定から閾値時間以内ならfalse
if (isComposing) return false;
const now = Date.now();
if (now - lastCompositionEndTime < THRESHOLD_MS) return false;
return true;
}
compositionstart
とcompositionend
イベントを監視して、日本語入力中かどうかを追跡します。また、入力確定後も一定時間(300ms)は送信をブロックすることで、誤送信を防止します。
2. キーイベントのインターセプト
document.addEventListener('keydown', function(event) {
// Enterキーで、ShiftKeyが押されていない場合
if (event.key === 'Enter' && !event.shiftKey) {
// 日本語入力中または直後なら、イベントを完全にキャンセル
if (!isEnterSubmitAllowed()) {
event.stopImmediatePropagation();
event.preventDefault();
return false;
}
}
}, true); // キャプチャフェーズが重要
キャプチャフェーズでEnterキーイベントをインターセプトして、日本語入力中や入力確定直後の送信を防止します。
3. 送信ボタンの制御
function overrideSendButton() {
// 一定間隔で送信ボタンを検索
setInterval(() => {
// Claude.aiの送信ボタンを探す(複数のセレクタをカバー)
const sendButtons = document.querySelectorAll('button[type="submit"], button[aria-label*="send"], button[aria-label*="Send"], button.send-button, form button');
sendButtons.forEach(button => {
// 既に処理済みならスキップ
if (button.getAttribute('japanese-fix-applied')) return;
// クリックイベントリスナーを上書き
const originalClick = button.onclick;
button.onclick = function(event) {
// 入力中なら送信をブロック
if (!isEnterSubmitAllowed()) {
event.stopImmediatePropagation();
event.preventDefault();
console.log('送信ボタンクリックをブロック');
return false;
}
// そうでなければ通常の処理を実行
if (originalClick) return originalClick.call(this, event);
return true;
};
// 処理済みマーク
button.setAttribute('japanese-fix-applied', 'true');
});
}, 1000);
}
送信ボタンのクリックイベントも制御し、日本語入力中の誤クリックによる送信を防ぎます。
4. 動的なDOM変更への対応
function observeDOM() {
const observer = new MutationObserver((mutations) => {
setupTextareas();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
MutationObserverを使用してDOM変更を監視し、動的に追加される入力欄にも対応します。
動作確認環境
- macOS Ventura 13.5以降
- Safari 16.5以降
- Tampermonkey 4.18.0
- Claude.ai(2025年3月現在)
カスタマイズポイント
-
THRESHOLD_MS
の値を調整することで、入力確定後の送信防止時間を変更できます - セレクタを追加/調整することで、他のウェブサイトにも応用可能です
注意点
- Claude.aiのUI変更により、将来的に機能しなくなる可能性があります
- Safariのバージョンや環境によって挙動が異なる場合があります
- このスクリプトはTampermonkeyの機能を使用しているため、他の拡張機能と競合する可能性があります
まとめ
このUserScriptを利用することで、MacのSafariでもClaude.aiを快適に使用できるようになります。日本語入力の問題に悩んでいた方は、ぜひお試しください。
また、このスクリプトはオープンソースで提供していますので、改善点や他のブラウザへの対応など、カスタマイズして活用していただければ幸いです。
最後まで読んでいただき、ありがとうございました。このスクリプトが皆さんのAI活用をより便利にする一助となれば幸いです。もし質問やフィードバックがあれば、コメントでお知らせください。
Discussion