From 521848da750c7740e0c9987f5b65a201c8d98353 Mon Sep 17 00:00:00 2001 From: 3ASiC <17235633+the3asic@users.noreply.github.com> Date: Tue, 2 Jun 2026 21:32:50 +0800 Subject: [PATCH] fix(ui): don't submit chat message on Enter during IME composition (#1091) CJK and other IME users confirm a candidate from the input-method popup by pressing Enter. The chat composer and the in-place message editor each bind a keydown handler that treats Enter (without Shift) as "submit", but they did not exclude the composition state. Pressing Enter to accept an IME candidate therefore sent the half-composed text (e.g. a stray "ce's") instead of just confirming the candidate. These textareas intentionally hijack Enter to submit (Enter sends, Shift+Enter inserts a newline), which bypasses the browser's native form submission and the IME guard that comes with it, so the guard has to be re-added explicitly. Add '&& !e.isComposing' to the three Enter-to-submit handlers: static/app.js (the main composer's button-submit path and its send/new-chat path) and static/js/chat.js (the editor for an already-sent message). Normal Enter (isComposing false) still submits; Shift+Enter still inserts a newline. Tested: node --check on both files; manually verified with a Chinese IME that pressing Enter to pick a candidate no longer sends, and a message is sent only after composition ends. --- static/app.js | 4 ++-- static/js/chat.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/static/app.js b/static/app.js index 2764b90..a848193 100644 --- a/static/app.js +++ b/static/app.js @@ -3160,7 +3160,7 @@ function initializeEventListeners() { setTimeout(() => uiModule.autoResize(textarea), 1); }); textarea.addEventListener('keydown', (e) => { - if (e.key === 'Enter' && !e.shiftKey) { + if (e.key === 'Enter' && !e.shiftKey && !e.isComposing) { // If ghost autocomplete is active, accept the suggestion instead of submitting if (window._ghostAutocomplete && window._ghostAutocomplete.isActive()) { e.preventDefault(); @@ -3733,7 +3733,7 @@ function startOdysseusApp() { // Enter to send (shift+enter for newline), or new chat when empty if (messageInput) { messageInput.addEventListener('keydown', (e) => { - if (e.key === 'Enter' && !e.shiftKey) { + if (e.key === 'Enter' && !e.shiftKey && !e.isComposing) { e.preventDefault(); // Flush the debounced icon update so dataset.mode reflects the current // text state. Without this, a fast type-and-Enter would still see the diff --git a/static/js/chat.js b/static/js/chat.js index cde0e6e..10f7e05 100644 --- a/static/js/chat.js +++ b/static/js/chat.js @@ -3424,7 +3424,7 @@ import createResearchSynapse from './researchSynapse.js'; // Also submit on Enter (without shift) editor.addEventListener('keydown', (e) => { - if (e.key === 'Enter' && !e.shiftKey) { + if (e.key === 'Enter' && !e.shiftKey && !e.isComposing) { e.preventDefault(); saveBtn.click(); }