How to know if a form is not selected? - c#

I have a lots of problem to distinguish such a simple thing.
I need to know if a form is currently in front of everything, the one which receives key entries.
I have no way to know if it is.
I can check if not minimized. But then it may just be behind other windows, or just not being selected (for example it is openend, desktop is behind, you click on desktop, then you still see the application, but it doesn't receive key inputs).
The property focus is irrevelant for this.
Here is the code
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
if (this.Focused)
{
gotFocus = true;
// never reaches tis
}

Check if window is the current active window.
Code:
using System.Runtime.InteropServices; // To use DllImport
...
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
if ((IntPtr)GetForegroundWindow() == this.Handle)
{
// Do stuff
}
See: Use GetForegroundWindow result in an if statement to check user's current window

Related

Microsoft UI Automation/Get The Item That The User Clicks

I am trying to figure out what item (for example document, web page tab, window, picture, folder) the user has clicked on. I started by using the following code when I detect a global left mouse click:
System.Drawing.Point MousePoint = System.Windows.Forms.Cursor.Position;
AutomationElement AutomationElement = AutomationElement.FromPoint(new System.Windows.Point(MousePoint.X, MousePoint.Y));
Console.WriteLine(AutomationElement.Current.Name);
This seems to work well in most conditions. However, I need to (if possible) get names of documents/images/folders inside Windows Explorer for example. The value returned when I click a document in the right hand pane of Windows Explorer (not the tree view) is "Name". Is there anyway to get the actual document name? For some reason, clicking sub-folders in the tree view returns the name of the folder, which is what I want.
I also notice that the code seems to display the document/image/folder name when clicked if the Windows Explorer view is set to icons (medium, large or extra large). Is there any reason why other views return "Name" or empty string while medium, large and extra large icons return the actual document/image/folder name? Is it to do with the size of the object clicked? I could really do with a way round this if possible?
I apologise, I am new to UI Automation and just really want a way to find the name of the object (file, folder, document, picture, web page tab etc.) that the user has clicked on. Any help anyone could give would be great.
You need to listen to InvokePattern.InvokedEvent UI automation event.
Example
The following example assumes you have an open instance of windows "Calculator" app. Then if you run the application, when you click on any button in Calculator, we handle the click event and show what button has clicked.
[DllImport("user32.dll")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var proc = System.Diagnostics.Process.GetProcessesByName("Calculator")
.FirstOrDefault();
if (proc != null)
{
var mainHwnd = FindWindow(null, "Calculator");
var mainWndElement = AutomationElement.FromHandle(mainHwnd);
Automation.AddAutomationEventHandler(
InvokePattern.InvokedEvent, mainWndElement,
TreeScope.Subtree, (s1, e1) =>
{
var element = s1 as AutomationElement;
MessageBox.Show($"'{element.Current.Name}' clicked by user!");
});
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
Automation.RemoveAllEventHandlers();
base.OnFormClosing(e);
}
You need to add reference to UIAutomationClient and UIAutomationTypes assemblies.
Note
You can easily extend the example and listen to Win32_ProcessStartTrace to detect when Calculator opens. You can see an example to detect when an external process window closes which is using Win32_ProcessStopTrace.
Another option is using SetWinEventHook you can listen to some events from other processes and register a WinEventProc callback method to receive the event when the event raised. Here, you are interested in EVENT_OBJECT_INVOKED event.

how to find the window handle, of the control in application where mouse was clicked

I writing a C# application. I am looking a way to find a window handle of the controls in other applications by just giving the coordinates of the mouse click (or for that matter any coordinates).
Example: On my desktop, I have calculator application opened, notepad opened and some other 3rd party application running. Screen is covered partially by each of them. Now if I run my application and if I click at any location on the screen, I want to be able to find out the window handle of the control (button, textbox, label, tab, frame, etc.) under the mouse irrespective if it was clicked on a button in calculator, File menu in notepad, or some other control in the 3rd party application. It is similar to the functionality we get from Spy++.
BTW, this has already been done for you, sounds like all you need is to clone the repo then customize to your hearts content.
I don't think Global Hooks would be necessary.
You should be able to use any number of methods to get cursor position, hooking is just going to complicate things. For example, you can try the following:
using System;
using System.Windows;
using System.Windows.Input;
using System.Runtime.InteropServices;
namespace Namespace1
{
class Class1
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetCursorPos(ref Win32Point pt);
[StructLayout(LayoutKind.Sequential)]
internal struct Win32Point
{
public Int32 X;
public Int32 Y;
};
public static Point GetMousePosition()
{
Win32Point w32Mouse = new Win32Point();
GetCursorPos(ref w32Mouse);
return new Point(w32Mouse.X, w32Mouse.Y);
}
}
}
Then you just need a few Pinvoke signatures.
Namely, WindowFromPoint and EnumChildWindows.
Refer to "Enumerating Windows/Controls of another application from .Net".
Hope that helps.
Good luck.
Use Windows hook for mouse events (like oleksa said) then this PInvoke to get the foreground window : http://www.pinvoke.net/default.aspx/user32.getforegroundwindow
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
void yourFonction(){
[...]
IntPtr handleTopMostWindow = GetForegroundWindow();
}
you just need to call this method in your code to retrieve the window's foreground handle :
you have to set global Windows hook for mouse events. This will cause yours application to get mouse (or keyboard) clicks in foreign windows.
Please find this article on code project as sample C# wrapper on Windows API. Windows API functions are listed in the article too

RichTextBox syntax highlighting in real time--Disabling the repaint

I'm creating a function that takes a RichTextBox and has access to a list of keywords & 'badwords'. I need to highlight any keywords & badwords I find in the RichTextBox while the user is typing, which means the function is called every time an editing key is released.
I've written this function, but the words and cursor in the box flicker too much for comfort.
I've discovered a solution--to disable the RichTextBox's ability to repaint itself while I'm editing and formatting its text. However, the only way I know to do this is to override the "WndProc" function and intercept (what I've been about to gather is) the repaint message as follows:
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == 0x00f) {
if (paint)
base.WndProc(ref m);
else
m.Result = IntPtr.Zero;
}
else
base.WndProc(ref m);
}
Where the boolean 'paint' is set to false just before I start highlighting and to true when I finish. But as I said, the function I make must take in a RichTextBox; I cannot use a subclass.
So, is there a way to disable the automatic repainting of a RichTextBox 'from the outside?'
It is an oversight in the RichTextBox class. Other controls, like ListBox, support the BeginUpdate and EndUpdate methods to suppress painting. Those methods generate the WM_SETREDRAW message. RTB in fact supports this message, but they forgot to add the methods.
Just add them yourself. Project + Add Class, paste the code shown below. Compile and drop the control from the top of the toolbox onto your form.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class MyRichTextBox : RichTextBox {
public void BeginUpdate() {
SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)0, IntPtr.Zero);
}
public void EndUpdate() {
SendMessage(this.Handle, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero);
this.Invalidate();
}
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
private const int WM_SETREDRAW = 0x0b;
}
Or P/Invoke SendMessage directly before/after you update the text.
I haven't accumulated enough points to amend Hans' recommendation. So I added this Answer to mention that it may be necessary to request a repaint by calling InvalidateRect. Some Begin/End Update implementations do this automatically upon the final release of the update lock. Similarly in .Net, Control.Invalidate() can be called which invokes the native InvalidateRect function.
MSDN: Finally, the application can call the InvalidateRect function to cause the list box to be repainted.
See WM_SETREDRAW
Your best bet to accomplish what you are trying to do is to create a multithreaded application. You'll want to create one thread that checks the text against your list. This thread will put any instances it finds into a queue. You'll also want to create another thread that does the actual highlighting of the words. Because you'll need to use BeginInvoke() and Invoke() to update the UI, you'll want to make sure you throttle the rate at which this gets called. I'd so no more then 20 times per second. To do this, you'd use code like this:
DateTime lastInvoke=DateTime.Now;
if ((DateTime.Now - lastInvoke).TotalMilliseconds >=42)
{
lastInvoke=DateTime.Now;
...Do your highlighting here...
}
This thread will check your queue for words that need to be highlighted or re-highlighted and will constantly check the queue for any new updates. Hope this makes sense!

Refer to active Window in WPF?

How can I refer to active Window of WPF application in C#, using something like ActiveForm property in WinForms?
One possible way would be to scan the list of open windows in the application and check which one of them has IsActive = true:
Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
Not sure if there may be more than one active window if, for example, there's a modal dialog showing, in which case, the owner of the dialog and the dialog itself might be active.
There is better way to do this using PInvoke. Aviads answer is not working all the time (there are some edge cases with dialogs).
IntPtr active = GetActiveWindow();
ActiveWindow = Application.Current.Windows.OfType<Window>()
.SingleOrDefault(window => new WindowInteropHelper(window).Handle == active);
One must include following import first:
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
I know this is a bit old question but I think my answer could help someone.
My problem was this: I had a WPF MVVM application and I needed to get my MainWindow instance in the second view, i.e. second view model, in order to set the visibility of title bar button to visible.
This is my solution:
MainWindow window = (MyApp.MainWindow)App.Current.MainWindow;
window.btnSearch.Visibility = System.Windows.Visibility.Visible;
Hope this would help someone.
I have problems With this way "Application.Current.Windows.OfType().SingleOrDefault(x => x.IsActive);" specialy because I was building an aplication with a main Window then i had problems when the main window was selected. I resolve it creating this:
In some base class or App.xaml.cs create this:
public static Window ActivatedWindow {get;set;}
Then put in your base class deriving Window or all of your Window's Activate Event:
First Option - personal Window Base Class:
public class MetroToolWindowBase
{
public MetroToolWindowBase()
{
Activated += new EventHandler(MakeActive);
}
private void MakeActive(object sender, EventArgs e)
{
App.ActivatedWindow= this;
}
}
Second Option- In Activated Event of Windows:
private void XWindow_Activated(object sender,EventArgs e)
{
App.ActivatedWindow= this;
}
Another way to do it is to use the native GetActiveWindow function from user32.dll.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetActiveWindow();
To convert it to an actual WPF Window:
IntPtr handle = GetActiveWindow();
HwndSource hwndSource = HwndSource.FromHwnd(handle);
var window = hwndSource?.RootVisual as Window;
If hosting a WPF Window in a WinForms app, WindowInteropHelper should be used. This makes for example the Window owner work correctly:
var wih = new WindowInteropHelper(window)
{
Owner = GetActiveWindow()
};
I edited my old answer because the edge case I encountered disappeared after a Visual Studio update, but it can be checked from answer history. I encountered an issue there where I was getting null for active window in certain circumstances while debugging.

Determine Whether Program is the Active Window in .NET

I have a C#/.NET app and I want to implement the following behavior:
I have a popup menu. Whenever the user clicks on anything within the application that is not the popup menu, I want the popup menu to close.
However, whenever a user is not in the application I don't want anything to happen.
I'm trying to manage this through the LostFocus event, but I'm having trouble determining whether my application is the active window. The code looks something like this.
private void Button_LostFocus(object sender, System.EventArgs e)
{
if (InActiveWindow()) {
CloseMenu()
}
else {
// not in active window, do nothing
}
}
What I need to know is how to implement the InActiveWindow() method.
You could P/Invoke into GetForegroundWindow(), and compare the HWND returned to the application's form.Handle property.
Once you have the handle, you can also P/Invoke GetAncestor() to get the root owner window. This should be the handle of your application's main, startup window, if this is in your application.
I stumbled upon your question while working on a project and based on Reed Copsey's answer, I wrote this quick code which seems to do the job well.
Here's the code:
Public Class Form1
'''<summary>
'''Returns a handle to the foreground window.
'''</summary>
<Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetForegroundWindow() As IntPtr
End Function
'''<summary>
'''Gets a value indicating whether this instance is foreground window.
'''</summary>
'''<value>
'''<c>true</c> if this is the foreground window; otherwise, <c>false</c>.
'''</value>
Private ReadOnly Property IsForegroundWindow As Boolean
Get
Dim foreWnd = GetForegroundWindow()
Return ((From f In Me.MdiChildren Select f.Handle).Union(
From f In Me.OwnedForms Select f.Handle).Union(
{Me.Handle})).Contains(foreWnd)
End Get
End Property
End Class
I didn't have too much time to convert it to C# as I'm working on a project with a deadline in 2 days but I believe you can quickly do the conversion.
Here is the C# version of the VB.NET code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
///<summary>Gets a value indicating whether this instance is foreground window.</summary>
///<value><c>true</c> if this is the foreground window; otherwise, <c>false</c>.</value>
private bool IsForegroundWindow
{
get
{
var foreWnd = GetForegroundWindow();
return ((from f in this.MdiChildren select f.Handle)
.Union(from f in this.OwnedForms select f.Handle)
.Union(new IntPtr[] { this.Handle })).Contains(foreWnd);
}
}
}
It seems like the biggest reason this is tricky is because the popup loses focus before the main form is deactivated, so the active window will always be in the application at the time of this event. Really, you want to know whether it will still be the active window after the event is over.
You could set up some kind of scheme where you remember that a popup is losing focus, set aside the fact that you will need to close it, and in the LostFocus or Deactivate event of the application's main form cancel the note that tells you you need to close it; but the problem is when will you process the note?
I'm thinking it might be easier, at least if the popup is a direct child of the main form (which I suspect in your case it may be) to hook the Focus or maybe even Click event of the main form and use it close the popup if it is open (perhaps by scanning its list of child forms for any that implement an ICloseOnLostFocus interface, so that the popup will have a chance to participate in the decision and do anything else it needs to do).
I wish I knew of a better document explaining what all these events actually mean and how they are sequenced with respect to one another, MSDN leaves a lot to be desired in describing them.

Categories

Resources