MouseHook, MouseDown and MouseClick split - c#

I have a little problem. I tried to look at google, but it gave me nothing much.
I made a little program that uses global hooks and get mouse coordinates on click. The problem is when I made a second method with MouseDown and when I just click a button, MouseDown method runs too.
So the question is:
How can I split two methods and let them work only separately: when I click, only MouseClick method is triggered, when press and keep down for a while it triggers only MouseDown?
Should I use some timing or what? Just give me a tip what I should try to use.
P.S. Sorry, my English isn't good, it's not my native language.
Here is some code, that I think give the overview.
public void StartRecording()
{
mouseListener = new MouseHookListener(new GlobalHooker());
mouseListener.Start();
mouseListener.MouseClick += new MouseEventHandler(MouseClicked);
mouseListener.MouseDown += new MouseEventHandler(MouseDown);
}
public void MouseClicked(object sender, MouseEventArgs e)
{
MessageBox.Show(String.Format("Mouse was pressed at {0}, {1}",
Control.MousePosition.X.ToString(),
Control.MousePosition.Y.ToString()));
}
public void MouseDown(object sender, MouseEventArgs e)
{
MessageBox.Show(String.Format("Mouse was down at {0}, {1}",
Control.MousePosition.X.ToString(),
Control.MousePosition.Y.ToString()));
}

When you click the mouse both is the case.
MouseClick is as far as i know both MouseDown and MouseUp, where MouseDown will be fired when you press down. And MouseUp will be fired when you release the button..
I think you will have to add some functionality to the MouseDown method which counts how long the mouse was pressed down.. That would be my solution.

In the MouseDown event you should store the current time and coordinates in variables that are global to the class they are in.
Then, you should use the MouseUp event to detect when the mouse button is released. You can then compare the new time and coordinates to the stored ones to see how long the button was pressed and if the mouse moved in that time, and act upon it accordingly.
Alternatively, you could also use the MouseMove event to reset the time and coordinates if required.

As a workaround, instead of hooking to MouseClick, try using MouseUp.
Then on MouseDown save current time in a class level variable (clickTime in the example). On MouseUp check the time again. If the time span is longer then say 3 seconds - do what you wanted to do on mouse down, otherwise - continue with mouse click.
DateTime clickTime;
public void MouseUp(object sender, MouseEventArgs e)
{
if (DateTime.Now - clickTime > someDelayTime)
{
// Do mouse down
}
else
{
// Do mouse click
}
}
public void MouseDown(object sender, MouseEventArgs e)
{
clickTime = DateTime.Now;
}

Related

How to trigger a mousemove event when mousedown in C# Form

I build an UserControl in C# form.
And I use MouseMove event in the event list.
Everything works properly.
Then,I want to detect if right or left button of mouse is pressed.
The MouseEventArgs provide Button status to use.
The issue is when left button on mouse is already pressed somewhere outside the UserControl ,then move the cursor on to the UserControl,MouseMove event just won't trigger.
Is there any solution for this?
This is because the MouseDown has happened somewhere else and therefore the MouseMove of that other place still keeps happening.
This is a good thing so you don't lose the event just because you happen to slip aside, eg from a scrollbar.
If you really want to prevent the good thing happening at that special place you can release the mouse capture that is going on..:
private void theOtherPlace_MouseMove(object sender, MouseEventArgs e)
{
if (! theOtherPlace.ClientRectangle.Contains(e.Location))
{
User32_DLL.ReleaseCapture();
}
}
Using this helper class:
using System.Runtime.InteropServices;
..
public static class User32_DLL
{
[DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
}
Not sure if it is a good idea, though! I for one am always very happy if I can rely on the pressed mousebutton to still work the way it should..
Or you could trigger the MouseMove of the UserControl from the other MouseMove, passing in the UC as sender and a modified MouseEventArgs:
private void theOtherPlace_MouseMove(object sender, MouseEventArgs e)
{
if (! theOtherPlace.ClientRectangle.Contains(e.Location))
{
Point pt = yourUserControl.PointToClient(Control.MousePosition);
if (yourUserControl.ClientRectangle.Contains(pt))
{
yourUserControl_MouseMove(listView1,
new MouseEventArgs(e.Button, e.Clicks, pt.X, pt.Y, e.Delta ) );
}
}
}

Button mouse over ForeColour change

To create a mouse over button I use this code
private void btnCreateAccount_MouseHover(object sender, EventArgs e)
{
btnCreateAccount.ForeColor = Color.Gold;
}
private void btnCreateAccount_MouseLeave(object sender, EventArgs e)
{
btnCreateAccount.ForeColor = Color.Black;
}
The mouse over button works however when I hover over the button there is a good at least 1 second delay. I would think that it should change colour as soon as the mouse is placed over the button and not with a (in my opinion) too long delay.
Is there any way of fixing that code by like refreshing the button or something along those lines? or perhaps someone has a code that works perfectly?
You are handling the Mouse Hover event. This will require the cursor to be still for a short while in order to fire.
The pause required for this event to be raised is specified in milliseconds by the MouseHoverTime property.
This is read only.
Normally if you want the colour to change immediately you should handle the Mouse Enter event:
private void btnCreateAccount_MouseEnter(object sender, EventArgs e)
{
btnCreateAccount.ForeColor = Color.Gold;
}

Detect whether multiple ListView items were selected by dragging

I have a ListView with the View set to LargeIcon.
I specifically need to detect when multiple items were selected by dragging a selection box around them with the mouse.
(For example I don't want to know when items were selected by CTRL + Click)
I thought I could simply do it by keeping track of whether the mouse was down while it was moving which would indicate dragging, then on mouse up if it was a drag then I can set another variable to indicate this.
In my example below mouseDown is set to true, but when I keep the mouse down and move it isDrag is never set to true and I can't see what I'm doing wrong.
(Edit: isDrag becomes true if I remove the if clause which is weird because as I said mouseDown is definitely true).
I realise the code is a little longer than it needs to be but it's for clarity.
bool mouseDown;
bool isDrag;
bool wasDrag;
private void listView1_MouseDown(object sender, MouseEventArgs args)
{
wasDrag = false;
mouseDown = true;
}
private void listView1_MouseMove(object sender, MouseEventArgs args)
{
if (mouseDown)
isDrag = true; // <-- Never becomes true, even though mouseDown is true
}
private void listView1_MouseUp(object sender, MouseEventArgs args)
{
if (isDrag)
wasDrag = true;
mouseDown = false;
isDrag = false;
}
I know it'll be something stupid. Please put me out of my misery.
Alternatively if someone knows of a better was to detect a dragging selection (what's the proper term?) then I'm all ears.
Can you try this:
private void listView1_MouseMove(object sender, MouseEventArgs args)
{
isDrag = mouseDown;
}
I think for some reason, your event listView1_MouseUp still fires, which makes your isDrag variable set to other than the intended value. Try to put breakpoints on both MouseMove and MouseUp events to see the sequence with which they are firing.
After further investigation I've discovered that for a ListView control the MouseMove event will not fire while MouseDown is still occurring and fires immediately after releasing the mouse.
I can only assume that the logic built into this control that allows you to select multiple files by dragging a selection is messing with these events and essentially making them synchronous.
I've put together a basic workaround for this. It's not ideal but it does the job so I thought I'd share.
Basically when the mouse goes down I record the position. When the mouse goes up I check to see if it has moved more than a certain distance in any direction. If it has not I consider it a click, if it has I consider it a drag.
// Records the mouse position on mousedown
int beforeMoveX;
int beforeMoveY;
// How far in pixels the mouse must move in any direction
// before we consider this a drag rather than a click
int moveBounds = 20;
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
// Save the mouse position
beforeMoveX = e.X;
beforeMoveY= e.Y;
}
private void listView1_MouseUp(object sender, MouseEventArgs e)
{
// Did we move more than the bounds in any direction?
if (e.X < (beforeMoveX - moveBounds) ||
e.X > (beforeMoveX + moveBounds) ||
e.Y < (beforeMoveY - moveBounds) ||
e.Y > (beforeMoveY + moveBounds))
{
// DRAGGED!
}
else
{
// NOT DRAGGED!
}
}

How to catch event Mouse Hold on a control?

I want to catch the event that user clicks and holds mouse on a control in C#.
I have read on MSDN and I only see events Mouse Down, Mouse Up, ... but don't have Move Hold event.
You need to use mentinoed events with some timer between them.
Example:
MouseDown
Start Timer
MouseUp
Disable Timer
In case if user holds more then timer time - invoke your event handler, when mouseUp happend faster then timer elapsed - disable runned timer.
First, you should use stop watch to detect time you want.
using System.Diagnostics;
Second, define a global instance of stopwatch class.
Stopwatch s = new Stopwatch();
This is the first event you should use:
private void controlName_MouseDown(object sender, MouseEventArgs e)
{
s.Start();
}
This is the second event you should use:
private void controlName_MouseUp(object sender, MouseEventArgs e)
{
s.Stop();
//determine time you want . but take attention it's in millisecond
if (s.ElapsedMilliseconds <= 700 && s.ElapsedMilliseconds >= 200)
{
//you code here.
}
s.Reset();
}

WPF equivalent of Control.CursorChanged event

I am trying to change my mouse cursor at certain point when I'm dragging my mouse around in a wpf listview. However, when I set my mouse, it quickly gets overridden by something else, and get changed back to the drag cursor.
I am not sure where the cursor change comes from, it is certainly not from my code, so it has to be system. If it is system, then I have to intercept the event for cursor change, and handle the event in order for the cursor to show what I want right?
So is there a WPF equivalent of this Control.CursorChanged event? Or perhaps there's some other way to approach this problem?
Edit:
here's part of my code
private void SetDragCursor()
{
if (_badDragLoc)
{
Mouse.OverrideCursor = Cursors.No;
}
else
{
Mouse.OverrideCursor = Cursors.Arrow;
}
}
private void listView_DragOver(object sender, DragEventArgs e)
{
if (at a bad drag location)
{
_badDragLoc = true;
SetDragCursor();
}
}
I also have a drag leave event handler, in which I also have the SetDragCursor() method as well. When I step by step go through each line of code in debugger, the mouse turned into the drag cursor from the no cursor right after it enters the drag leave handler. Which is why I think it has to be the system.
If it indeed is the system, then if I can capture the event firing, I can then handle those event myself and not let it bubble through.
Thank you!
Just does not work like that, the way to set the cursor during a DragOver event is the following:
void listView__DragOver(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent("Images"))
{
e.Effects = DragDropEffects.None;
e.Handled = true;
}
}
depending on the value of DragDropEffects enum you assign to e.Effects the mouse will change cursor.
do not call Mouse.OverrideCursor because is not the right way.

Categories

Resources