1

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.

Ashley Williams
  • 317
  • 4
  • 13
  • 1
    @AhsleyWilliams are you wanting the form to be Modal..? is this a MDI application..? also please show what you have tried on your own before expecting others to post answers for you. – MethodMan Mar 12 '15 at 20:22
  • The clicks will always steal the focus. But if you have a handle to the application below you should be able to bring it back. As for click though you need Fuchsia as the TransparencyKey. – TaW Mar 12 '15 at 20:27
  • Its a normal WinForm, its overlays a DirectX9 window. I need to be able to click a button, and my keyboard presses should still be sent the the window underneath. – Ashley Williams Mar 12 '15 at 20:49
  • I am sorry but you dont make sense. You want to click a button on your application and send the key to the other application? Where does the focus thing come in? –  Mar 12 '15 at 21:07
  • It makes sense to me, basically he is adding buttons to the other application without interfering with its keyboard action.. – TaW Mar 12 '15 at 21:17
  • TaW is correct. This is exactly what I am trying to do – Ashley Williams Mar 13 '15 at 11:59

2 Answers2

2

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)

Community
  • 1
  • 1
Cjen1
  • 1,826
  • 3
  • 17
  • 47
0

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);
    }
}
TaW
  • 53,122
  • 8
  • 69
  • 111
  • Its not perfect, but its better than losing focus completely. Just to give you more information, the overlay is for a game. Say I need to hold down W to move forward, this would still stop me moving untll I press W down again. – Ashley Williams Mar 17 '15 at 12:27
  • Hm, that will depend on how the target program handles the events. As you can see I tested with Notepad2 (and also Notepad) and both don't require to press down again, they just keep adding the char I hold down or moving the cursor forward through the text even if I click my button inbetween. But your game may act differently. – TaW Mar 17 '15 at 16:03