This is not a real answer but it describes the current situation. (I hope I got it right.)
The following section of
keyboard.c is relevant for the mouse event messages:
/* If in middle of key sequence and minibuffer not active,
start echoing if enough time elapses. */
if (minibuf_level == 0
&& (this_command_key_count > 0
|| !NILP (call0 (Qinternal_echo_keystrokes_prefix)))
&& ! noninteractive
&& echo_keystrokes_p ()
&& (/* No message. */
/* Or empty message. */
|| (BUF_BEG (XBUFFER (echo_area_buffer))
== BUF_Z (XBUFFER (echo_area_buffer)))
/* Or already echoing from same kboard. */
|| (echo_kboard && ok_to_echo_at_next_pause == echo_kboard)
/* Or not echoing before and echoing allowed. */
|| (!echo_kboard && ok_to_echo_at_next_pause)))
/* After a mouse event, start echoing right away.
This is because we are probably about to display a menu,
and we don't want to delay before doing so. */
if (EVENT_HAS_PARAMETERS (prev_event))
It shows that the menu key sequences are echoed even more direct than normal key strokes. The timer that ticks for normal keystrokes is bypassed for menu key sequences. BTW,
echo_keystrokes_p() just tests whether
echo-keystrokes is positive.
Now let us have a look at
echo_now() which is also defined in
/* Display the current echo string, and begin echoing if not already
doing so. */
/* This test breaks calls that use `echo_now' to display the echo_prompt.
&& echo_keystrokes_p () */)
current_kboard->immediate_echo = true;
/* Put a dash at the end to invite the user to type more. */
echoing = true;
/* FIXME: Use call (Qmessage) so it can be advised (e.g. emacspeak). */
message3_nolog (KVAR (current_kboard, echo_string));
Most interesting is here the last comment. That comment explicitly states that advising
message has no effect. That is the reason why the filter approach does not work.
Furthermore, it shows that the developers already considered to make message filters work. If you deliver them one more good reason to do so maybe they will.
Finally, let us have a look at the Elisp function
(defun read-key (&optional prompt)
"Read a key from the keyboard.
Contrary to `read-event' this will not return a raw event but instead will
obey the input decoding and translations usually done by `read-key-sequence'.
So escape sequences and keyboard encoding are taken into account.
When there's an ambiguity because the key looks like the prefix of
some sort of escape sequence, the ambiguity is resolved via `read-key-delay'."
;; This overriding-terminal-local-map binding also happens to
;; disable quail's input methods, so although read-key-sequence
;; always inherits the input method, in practice read-key does not
;; inherit the input method (at least not if it's based on quail).
(let ((overriding-terminal-local-map nil)
Later on they read the actual key with
read-key-sequence-vector within the body of the
(echo-keystrokes 0) is the most interesting part.
echo-keystrokes to zero is the official way to suppress the echoing of keystrokes including menu key sequences while reading characters from the keyboard.
interactive special form does not take that measure.
It is also not possible to advice
interactive in any way since it is a special Elisp form:-(.