this question is about a tooltip that you can implement very easy in order
to track mouse location via it's coordinates
the only problem for me is to add the ability to track the coordinates on a specific
window after setting it to foreground ... and it's not a form , but a 3rd party
application .
the code which works for me on the visual studio windows form is
ToolTip trackTip;
private void TrackCoordinates()
{
trackTip = new ToolTip();
this.MouseMove += new MouseEventHandler(Form1_MouseMove);
}
void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
String tipText = String.Format("({0}, {1})", e.X, e.Y);
trackTip.Show(tipText, this, e.Location);
}
//thats a code i have seen somewhere on the web and then again after some more googling
found the msdn source at the url :
msdn source url
so the question remains if you'll be kind to answer :
how do i get tool tip coordinates of a 3rd party (other than Vs winform window)
subsclass the target window and listen for WM_MOUSEMOVE messages.
Or
Use a timer and grab the mouse screen coordinates.
You need to use one of the following (as it is explained in this question):
1.Using Windows Forms. Add a reference to System.Windows.Forms
public static Point GetMousePositionWindowsForms()
{
System.Drawing.Point point = Control.MousePosition;
return new Point(point.X, point.Y);
}
2.Using Win32
[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);
}
Related
I encountered a problem in WPF (C#), I need to position a popup on a certain point within the parent window.
I get the parent position with Application.Current.MainWindow.Left and Application.Current.MainWindow.Top, it works as long as I don't move the window from one monitor to the other with the Windows shortcut Windows + Shift + ◄/►. If I use the shortcut the properties stay the same as they were before moving the window.
The window has to be WindowState.Maximized, it works if it is not maximized.
I also tried using Window.GetWindow(this) instead of Application.Current.MainWindow, result is the same.
It seems as if the positionchanged event doesn't occur for the Application.Current.MainWindow and it doesn't update the Left and Top properties.
I didn't find anything on this on SO or Google.
A workaround, hint or solution are greatly appreciated.
Try to use this:
WindowInteropHelper windowInteropHelper = new WindowInteropHelper(Application.Current.MainWindow);
Screen screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle);
The Screen Bounds property provides the coordinates of the whole window and the WorkingArea the boundaries of the area without titlebar and docked windows.
You should use the win32 API to retrieve the information you want as the events exposed by .NET aren't enough to detect this scenario.
There are two things you have to do:
Listen to the WndProc message that corresponds to a window movement (full list here). The one we want is WM_MOVE and is equal to 0x0003. See this thread for details.
Be able to determine the real location of the Window even when it's in Maximized state, which we can do by using the GetWindowRect method. See this thread for details.
Here would be the assembled code that prints the top-left location of your Window when it is moved, including using the shortcut you describe.
public partial class MainWindow : Window {
HwndSource source;
const short WM_MOVE = 0x0003;
public MainWindow() {
InitializeComponent();
// Loaded event needed to make sure the window handle has been created.
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
// Subscribe to win32 level events
source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
if (msg == WM_MOVE) {
Console.WriteLine("Window has moved!");
GetWindowRect(new HandleRef(this, new WindowInteropHelper(this).Handle), out RECT rect);
Console.WriteLine("New location is " + (rect.Left, rect.Top));
}
return IntPtr.Zero;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
}
I am currently trying the recreate the Docking Panel/forms of visual studio. I want to apply the same system to a different project to handle different window views, but first I want to recreate it.
So far I've been switching the MDiParent property between the MainForm and null, but haven't been able to recreate the smooth transition seen in Visual Studio. It's always janky and half the time I find out the MouseUP event I tie the switch to rarely works (I'm currently using the Location change event).
To move the form, I've been using this handy code block I found;
#region Form Movement
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
private void MoveForm()
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
#endregion
And to Handle the Dock/UnDock, I'm using this code;
private void DockToMain()
{
Point f = Form1.Main.PointToClient(this.Location);
Point newP = new Point(f.X - 25, f.Y - 51);
try { this.MdiParent = Form1.Main; } catch { }
this.Location = newP;
}
private void UnDockFromMain()
{
Point f = Form1.Main.PointToScreen(this.Location);
Point newP = new Point(f.X + 25, f.Y + 51);
try { this.MdiParent = null; } catch { }
this.Location = newP;
}
Is there a way to recreate the Dock Panel/Form in Winforms? Am I even on the right track here, or is there a better way I'm not seeing?
Just to Answer this, Will is Completely Right. I Somehow got it to kind of work, but it's far too glitchy to be of any use. Just Switch to WPF (it isn't too difficult to make the jump from WinForms) and use the Avalon dock control from xceedsoftware's " Extended WPF Toolkit"
I'm using .Net c# winforms. I want to move my mouse over another application and see the cusor X,Y position as I move the mouse over it's interface. Displaying the X,Y on my forms title bar is ok. I want to see the X,Y location for a specific spot on this app's form.
The reason I want to do this is because there are controls on this app's interface that I can mouse click on to turn a knob, one mouse click per knob turn. I want to write an app that I can position the mouse cursor to that specific X,Y position on this app form and then do a software mouse click to turn that same knob one turn. But I want to do this from my app, kind of like remote control I guess you could say. The other app knobs responds to mouse clicks when you are over the correct X,Y location.
Thanks for any pointers in the right direction.
Add a Label to your Form and wire up its MouseMove() and QueryContinueDrag() events. Use the WindowFromPoint() and GetAncestor() APIs to get a handle to the main window containing the cursor position, then use the ScreenToClient() API to convert the screen coordinate to the client coordinate of that Form. Run the app and left drag the Label in your Form over to the knobs in your target application. The title bar should update with the client coords of the current mouse position relative to the app it is over:
private const uint GA_ROOT = 2;
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(int xPoint, int yPoint);
[System.Runtime.InteropServices.DllImport("user32.dll", ExactSpelling = true)]
private static extern IntPtr GetAncestor(IntPtr hwnd, uint gaFlags);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);
private void label1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
label1.DoDragDrop(label1, DragDropEffects.Copy);
}
}
private void label1_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
Point pt = Cursor.Position;
IntPtr wnd = WindowFromPoint(pt.X, pt.Y);
IntPtr mainWnd = GetAncestor(wnd, GA_ROOT);
POINT PT;
PT.X = pt.X;
PT.Y = pt.Y;
ScreenToClient(mainWnd, ref PT);
this.Text = String.Format("({0}, {1})", PT.X.ToString(), PT.Y.ToString());
}
Disclosure: This is my first WPF app. Please be accepting of my ignorance.
In my WPF application, I have a ControlTemplate with a Grid and various children beneath that. In the code-behind, I am dynamically adding a custom ContentControl element using the ControlTemplate.
When the new Control is created, it is intended to capture the mouse and allow dragging capabilities. The code for the dragging calculations is fine if the Grid has already been loaded on the window and I have the start Point set to MouseButtonEventArgs.GetPosition(window). But when the event is fired when the Grid is initially loaded, the Point is equal to the inverse position of the window. E.g. if my window is at (350,250), my start Point is (-350,-250).
private void GridLoaded(object sender, EventArgs e) { // fires MouseLeftButtonDown event for grid}
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
...
m_start = e.GetPosition(this); // 'this' is the current window; returns the inverse coordinates of 'this'
...
}
Is there a more appropriate method to get the x,y coordinates of my mouse position. I could work with screen coordinates if necessary, but all code I've found uses what would be PointToScreen(m_start). This is useless as m_start is incorrect.
Any help is greatly appreciated.
Can you try, I snagged this some time ago and it worked well for me:
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public static implicit operator Point(POINT point)
{
return new Point(point.X, point.Y);
}
}
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out POINT lpPoint);
public static Point GetCursorPosition()
{
POINT lpPoint;
GetCursorPos(out lpPoint);
//bool success = User32.GetCursorPos(out lpPoint);
// if (!success)
return lpPoint;
}
Problem
When you search for such question using google you get a lot of hits but all solutions assume you have at least one window.
But my question is just like I phrased it -- not assumptions at all. I can have a window, but I could have zero windows (because I didn't even show one or I just closed the last one). So in short the solution cannot rely on any widget or window -- the only thing is known, is there is a desktop (and app running, but it does not have any windows).
So the question is -- how to get the mouse position?
Background
I would like to show windows centered to mouse position. There is no such mode in WPF (there are only center to owner, or center to screen) so I have to do it manually. The missing piece is mouse position.
Edits
Thank you all, so now I have the first part of the solution -- raw position. Now there is a problem how to convert the data for WPF. I found such topic:
WPF Pixels to desktop pixels
but again, it assumes having some window.
Then I googled more and I found solution:
http://jerryclin.wordpress.com/2007/11/13/creating-non-rectangular-windows-with-interop/
the code includes class for scaling up/down coordinates relying only on info about desktop. So joining those two pieces, I finally get the solution :-). Thanks again.
Getting the Screen Coordinates:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out POINT lpPoint);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}
private void WritePoint(object sender, RoutedEventArgs e)
{
POINT p;
if (GetCursorPos(out p))
{
System.Console.WriteLine(Convert.ToString(p.X) + ";" + Convert.ToString(p.Y));
}
}
Converting Pixels to WPF Units:
[DllImport("User32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
private Point ConvertPixelsToUnits(int x, int y)
{
// get the system DPI
IntPtr dDC = GetDC(IntPtr.Zero); // Get desktop DC
int dpi = GetDeviceCaps(dDC, 88);
bool rv = ReleaseDC(IntPtr.Zero, dDC);
// WPF's physical unit size is calculated by taking the
// "Device-Independant Unit Size" (always 1/96)
// and scaling it by the system DPI
double physicalUnitSize = (1d / 96d) * (double)dpi;
Point wpfUnits = new Point(physicalUnitSize * (double)x,
physicalUnitSize * (double)y);
return wpfUnits;
}
Putting both together:
private void WriteMouseCoordinatesInWPFUnits()
{
POINT p;
if (GetCursorPos(out p))
{
Point wpfPoint = ConvertPixelsToUnits(p.X, p.Y);
System.Console.WriteLine(Convert.ToString(wpfPoint.X) + ";" + Convert.ToString(wpfPoint.Y));
}
}
Two options:
Use System.Windows.Forms.Control.MousePosition, or p/invoke
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern bool GetCursorPos([In, Out] NativeMethods.POINT pt);
The first option already does the p/invoke for you. I'm not entirely sure it requires you have some UI splashed up, but I don't think so. Yes, its winforms and not wpf, but it really doesn't have anything to do with where its located at.
If you want to skip any dependencies on system.windows.forms.dll then check out more information about the second on pinvoke.net.
I stumbled over that thread while looking for a solution for the same problem. In the meantime, I found PointToScreen, which does not require any P/Invoke. The method is available on any Visual starting .NET 3.0 (and thus UIElement, Control, etc.) and an implementation would look like this:
protected void OnMouseLeave(object Sender, MouseEventArgs e) {
var relativePosition = e.GetPosition(this);
var screenPosition = this.PointToScreen(relativePosition);
}