0
votes

I have a Window with a TextBox. The cursor is inside the TextBox. If I press a key, then I receive a message in WndProc (for KeyUp and KeyDown). But if I set e.Handled = true in the KeyUp and KeyDown events, then I don't receive any key messages:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        var textBox = new TextBox();
        textBox.KeyDown += TextBox_KeyDown;
        textBox.KeyUp += TextBox_KeyUp;
        Content = textBox;
        (PresentationSource.FromVisual(this) as HwndSource).AddHook(WndProc);
    }

    private void TextBox_KeyDown(object sender, KeyEventArgs e)
    {
        e.Handled = true;
    }

    private void TextBox_KeyUp(object sender, KeyEventArgs e)
    {
        e.Handled = true;
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        Debug.WriteLine(msg + " " + wParam);
        return IntPtr.Zero;
    }
}

Is it possible to receive a PreviewKeyDown/PreviewKeyUp event in WndProc?

2
e.Handled = true means, by definition, that you have handled it and therefore Windows does not process it further. It would be more helpful if you gave some context as to what you want to ultimately achieve.Dax Pandhi
Yes, I know, but key preview events will still received, you can test it: textBox.PreviewKeyDown += (ss, ee) => { Debug.WriteLine("PreviewKeyDown"); }; textBox.PreviewKeyUp += (ss, ee) => { Debug.WriteLine("PreviewKeyUp"); }; But why these events are not received in WndProc?Jotrius
AFAIK, the Preview* events are internal to WPF and not broadcasted since they would not have much meaning to external applications - including Windows itself.Dax Pandhi
Ok, but is it possible to receive key events before the TextBox it handled (with Window Messages)?Jotrius
You would need to create hook to intercept all the messages. WPF does not expose hWnd for individual controls. You should look into ManagedWinApi to create a hook. If your current code is not working, then it may be that the WndProc is being broadcast AFTER the messages have been processed. By using win32 api, you would need to create a higher priority hook where you get the messages before the WPF window itself.Dax Pandhi

2 Answers

4
votes

There are tons of way to intercept key messages. You don't even need any library for this. Using pure Win32 API is OK but if you want simplicity, try handling the ThreadPreprocessMessage event of ComponentDispatcher:

ComponentDispatcher.ThreadPreprocessMessage += (ref MSG m, ref bool handled) => {
            //check if WM_KEYDOWN, print some message to test it
            if (m.message == 0x100)
            {
                System.Diagnostics.Debug.Print("Key down!");
            }
        };

The event is able to receive any key messages before it is actually sent to your window. So it's what you want in this case if you want to handle raw messages (instead of handling PreviewKeyDown, ...).

The AddHook method allows to add some hook proc for the window but it's really limited in WPF (while the equivalent WndProc protected method of Form in winforms can intercept much more messages).

0
votes

Try using ManagedWinApi. You can install it with NuGet.

PM> Install-Package ManagedWinapi

For extensive examples of keyboard and other msg interception: http://mwinapi.sourceforge.net/

Another alternative is https://easyhook.github.io/

Both libraries are well documented.