2

I am making an application for personal use where the stylus can be used to draw on the current screen but the normal use (with mouse) won't be interrupted.

Currently, I am trying to use WS_EX_TRANSPARENT to set the window to allow mouse events through, but it seems like that stylus events also get passed through without being captured.

Is there any other method I can use to pass through mouse/keyboard events while still allowing stylus events? Here is what my program looks like so far:

Example picture

David Diaz
  • 148
  • 1
  • 12
  • What do you mean when you say "the stylus can be used to draw on the current screen but the normal use (with mouse) won't be interrupted"? Are you trying to write a WPF application that responds _only_ to the stylus, and ignores all mouse and keyboard events? – Steven Rands Mar 05 '15 at 09:27
  • Yes, that's exactly what I'm trying to do! – David Diaz Mar 05 '15 at 11:04

1 Answers1

2

Disable the RealTimeStylus for WPF Applications on MSDN states:

[...] (WPF) has built in support for processing Windows 7 touch input [...] Windows 7 also provides multi-touch input as Win32 WM_TOUCH window messages. These two APIs are mutually exclusive on the same HWND.

This seems to imply that, for a given window, you can receive stylus events or touch events but not both. As you do want to handle the stylus events this means you don't need to bother filtering the touch events. That just leaves the mouse and keyboard.

At first I thought you might be able to use a custom window procedure (WndProc) and filter-out the mouse and keyboard messages. However, the WndProc (when used in WPF) is really just a notification mechanism and you can't block the received messages.

I found a Windows API called BlockInput that supposedly "Blocks keyboard and mouse input events from reaching applications". However from the docs this appears to be system-wide not app-specific so may not be any use to you.

The only other way I can think of is to use a low-level keyboard or mouse hook. This requires some P/Invoke but it's not too difficult. These hooks allow you to register callback functions that get called when keyboard and mouse events are raised. The advantage is that you can prevent those events from propagating and effectively "swallow" them, which sounds like what you need.

I don't really like posting an answer that basically says "do a search for ..." but the amount of code involved is non-trivial and has been posted in numerous places both on Stack Overflow and elsewhere, so: try doing a search for low level keyboard hook c# wpf and you should find some code that might help!

One thing you may have trouble with even if you go down this route is focus. As soon as your "invisible" topmost window gets a stylus message that it responds to, I'm presuming focus will switch to your WPF application, thus "stealing" focus from whatever application was being used prior. You might be able to use P/Invoke again to set the window style flags of your main window to prevent this (as per the accepted answer to this SO question).


ORIGINAL ANSWER

You can override the appropriate keyboard, mouse and touch Preview... event handler methods of the Window and mark them as handled. This has the effect of stopping child controls from receiving those events.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        e.Handled = true;
        base.OnPreviewKeyDown(e);
    }

    protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
    {
        e.Handled = true;
        base.OnPreviewMouseDown(e);
    }

    protected override void OnPreviewMouseMove(MouseEventArgs e)
    {
        e.Handled = true;
        base.OnPreviewMouseMove(e);
    }

    protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)
    {
        e.Handled = true;
        base.OnPreviewMouseWheel(e);
    }

    protected override void OnPreviewTouchDown(TouchEventArgs e)
    {
        e.Handled = true;
        base.OnPreviewTouchDown(e);
    }

    protected override void OnPreviewTouchMove(TouchEventArgs e)
    {
        e.Handled = true;
        base.OnPreviewTouchMove(e);
    }
}

I've done the basic keyboard, mouse and touch events here. In a simple app test it seemed to do the trick and I assume it would still let stylus events through (I don't have a stylus I can test with).

You may have to experiment with which events need to be handled like this. I only did KeyDown for example, not KeyUp as I presume the latter is irrelevant without the former. I may also have implemented some that didn't need to be handled, and I'm not sure the calls to the base methods are needed either. As I say, experiment until you get something that works for you.

Community
  • 1
  • 1
Steven Rands
  • 5,160
  • 3
  • 27
  • 56
  • The problem with this is that the events don't get passed through to the windows behind. When I set WS_EX_TRANSPARENT all mouse events get passed to the window behind while it still renders on top (with Topmost). In the screenshot you can see how I would draw using the stylus but I still want the user to be able to interact with their computer using the mouse & keyboard – David Diaz Mar 06 '15 at 05:58
  • @DavidDiaz Oh, I get what you're trying to accomplish now. I've updated my answer with some alternate suggestions. – Steven Rands Mar 06 '15 at 10:24
  • Cheers! I guess that's the best source of information I can get, the problem seems more complicated than it first looks. Thanks for the help! – David Diaz Mar 06 '15 at 22:17
  • @DavidDiaz you found the way to solve that? Any reference please? I'm in the same point, using WS_EX_TRANSPARENT I can't get stylus events. – Juan Garcia Jul 21 '15 at 15:56
  • @jgd Sorry, I gave up on it :( Couldn't get it to work – David Diaz Jul 23 '15 at 00:23