How to get mouse position on screen in WPF? - c#

It works within a specific control, but it doesn't work out the specific control.
How to get mouse position and use mouse events independently of any control just directly from screen (without Platform Invoke)?
2 needed points:
Mouse events when mouse is not within a control, but on a screen.
Mouse position when mouse is not within a control, but on a screen.
It should be solved without using Platform Invoke.
Next two don't work:
System.Windows.Input.Mouse.GetPosition(this)
Doesn't get mouse position out a specific control.
System.Windows.Forms.Cursor.Position.X
System.Windows.Forms.Cursor.Position doesn't work because it has no types in a WPF app, but it works in a Windows Forms app.
IntelliSense gets System.Windows.Forms.Cursor.Position, but it doesn't get any type of Position, hence I can't get:
Position.X
Position.Y
and
Point pointToWindow = Mouse.GetPosition(this);
Point pointToScreen = PointToScreen(pointToWindow);
Doesn't get mouse position out a specific control.

Using MouseDown event of a control you can try this:
var point = e.GetPosition(this.YourControl);
EDIT:
You can capture mouse event to a specific control using Mouse.Capture(YourControl); so it will capture the mouse events even if it is not on that control. Here is the link

You can use PointToScreen
Converts a Point that represents the current coordinate system of the
Visual into a Point in screen coordinates.
Something like this:
private void MouseCordinateMethod(object sender, MouseEventArgs e)
{
var relativePosition = e.GetPosition(this);
var point= PointToScreen(relativePosition);
_x.HorizontalOffset = point.X;
_x.VerticalOffset = point.Y;
}
Do note that Mouse.GetPosition returns a Point, and PointToScreen converts the point to the screen coordinate
EDIT:
You can use the Mouse.Capture(SepcificControl);. From MSDN
Captures mouse input to the specified element.

I have little new found,
Code is below, fisrt build and run the Window ,
then just wheel your mouse one time on the window to invoke the endless screen detect of the Mouse Position.
(Thus I didn't find the way to detect mouse event out of the control in the second point of the question, but similar use an endless thread.)
But I just use a little skill to enable Windows.Forms in WPF Project, by simply use the Forms code in pure method, then refer that method in the Event Code Block.
.
Here's the Code:
Add two references to project:
System.Drawing
System.Windows.Forms
Xaml part:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:g="clr-namespace:Gma.UserActivityMonitor;assembly=Gma.UserActivityMonitor"
Title="MainWindow" Height="350" Width="525"
MouseWheel="MainWindow_OnMouseWheel">
<Grid>
<TextBlock Name="TBK" />
</Grid>
</Window>
Class Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void KeepReportMousePos()
{
//Endless Report Mouse position
Task.Factory.StartNew(() =>
{
while(true){
this.Dispatcher.Invoke(
DispatcherPriority.SystemIdle,
new Action(() =>
{
GetCursorPos();
}));
}
});
}
public void GetCursorPos()
{
//get the mouse position and show on the TextBlock
System.Drawing.Point p = System.Windows.Forms.Cursor.Position;
TBK.Text = p.X + " " + p.Y;
}
private void MainWindow_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
//invoke mouse position detect when wheel the mouse
KeepReportMousePos();
}
}

Why complicate things? Just pass null to get screen coordinates:
private void MouseCordinateMethod(object sender, MouseEventArgs e)
{
var screenPos = e.GetPosition(null);
// ...
}

Related

WinUI 3 : Force Mouse Pointer to interact with a User Control, when it "souldn't"

I'm creating a WinUI 3 User Control that -for sake of simplicity- can be described as glorified slider:
Whenever user presses their left click (PointerPressed event), Pointer movement starts being tracked.
Whenever uses releases their left click (PointerReleased event), this tracking stops.
Sample XAML
<UserControl [...] >
<Border Name="MainArea"
PointerPressed="StartCapturing"
PointerReleased="StopCapturing"
PointerMoved="CaptureCoords"
[...] >
<!-- [...] -->
</Border>
</UserControl>
Sample C#
bool _isCapturing = false;
private void CalculateCoords(PointerRoutedEventArgs args){
// max distance is [w,h]. min distance is [0,0]
var h = MainArea.ActualHeight;
var w = MainArea.ActualWidth;
// Coordinates relative to the MainArea element;
var pos = args.GetCurrentPoint(MainArea).Position;
var (x, y) = (pos.X, pos.Y);
// clip 0% - 100%
x = x < 0 ? 0 : (x > w ? w : x);
y = y < 0 ? 0 : (y > h ? h : y);
// convert to percentages
var (x_perc, y_perc) = (x/w, y/h);
// Do stuff with the two percentages
}
public void StartCapturing(object? sender, PointerRoutedEventArgs args){
_isCapturing = true;
CalculateCoords(args);
}
public void CaptureCoords(object? sender, PointerRoutedEventArgs args){
if (!_isCapturing) return;
CalculateCoords(args);
}
public void StopCapturing(object? sender, PointerRoutedEventArgs args){
_isCapturing = false;
CalculateCoords(args);
}
This methodology works fine while the cursor is inside the control. The problem comes when the cursor leaves the element: Movement tracking stops and, if click is released outside of the bounding box, the capturing will continue once the mouse re-enters the bounding box, even without click pressed.
These problems where to be expected. To eliminate them, the only possible solutions I have thought of but don't know how to implement them, are:
Force-Capture Mouse events, even when pointer exits the control
Restrain mouse movement within control's bounding box
Is there a way to do any of these two things?
You can use CapturePointer in StartCapturing.
You typically capture the pointer because you want the current pointer
action to initiate a behavior in your app. In this case you typically
don't want other elements to handle any other events that come from
that pointer's actions, until your behavior is either completed or is
canceled by releasing the pointer capture. If a pointer is captured,
only the element that has capture gets the pointer's input events, and
other elements don't fire events even if the pointer moves into their
bounds. For example, consider a UI that has two adjacent elements.
Normally, if you moved the pointer from one element to the other,
you'd first get PointerMoved events from the first element, and then
from the second element. But if the first element has captured the
pointer, then the first element continues to receive PointerMoved
events even if the captured pointer leaves its bounds. Also, the
second element doesn't fire PointerEntered events for a captured
pointer when the captured pointer enters it.
public void StartCapturing(object sender, PointerRoutedEventArgs args)
{
_isCapturing = true;
CalculateCoords(args);
MainArea.CapturePointer(args.Pointer);
}

How can I get a relative position to my Canvas when the mouse is outside of the application Window in WPF

public MainWindow()
{
InitializeComponent();
_hook = Hook.GlobalEvents();
_hook.MouseMove += DrawMouseMove;
}
private void DrawMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
Point GetMousePos() => Mouse.GetPosition(DrawCanvas);
Point pos = GetMousePos();
CoordinateLabel.Content = $"{Math.Ceiling(pos.X)}, {Math.Ceiling(pos.Y)}px";
//... code down here is draw a shape with pos, a relative position to DrawCanvas
}
I'm using hook for global event, but i stuck at getting relative position to DrawCanvas when the mouse is outside of my application window. The thing I want to achive is just like mspaint, you can still draw shape even when the mouse moved out of the window

WPF C# wrong mouse coordinates

So im trying to get mouse coordinates from a click on an image, and it gives the wrong coordinates. When i move the mouse to draw, the line appears away from the cursor.
This is the code i use to get the mouse coordinates:
private void ponaredek_MouseDown(object sender, MouseButtonEventArgs e)
{
mouseDown = true;
//x1 = System.Windows.Forms.Control.MousePosition;
x1 = new System.Drawing.Point((int)e.GetPosition(this).X, (int)e.GetPosition(this).Y);
}
x1 is of type System.Drawing.Point (i need the point from drawing, to use in emgucv). What do i have to do to correct the cursor location (i drew where the cursor was)
You want to get the mouse position relative to the Image element, not the Window. So replace
e.GetPosition(this)
by
e.GetPosition((IInputElement)sender)
or
e.GetPosition(ponaredek)
if that is the Image element.
It should look like this:
var pos = e.GetPosition((IInputElement)sender);
x1 = new System.Drawing.Point(pos.X, pos.Y);
Also make sure the Image element's Stretch property is set to None.

How can I convert the mouse cursor coordinates when click on pictureBox are to the screen relative mouse cursor coordinates?

In my program I added this code so when I move my mouse all over the screen I will get the mouse cursor coordinates in real time:
Form1 Load:
private void Form1_Load(object sender, EventArgs e)
{
System.Windows.Forms.Timer t1 = new System.Windows.Forms.Timer();
t1.Interval = 50;
t1.Tick += new EventHandler(timer1_Tick);
t1.Enabled = true;;
}
Then the method that get the mouse position:
public static Point GetMousePosition()
{
var position = System.Windows.Forms.Cursor.Position;
return new Point(position.X, position.Y);
}
Then the timer1 tick event:
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = string.Format("X={0}, Y={1}", GetMousePosition().X, GetMousePosition().Y);
}
Then I ran some application and moved the mouse over a specific location on the screen where the application window is and I found this coordinates:
358, 913
Now I have in my program a listBox with items each item present application screenshot. And if I click on the pictureBox for example in this case on the BATTLEFIELD 3 area I get the mouse cursor coordinates according to the pictureBox area.
So I did:
Point screenCoordinates;
Point pictureBoxSnapCoordinates;
private void pictureBoxSnap_MouseDown(object sender, MouseEventArgs e)
{
screenCoordinates = pictureBoxSnap.PointToScreen(e.Location);
pictureBoxSnapCoordinates = e.Location;
}
Now when I click in the pictureBox at the same location as I found the coordinates 358, 913 but on the pictureBox so the results are:
screenCoordinates 435, 724
pictureBoxSnapCoordinates 23,423
The screenCoordinates isn't the same coordinates as I found with the mouse move 358, 913 it's not even close. There is a big difference between 358,913 and 437,724
e.Location is relative to the Control's top left corner. If you want to use e.Location to get the screen coordinates, then you have to first do pictureBoxSnap.PointToScreen(Point.Empty); and then offset by the e.Location.
Also, Cursor.Position returns a Point object, so making a new Point(...) is pointless.
I must add, if you are dealing with images, and you need to interact with mouse, and do any task related with offset, scroll, etc, I recommend you that library, it is open source and have a lot of examples and methods that will help you
https://github.com/cyotek/Cyotek.Windows.Forms.ImageBox

How to fake mouse cursor position in Windows Forms C#?

I have this Windows Forms application with a simple balloon tooltip. Depending on the application's window location on the desktop and the mouse cursor location, the balloon 'tip' (or balloon pointing arrow) may or may not be pointing to the location I want.
For instance, my app snaps to the desktop sides and when it's snapped to the right side, if the mouse cursor is below 100px of the right side, the balloon 'tip' will point to the wrong place. But if the mouse cursor is anywhere else, it will point to the right place.
In this situation I wanted to fake the mouse cursor position (without actually changing the mouse cursor position) to be somewhere else so the the problem wouldn't occur.
Is this possible? How can I achieve this?
private void noteTitleInput_KeyPress(object sender, KeyPressEventArgs e) {
if(e.KeyChar == Convert.ToChar(Keys.Return, CultureInfo.InvariantCulture) && noteTitleInput.Text.Length > 0) {
e.Handled = true;
noteInputButton_Click(null, null);
} else if(!Char.IsControl(e.KeyChar)) {
if(Array.IndexOf(Path.GetInvalidFileNameChars(), e.KeyChar) > -1) {
e.Handled = true;
System.Media.SystemSounds.Beep.Play();
noteTitleToolTip.Show("The following characters are not valid:\n\\ / : * ? < > |",
groupNoteInput, 25, -75, 2500);
return;
}
}
noteTitleToolTip.Hide(groupNoteInput);
}
I'm not quite sure why do you need to set cursor position, because you can set tool tip to appear where you tell it, and not necessarily where the mouse is.
For example:
tooltip1.Show("My tip", controlOnWhichToShow, 15, 15);
would display the tip at upper left corner of the controlOnWhichToShow, 15 points away from edges.
If I misunderstood you, than please specify at which point in time is the mouse position being used.
If you sync the MouseHover event, you can create the Tooltip as veljkoz describes. In this way you can place the tooltip as you like. The code would look smething like this:
protected override void OnMouseHover(EventArgs e)
{
ToolTip myToolTip = new ToolTip();
myToolTip.IsBalloon = true;
// TODO The x and y coordinates should be what ever you wish.
myToolTip.Show("Helpful Text Also", this, 50, 50);
base.OnMouseHover(e);
}
Hope that helps.
In Windows Forms the mouse is captured by the control when the user presses a mouse button on a control, and the mouse is released by the control when the user releases the mouse button.
The Capture property of the Control class specifies whether a control has captured the mouse. To determine when a control loses mouse capture, handle the MouseCaptureChanged event.
Only the foreground window can capture the mouse. When a background window attempts to capture the mouse, the window receives messages only for mouse events that occur when the mouse pointer is within the visible portion of the window. Also, even if the foreground window has captured the mouse, the user can still click another window, bringing it to the foreground. When the mouse is captured, shortcut keys do not work.
More here. Mouse Capture in Windows Forms
You can do what you say with a Class. You can do it in a very simple way.
one create class and
namespace MousLokasyonbulma
{
class benimtooltip : ToolTip
{
[System.Runtime.InteropServices.DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr h, int x, int y, int width, int height, bool redraw);
public benimtooltip()
{
this.OwnerDraw = true;
this.Draw += Benimtooltip_Draw;
}
private void Benimtooltip_Draw(object sender, DrawToolTipEventArgs e)
{
e.DrawBackground();
e.DrawBorder();
e.DrawText();
var t = (ToolTip)sender;
var h = t.GetType().GetProperty("Handle",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var handle = (IntPtr)h.GetValue(t);
var location = new Point(650, 650);
var ss= MoveWindow(handle, location.X, location.Y, e.Bounds.Width, e.Bounds.Height, false);
}
}
}
full Code MyGithup
Example Project image
https://i.hizliresim.com/1pndZG.png
https://i.hizliresim.com/Lvo3Rb.png

Categories