Ashley Williams
Ashley Williams

Reputation: 327

How to click through a WinForm, without taking focus?

I cant find any information for this...

Basically I have a TopMost WinForm in C# that is an overlay for another application.

The overlay has buttons that I need to be able to press without stealing focus from the other application.

Is this possible, as I can't find any relative information.

Upvotes: 1

Views: 1786

Answers (2)

TaW
TaW

Reputation: 54433

Here is a solution that is working for me:

It identifies the target program by its title or parts of it and after each Button click it sets the target to be the foreground window again.

I can type into notepad, click a Button and type on..

I start by making the Form click-through.

You may want to do a lot more styling, maybe maximize, remove the control/min/max boxes and the title or even grab the target's position and size and overlay just the target window. This way you can make completely unobtrusive adornments to the target.

(I did that once because the target didn't treat touch screens right; so I made an overlay with holes in its region where the non-touch-defunct controls were. Nobody can even notice that the overlay is there!)

I write a few status info into to the output console..

Instead of the MainWindowTitle you could also use the ProcessName to identify the target. You can also incorporate code to re-establish the process after an error, like the user closing and restarting the target app..

using System.Runtime.InteropServices;
using System.Diagnostics;
...
public partial class Form1 : Form
{

    [DllImport("user32.dll")]
    static extern bool SetForegroundWindow(IntPtr hWnd);

    string targetTitle = "Notepad2";
    Process theProcess = null;

    public Form1()
    {
        InitializeComponent();
        // make the form clickthrough..
        TransparencyKey = Color.Fuchsia;
        BackColor = TransparencyKey;
        // find and keep a reference to the target process
        theProcess = findProcess(targetTitle);
        // our overlay should stay on top
        TopMost = true;
    }


    Process findProcess(string processTitle)
    {
        Process[] processList = Process.GetProcesses();
        return processList.FirstOrDefault(
               pr => pr.MainWindowTitle.ToLower().Contains(targetTitle.ToLower()));
    }


    void setActive(Process theProcess)
    {
        if (theProcess == null)
        { Console.WriteLine( "Process " + targetTitle + " not found";) return; }
        bool ok = SetForegroundWindow(theProcess.MainWindowHandle);
        Console.Write("Process " + theProcess.ProcessName + " (" + 
                       theProcess.MainWindowTitle + +  ok ? " OK." : " not OK!" );
    }

    private void button1_Click(object sender, EventArgs e)
    {
        // do your stuff..
        Console.WriteLine("Testing Button 1");

        // done: bring the target process back:
        setActive(theProcess);
    }
}

Upvotes: 0

Cjen1
Cjen1

Reputation: 1746

You could store the mouse position:

Point point = Cursor.Position;

and then use an area with no controls in it to change the focus back to the DirectX9 window,

moving the cursor back to the original position before clicking again? That might work.

The only issue is that the button would still be there so you would need some way of getting it to click to the window rather than the button.

e.g.

Point p = Cursor.Position;
Cursor.Position = new point(x,y);
mouse(leftClick);
Cursor.Position = p;
mouse(leftClick);

the mouse(leftclick) method is here.

The other way to do this would be to track cursor position separately and then on each click, check if the click is within any controls and if so then run that method;

(Please tell me in the comments if there is a way to do this more efficiently as it would actually be quite useful to know)

Upvotes: 1

Related Questions