简体   繁体   中英

How can I determine when my application's console window gets or loses focus?

Is there a simple way to do this? Or at the very least check if the console is currently in focus?

Imagine something like a game (thats not the case here but the analogy holds) - it would be useful if it could pause automatically. I need something similar.

If the window you were interested in were not a console window, this would have been very simple to do by just tapping into the appropriate focus event. But console windows don't have focus events, so the easy way out is not available here.

What you can do is set up an event handler to receive WinEvents generated by the UI Automation services. An event is generated whenever the window focus changes; you can get the HWND of the newly focused window and compare it to that of your console window. If they match, you just got focus; if they don't, you don't have focus (either just lost it or never had it to begin with).

The most convenient way to tap into UI Automation is through the System.Windows.Automation namespace. You can set up the event handler with AddAutomationFocusChangedEventHandler , which will give you an instance of AutomationFocusChangedEventArgs from which you can determine which window has received focus.

Here's some sample code:

AutomationFocusChangedEventHandler focusHandler = OnFocusChange;
Automation.AddAutomationFocusChangedEventHandler(focusHandler);
MessageBox.Show("Listening to focus changes");
Automation.RemoveAutomationFocusChangedEventHandler(focusHandler);

where OnFocusChange is:

void OnFocusChange(object source, AutomationFocusChangedEventArgs e)
{
    var focusedHandle = new IntPtr(AutomationElement.FocusedElement.Current.NativeWindowHandle);
    var myConsoleHandle = Process.GetCurrentProcess().MainWindowHandle;

    if (focusedHandle == myConsoleHandle)
    {
        // ...
    }
}

Note that I am assuming the console is your process's main window for simplicity; if that's not the case, you need to get a HWND to the console window some other way.

Also note that in order to receive automation events, your process must be running a message loop (in this case also known as a "dispatcher loop"), which in turn requires a thread being dedicated to running it. In the example above this happens automatically when MessageBox.Show is called, but in the general case you will have to take proper care of it.

I can't add a comment so I'm just going to have to post an answer. You can test the theory posted by DJ KRAZE like this:

    /// <summary>Returns true if the current application has focus, false otherwise</summary>
public static bool ApplicationIsActivated()
{
    var activatedHandle = GetForegroundWindow();
    if (activatedHandle == IntPtr.Zero) {
        return false;       // No window is currently activated
    }else{
Console.WriteLine("Application is focused!"); 
}

    var procId = Process.GetCurrentProcess().Id;
    int activeProcId;
    GetWindowThreadProcessId(activatedHandle, out activeProcId);

    return activeProcId == procId;
}


[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);

So if it doesn't return false, then it will print "Application is focused!" in the application. You can always add something where "return false" is to do something when it's not focused as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM