diff --git a/gajim/gtk/chat_action_processor.py b/gajim/gtk/chat_action_processor.py
index b6615afefb1e55dce2cf4453736c47d05e2ea8fc..b03c17006cbbaa11f3579531c80715b4223f5686 100644
--- a/gajim/gtk/chat_action_processor.py
+++ b/gajim/gtk/chat_action_processor.py
@@ -24,9 +24,13 @@
 from gi.repository import Gtk
 
 from gajim.common import app
+from gajim.common import types
 from gajim.common.const import Direction
+from gajim.common.modules.contacts import GroupchatContact
 
 from .emoji_data_gtk import get_emoji_data
+from .groupchat_nick_completion import GroupChatNickCompletion
+
 if TYPE_CHECKING:
     from .message_input import MessageInputTextView
 
@@ -34,7 +38,11 @@
 
 
 class ChatActionProcessor(Gtk.Popover):
-    def __init__(self, message_input: MessageInputTextView) -> None:
+    def __init__(self,
+                 account: str,
+                 contact: types.ChatContactT,
+                 message_input: MessageInputTextView
+                 ) -> None:
         Gtk.Popover.__init__(self)
         self._menu = Gio.Menu()
         self.bind_model(self._menu)
@@ -51,6 +59,12 @@ def __init__(self, message_input: MessageInputTextView) -> None:
         self._buf = message_input.get_buffer()
         self._buf.connect('changed', self._on_changed)
 
+        self._nick_completion: Optional[GroupChatNickCompletion] = None
+        if contact.is_groupchat:
+            assert isinstance(contact, GroupchatContact)
+            self._nick_completion = GroupChatNickCompletion(
+                account, contact, message_input)
+
         self._start_mark: Optional[Gtk.TextMark] = None
         self._current_iter: Optional[Gtk.TextIter] = None
 
@@ -60,9 +74,14 @@ def _on_destroy(self, _popover: Gtk.Popover) -> None:
         app.check_finalize(self)
 
     def _on_key_press(self,
-                      _textview: Gtk.TextView,
+                      textview: MessageInputTextView,
                       event: Gdk.EventKey
                       ) -> bool:
+        if self._nick_completion is not None:
+            res = self._nick_completion.process_key_press(textview, event)
+            if res:
+                return True
+
         if not self._active:
             return False
 
@@ -305,3 +324,7 @@ def _move_selection(self, direction: Direction) -> None:
     def _item_has_focus(item: Gtk.ModelButton) -> bool:
         flags = item.get_state_flags()
         return 'GTK_STATE_FLAG_FOCUSED' in str(flags)
+
+    def process_outgoing_message(self, contact: str, highlight: bool) -> None:
+        if self._nick_completion is not None:
+            self._nick_completion.record_message(contact, highlight)
diff --git a/gajim/gtk/controls/groupchat.py b/gajim/gtk/controls/groupchat.py
index e10b7b21a9c854f2f85f7ab62ee46f280c89517a..33096eb5ff43d3cd0856fe5a912c1e90f3287bc3 100644
--- a/gajim/gtk/controls/groupchat.py
+++ b/gajim/gtk/controls/groupchat.py
@@ -72,7 +72,6 @@
 from gajim.gui.groupchat_inviter import GroupChatInviter
 from gajim.gui.groupchat_roster import GroupchatRoster
 from gajim.gui.groupchat_state import GroupchatState
-from gajim.gui.groupchat_nick_completion import GroupChatNickCompletion
 from gajim.gui.util import open_window
 
 from ..menus import get_encryption_menu
@@ -152,9 +151,6 @@ def __init__(self, account: str, jid: JID) -> None:
         # if True, the room has mentioned us
         self.attention_flag: bool = False
 
-        self._nick_completion = GroupChatNickCompletion(
-            self.account, self.contact, self.msg_textview)
-
         # Send file
         self.xml.sendfile_button.set_action_name(
             f'win.send-file-{self.control_id}')
@@ -657,7 +653,7 @@ def add_message(self,
             highlight = helpers.message_needs_highlight(
                 text, self.contact.nickname, self._client.get_own_jid().bare)
 
-            self._nick_completion.record_message(contact, highlight)
+            self.msg_textview.process_outgoing_message(contact, highlight)
 
         BaseControl.add_message(self,
                                 text,
diff --git a/gajim/gtk/groupchat_nick_completion.py b/gajim/gtk/groupchat_nick_completion.py
index 6a6e2162290abc3357367bac36d88a99c86dfc78..4369faed855f7bc2213c50d1495e2d2750925bfc 100644
--- a/gajim/gtk/groupchat_nick_completion.py
+++ b/gajim/gtk/groupchat_nick_completion.py
@@ -44,8 +44,6 @@ def __init__(self,
         self._contact.connect(
             'user-nickname-changed', self._on_user_nickname_changed)
 
-        message_input.connect('key-press-event', self._on_key_press)
-
         self._sender_list: list[str] = []
         self._attention_list: list[str] = []
         self._nick_hits: list[str] = []
@@ -140,10 +138,10 @@ def _nick_matching(nick: str) -> bool:
 
         return matches + other_nicks
 
-    def _on_key_press(self,
-                      textview: MessageInputTextView,
-                      event: Gdk.EventKey
-                      ) -> bool:
+    def process_key_press(self,
+                          textview: MessageInputTextView,
+                          event: Gdk.EventKey
+                          ) -> bool:
         if event.keyval not in (Gdk.KEY_ISO_Left_Tab, Gdk.KEY_Tab):
             self._last_key_tab = False
             return False
@@ -156,7 +154,6 @@ def _on_key_press(self,
 
         text_split = text.split()
 
-        # nick completion
         # check if tab is pressed with empty message
         if text_split:  # if there are any words
             begin = text_split[-1]  # last word we typed
@@ -194,22 +191,21 @@ def _on_key_press(self,
                 return False
 
         if self._nick_hits:
+            shell_like_completion = app.settings.get('shell_like_completion')
+
             if len(text_split) < 2 or with_refer_to_nick_char:
                 # This is the 1st word of the line or no word or we are
-                # cycling at the beginning, possibly with a space in
-                # one nick
+                # cycling at the beginning, possibly with a space in one nick
                 add = gc_refer_to_nick_char + ' '
             else:
                 add = ' '
             start_iter = end_iter.copy()
             if (self._last_key_tab and
                     with_refer_to_nick_char or (text and text[-1] == ' ')):
-                # have to accommodate for the added space from last
-                # completion
+                # have to accommodate for the added space from last completion
                 # gc_refer_to_nick_char may be more than one char!
                 start_iter.backward_chars(len(begin) + len(add))
-            elif (self._last_key_tab and
-                    not app.settings.get('shell_like_completion')):
+            elif self._last_key_tab and not shell_like_completion:
                 # have to accommodate for the added space from last
                 # completion
                 start_iter.backward_chars(
@@ -225,11 +221,10 @@ def _on_key_press(self,
             # get a shell-like completion
             # if there's more than one nick for this completion, complete
             # only the part that all these nicks have in common
-            if (app.settings.get('shell_like_completion') and
-                    len(self._nick_hits) > 1):
+            if shell_like_completion and len(self._nick_hits) > 1:
                 end = False
                 completion = ''
-                add = ""  # if nick is not complete, don't add anything
+                add = ''  # if nick is not complete, don't add anything
                 while not end and len(completion) < len(self._nick_hits[0]):
                     completion = self._nick_hits[0][:len(completion) + 1]
                     for nick in self._nick_hits:
diff --git a/gajim/gtk/message_input.py b/gajim/gtk/message_input.py
index 69fbff935d26686d9620a058a73bde0bf0f7c044..7974706116dd4765dade296e0e6bb3db123b1047 100644
--- a/gajim/gtk/message_input.py
+++ b/gajim/gtk/message_input.py
@@ -73,7 +73,8 @@ def __init__(self, account: str, contact: ChatContactT) -> None:
         self._undo_list: list[str] = []
         self.undo_pressed: bool = False
 
-        self._chat_action_processor = ChatActionProcessor(self)
+        self._chat_action_processor = ChatActionProcessor(
+            account, contact, self)
 
         self.get_buffer().create_tag('strong', weight=Pango.Weight.BOLD)
         self.get_buffer().create_tag('emphasis', style=Pango.Style.ITALIC)
@@ -313,3 +314,10 @@ def undo(self, *args: Any) -> None:
         if self._undo_list:
             buf.set_text(self._undo_list.pop())
         self.undo_pressed = True
+
+    def process_outgoing_message(self,
+                                 contact_name: str,
+                                 highlight: bool
+                                 ) -> None:
+        self._chat_action_processor.process_outgoing_message(
+            contact_name, highlight)