From f1fafd23f21f75fbcb45e84de61ba4ed352616fa Mon Sep 17 00:00:00 2001 From: selftaughtdev Date: Tue, 8 Sep 2026 09:42:14 +0530 Subject: [PATCH] Fix autocomplete stealing keyboard focus from the editor Set NoFocus and WA_ShowWithoutActivating on the autocomplete popup and its list, remove the explicit focus grab when the list updates, and intercept key presses on the editor component while the popup is visible so navigation keys still operate the list. Fixes Mudlet/Mudlet#5310 --- CHANGELOG.md | 2 ++ .../texteditorautocompletecomponent.cpp | 33 ++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d80e095..862bf97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +- (2026-09-08) Fix autocomplete stealing keyboard focus from the editor. The popup and its list can no longer receive focus; typed text and navigation keys are routed between the editor and the list via the event filter (fixes Mudlet/Mudlet#5310) + - (2026-04-14) #177, Fix strange mouse behavior caused by rawLineIndexForYpos returning std::npos with negative y positions. (@distractor) - (2026-04-01) #176, Fix FreeBSD Build, CMake find Oniguruma, cmake fixes. (@SlySven) diff --git a/edbee-lib/edbee/views/components/texteditorautocompletecomponent.cpp b/edbee-lib/edbee/views/components/texteditorautocompletecomponent.cpp index 3c23332..61110e6 100644 --- a/edbee-lib/edbee/views/components/texteditorautocompletecomponent.cpp +++ b/edbee-lib/edbee/views/components/texteditorautocompletecomponent.cpp @@ -50,10 +50,15 @@ TextEditorAutoCompleteComponent::TextEditorAutoCompleteComponent(TextEditorContr this->setAttribute(Qt::WA_ShowWithoutActivating); menuRef_ = new QMenu(this); + menuRef_->setFocusPolicy(Qt::NoFocus); + menuRef_->setAttribute(Qt::WA_ShowWithoutActivating); menuRef_->setAccessibleName("Autocomplete"); listWidgetRef_ = new QListWidget(menuRef_); + listWidgetRef_->setFocusPolicy(Qt::NoFocus); + listWidgetRef_->setAttribute(Qt::WA_ShowWithoutActivating); + editorComponentRef_->installEventFilter(this); listWidgetRef_->installEventFilter(this); menuRef_->installEventFilter(this); @@ -336,15 +341,20 @@ bool TextEditorAutoCompleteComponent::eventFilter(QObject *obj, QEvent *event) return QObject::eventFilter(obj, event); } - if(obj == listWidgetRef_ && event->type() == QEvent::KeyPress) { + if ((obj == listWidgetRef_ || obj == editorComponentRef_) && event->type() == QEvent::KeyPress && menuRef_->isVisible()) { QKeyEvent* key = static_cast(event); + const bool eventFromEditor = (obj == editorComponentRef_); // text keys are allowed if (!key->text().isEmpty()) { QChar nextChar = key->text().at(0); if (nextChar.isLetterOrNumber()) { - QApplication::sendEvent(editorComponentRef_, event); - return true; + if (eventFromEditor) { + // the editor handles typed text itself + return false; + } + QApplication::sendEvent(editorComponentRef_, event); + return true; } } @@ -360,6 +370,9 @@ bool TextEditorAutoCompleteComponent::eventFilter(QObject *obj, QEvent *event) case Qt::Key_Tab: if (listWidgetRef_->currentItem() && currentWord_ == listWidgetRef_->currentItem()->text()) { // sends normal enter/return/tab if you've typed a full word menuRef_->close(); + if (eventFromEditor) { + return false; + } QApplication::sendEvent(editorComponentRef_, event); return true; } else if (listWidgetRef_->currentItem()) { @@ -371,10 +384,16 @@ bool TextEditorAutoCompleteComponent::eventFilter(QObject *obj, QEvent *event) break; case Qt::Key_Backspace: + if (eventFromEditor) { + return false; + } QApplication::sendEvent(editorComponentRef_, event); return true; case Qt::Key_Shift: //ignore shift, don't hide + if (eventFromEditor) { + return false; + } QApplication::sendEvent(editorComponentRef_, event); return true; @@ -383,11 +402,18 @@ bool TextEditorAutoCompleteComponent::eventFilter(QObject *obj, QEvent *event) case Qt::Key_Down: case Qt::Key_PageDown: case Qt::Key_PageUp: + if (eventFromEditor) { + QApplication::sendEvent(listWidgetRef_, event); + return true; + } return false; } // default operation is to hide and continue the event menuRef_->close(); + if (eventFromEditor) { + return false; + } QApplication::sendEvent(editorComponentRef_, event); return true; @@ -428,7 +454,6 @@ void TextEditorAutoCompleteComponent::updateList() // fills the autocomplete list with the curent word if (fillAutoCompleteList(doc, range, currentWord_)) { menuRef_->popup(menuRef_->pos()); - listWidgetRef_->setFocus(); // position the widget showInfoTip();