Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

win32: Don't raise TextInput event when KeyDown was handled. #7351

Closed
wants to merge 1 commit into from

Conversation

grokys
Copy link
Member

@grokys grokys commented Jan 12, 2022

What does the pull request do?

On win32, returning handled from WM_KEYDOWN doesn't automatically prevent a WM_CHAR message, resulting in #5849.

The TranslateMessage call is responsible for translating the WM_KEYDOWN event to a WM_CHAR event, so one needs to "simply" not call this function if the key down event was handled. However there's a problem: TranslateMessage is called before the DispatchMessage call which dispatches the key down message to the WindowImpl.

To get around this, this PR adds a PreProcessMessage step which can be used to handle key down messages and raise events outside of DispatchMessage/WndProc. This solution broadly comes from WPF, though there the solution is a bit more complicated (it's hooked into using ComponentDispatcher events from HwndSource).

Fixed issues

Fixes #5849

On win32, returning handled from `WM_KEYDOWN` doesn't automatically prevent a `WM_CHAR` message, resulting in #5849.

The `TranslateMessage` call is responsible for translating the `WM_KEYDOWN` event to a `WM_CHAR` event, so one needs to "simply" not call this function if the key down event was handled. However there's a problem: `TranslateMessage` is called before the `DispatchMessage` call which dispatches the message to the `WindowImpl.

To get around this, add a `PreProcessMessage` which can be used to handle key down messages outside of the `DispatchMessage` call. This solution broadly comes from WPF, though there the solution is a bit more complicated (it's hooked into using `ComponentDispatcher` events).

Fixes #5849
private protected virtual bool OnPreProcessMessage(in MSG msg)
{
RawInputEventArgs e = null;
uint timestamp = unchecked((uint)GetMessageTime());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not used anywhere.

@@ -189,8 +189,11 @@ public void ProcessMessage()

if (UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0) > -1)
{
UnmanagedMethods.TranslateMessage(ref msg);
UnmanagedMethods.DispatchMessage(ref msg);
if (!WindowImpl.PreProcessMessage(msg))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see one problem with this - my app is running a custom window loop so I might need a way of invoking Avalonia message handling somehow. Since my app is basically doing:

while (PeekMessage(...)) {
  TranslateMessage();
  DispatchMessage()
}

This allows my update loop to still run and process win32 messages when I need to.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're already exposing the message loop in this method, so I guess we also need to expose a public PreProcessMessage method here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That won't help if custom message loop is run by Windows itself at some point, which happens quite frequently. So I think it's better to raise a flag in WindowImpl itself and check if if the next arrived message is WM_CHAR.

Copy link
Member Author

@grokys grokys Jan 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That might be better (and simpler tbh). I didn't go that way because WPF does the PreProcessMessage stuff, but it also has hacks where it sets a flag as well, so I'm guessing they encountered the same thing after implementing the pre-proccessing.

If it's guaranteed that a WM_CHAR is always preceded by a WM_KEYDOWN then I don't think it should cause problems.

I'll close this PR then and open another.

@grokys grokys closed this Jan 14, 2022
@grokys grokys deleted the fixes/5849-textinput-keydown-handed branch January 14, 2022 12:41
grokys added a commit that referenced this pull request Jan 17, 2022
On win32, returning handled from `WM_KEYDOWN` doesn't automatically prevent a `WM_CHAR` message, resulting in #5849.

Fix this by setting a flag after `WM_KEYDOWN` is handled which will make the following `WM_CHAR` message be ignored.

This is the second attempt at fixing this after it was decided that #7351 was not the right approach.

Fixes #5849
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Handling KeyDown events does not prevent TextInput events
4 participants