locked
Making a Window invisible to Mouse Events, IsHitTestVisible="false" not working. RRS feed

  • Question

  • I'm trying to make a borderless, semi-transparent, top-level window that will never receive focus (the mouse events will always pass throuh).  I've been trying to set the IsHitTestVisible property to false, but it isnt' having any effect.  My window declaration looks like this:

    Code Snippet

    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
        x:Class="Patina.Window1"
        x:Name="Cursor_Tracker_Tool"
        Title="ActivityWatcher"
        IsHitTestVisible = "false"
        Width="816" Height="186" Closing="OnClosing" xmlns:Patina="clr-namespace:Patina" Topmost="True" WindowStyle="None" AllowsTransparency="True" Background="#00000000"
    IsEnabled="False" ResizeMode="NoResize">


    Any ideas about how I should get this to work?

    Thanks,
    Justin
    Tuesday, March 4, 2008 11:09 PM

Answers

  • I've figured out how to do this.  The key being the WS_EX_TRANSPARENT flag for the window's extended style.You can set the topmost property like you normally would, then this code takes care of making the window transparent to mouse clicks:


    Code Snippet

    public const int WS_EX_TRANSPARENT = 0x00000020;
    public const int GWL_EXSTYLE = (-20);

    [DllImport("user32.dll")]
    public static extern int GetWindowLong(IntPtr hwnd, int index);

    [DllImport("user32.dll")]
    public static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);

    protected override void OnSourceInitialized(EventArgs e)
    {
    base.OnSourceInitialized(e);

    // Get this window's handle
    IntPtr hwnd = new WindowInteropHelper(this).Handle;

    // Change the extended window style to include WS_EX_TRANSPARENT
    int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
    WinAPI.SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
    }

    Thursday, March 13, 2008 8:25 PM
  • You indend the mouse events will always pass through What?

    Is it another window in your app or dialog window overlapping the main one? In this case you'd better catch all the required mouse events and deliver them to the main one as the overlapped window is not clickable at that time.

    Also the Mouse class got plenty a lot of stuff for handler establishing, look through it also.

    Wednesday, March 5, 2008 9:18 AM
  • Setting IsHitTestVisible will only affect how WPF does hit testing, it cannot affect how on win32 does hit testing, win32 always use pixel hit testing, which means that only if the pixel which gets hit is transparent, win32 will directly hit it through.

    So the best bet you can do is either using full transparent window, or you need to capture all the mouse events, and use SendMessage or PostMessage to deliver those mouse messages to its underlying window.

    Hope this helps
    Thursday, March 6, 2008 6:35 AM

All replies

  • You indend the mouse events will always pass through What?

    Is it another window in your app or dialog window overlapping the main one? In this case you'd better catch all the required mouse events and deliver them to the main one as the overlapped window is not clickable at that time.

    Also the Mouse class got plenty a lot of stuff for handler establishing, look through it also.

    Wednesday, March 5, 2008 9:18 AM
  • Yes, I intend that the mouse events will always pass though, and they will pass through to whatever application is below.  The window is just an informational overlay and is not meant to handle input.  I will take a look at the Mouse class, but looking at the documentation, setting IsHitTestVisible="false" on my window should do everything I am looking for, but it does not work.  Should that work?  Also, overriding the HitTestCore() method in the Window is not working either as it never gets hit.

    Thanks,
    Justin
    Wednesday, March 5, 2008 5:13 PM
  • Setting IsHitTestVisible will only affect how WPF does hit testing, it cannot affect how on win32 does hit testing, win32 always use pixel hit testing, which means that only if the pixel which gets hit is transparent, win32 will directly hit it through.

    So the best bet you can do is either using full transparent window, or you need to capture all the mouse events, and use SendMessage or PostMessage to deliver those mouse messages to its underlying window.

    Hope this helps
    Thursday, March 6, 2008 6:35 AM
  • I've figured out how to do this.  The key being the WS_EX_TRANSPARENT flag for the window's extended style.You can set the topmost property like you normally would, then this code takes care of making the window transparent to mouse clicks:


    Code Snippet

    public const int WS_EX_TRANSPARENT = 0x00000020;
    public const int GWL_EXSTYLE = (-20);

    [DllImport("user32.dll")]
    public static extern int GetWindowLong(IntPtr hwnd, int index);

    [DllImport("user32.dll")]
    public static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);

    protected override void OnSourceInitialized(EventArgs e)
    {
    base.OnSourceInitialized(e);

    // Get this window's handle
    IntPtr hwnd = new WindowInteropHelper(this).Handle;

    // Change the extended window style to include WS_EX_TRANSPARENT
    int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
    WinAPI.SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
    }

    Thursday, March 13, 2008 8:25 PM
  • Nice find! Just what I needed.
    Friday, October 3, 2008 2:54 PM
  • My autoanswer! ,this is the way.
    public static void makeNormal(IntPtr hwnd) 
    { 
       
        int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE); 
       
    Win32.SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle & ~WS_EX_TRANSPARENT); 
    } 
    Monday, January 10, 2011 10:51 AM