I have a button on a (c#) WinForm, and when it is pressed (mouse down then up) I would like to change the mouse cursor to a custom icon. I would like that custom cursor icon to remain regardless of mouse position on the screen area (over source app, other apps, desktop, etc.) until the mouse is clicked (mouse down then up). After this second click I want the cursor to revert back to its default behavior.
I'm currently using the global mouse hook method outlined by Dan Silk (with adjustment from Hans Passant) to capture global mouse move and click events.
I think I need to intercept (and subsequently stop) WM_SETCURSOR messages (which according to Hans follow any mouse move). However I'm not sure how to do this for things beyond the source app, which Reza Aghaei outlined as follows:
const int WM_SETCURSOR = 0x0020;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SETCURSOR)
Cursor.Current = myCustomCursor;
else
base.WndProc(ref m);
}
When I tried to use the above WndProc method for adjusting the cursor for just the source app, I still got cursor flickering. Is there a proper way to stop the WM_SETCURSOR message sending/posting?
Any help or suggestions would be most appreciated!
UPDATE
I decided to go at my problem from a different angle to avoid fighting WM_SETCURSOR messages entirely. What I have now works fine, however if there is an answer floating out there you are welcome to post it for posterity.
Couple of these events works for me globally no matter which application is mouse over:
private static Cursor _customCursor = new Cursor(#"C:\path\Hand.cur");
private void button1_MouseDown(object sender, MouseEventArgs e)
{
Cursor = _customCursor;
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
Cursor = Cursors.Default;
}
Does it cover your needs or I have missed something important here?
Related
I'm trying to move the form instead of resizing it while I'm resizing if the right button is down.
Resize event:
if (rightMouseDown)
{
this.SetDesktopLocation(MousePosition.X - this.Width, MousePosition.Y - this.Height);
this.MaximumSize = new System.Drawing.Size(this.Width, this.Height);
this.MinimumSize = new System.Drawing.Size(this.Width, this.Height);
}
Global mouse event:
bool rightMouseDown;
private void HoldMouse(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right && e.Clicks != 1)
{
rightMouseDown = true;
}
else if (e.Button == MouseButtons.Right)
{
rightMouseDown = false;
this.MaximumSize = new System.Drawing.Size(0, 0);
this.MinimumSize = new System.Drawing.Size(100, 100);
}
}
At the moment when I click the right button it freezes because the MaximumSize is constant, therefore I can't resize the form.
e.cancel would be awesome if it would work but I can't use that.
I'm able to capture the mouse events with a global one, the form events doesn't work weirdly.
I Got it working but only when the window's width is minimum and it goes to it's original width after the right mouse button goes up.
This is due to setting it to the default size. How can I keep the window in the changed size without setting it to MaximumSize 0,0?
First of all, I would suggest that you do not move the form while the right button is down, because this is highly non-standard and therefore likely to be perceived as highly peculiar by anyone trying to use your app. To be more specific, nobody is ever going to try either moving or resizing your form with the right mouse button, so:
if that's the only way you offer for moving your form, then nobody will ever be able to move your form.
if you also offer other ways of moving your form, then why bother with offering this way too?
Secondly, I would like to propose that this is most probably an X-Y problem meaning that you probably have some other issue, which you have told us nothing about, you think that you might address it by moving-by-right-click, then you discover that moving-by-right-click does not work for you, and you come here asking how to get moving-by-right-click to work. Why don't you begin by describing the real issue?
Thirdly, if you really want to proceed with moving your form by right-click, that's not how to do it.
First, you need to detect when the right mouse button is pressed. There are events for this. They work. If they don't work for you, that's not a reason to be doing other weird things instead. The statement "I'm not able to capture the mouse click with the Mouse events" is utterly bizarre, because a) it is a wrong use of the term "capture"; mouse capture is a very specific thing, (more about it later,) so please refrain from using it in other contexts, and b) if you cannot accomplish something, then that should be the subject of a stackoverflow question on its own. You cannot be trying utterly bizarre things because your attempts to do the right things failed.
So, once you have gotten detection of the right mouse click to work, then you need to set up mouse capture. (Look it up, search for "SetCapture".) That's what guarantees that you can keep receiving mouse move events, and finally a mouse-up event, even though the mouse has moved outside of your form while you were dragging it.
Like the RichTextBox, I want to be able to handle events for when the vertical scrollbar has been adjusted (through slider dragging, the mouse wheel or otherwise), and for when the caret / text cursor has been moved. However, these events appear to be missing from Scintilla. How can I achieve the same result?
Both of those are available under the UpdateUI event via the UpdateChange structure. Example:
private void scintilla1_UpdateUI(object sender, ScintillaNET.UpdateUIEventArgs e)
{
if (e.Change == ScintillaNET.UpdateChange.VScroll)
{
...
}
}
I'm making a little tool for drawing onto the screen with the mouse after a 'pen' button is toggled in a floating sidebar.
I have done this (please don't laugh) by having a top-most windows form with its background as its transparency key cover the whole screen.
I need to make the mouse not click through the form onto the stuff below when I"m in drawing mode. I tried following this:
Windows form with a transparent background that cannot be clicked through
How to disable click through on transparent control?
which successfully stops the mouse but also un-maximises the form and drags it around with the mouse (using HTCAPTION IntPtr(2) this is) I tried using some of the other values listed on MSDN, but with no luck.
I'm way out of my depth, any help greatly appreciated (newbie friendly please!)
PS I'm using this right now..
//code for allowing clicking through of menus
protected override void WndProc(ref Message m)
{
if (penMode && m.Msg == 0x84)
{
m.Result = new IntPtr(2);
}
else
base.WndProc(ref m);
}
UPDATE: Now solved the problem by approaching it in another way entirely. It doesn't look like WndProc will work so I simply created a blank form over the whole screen the showed my main form (form.Show(this)) from within that. Then adjust the opacity of the blank form which sits underneath from 0% to 1% to allow/ prevent clicking through. Works!
Thanks to all answers, taught me a lot.
Actually, no need to laugh—it sounds to me like you're doing this the correct way already. Since you don't own the desktop, you shouldn't draw directly on it. Instead, you need to simulate it by overlaying a transparent form that you do own, and then drawing on that. Because you own the transparent overlay form, it's no problem to draw on it.
But beyond that, it sounds like you're just trying values randomly without a clear understanding of what they actually do. That's like throwing darts with your eyes closed. You won't have a very high hit count.
Let's start by understanding what your code does. The magic value 0x84 corresponds to the WM_NCHITTEST message, which is sent by Windows to a window to determine how mouse clicks on that window should be handled. In response to that message, you reply with one of the HT* values, given in the linked documentation. Each of those values has a particular meaning, also explained in the documentation. For example:
HTCAPTION (which has a value of 2) means that the clicked portion of the window should be treated as the window's caption/title bar. You know from using Windows that you can drag windows around on the screen using the title bar, so it makes sense that returning HTCAPTION in response to mouse clicks would allow your window to be draggable. You'll see this used on borderless forms (i.e., those with no title bar) to allow them to be movable.
HTTRANSPARENT (which has a value of -1) is another available value. This one's pretty simple. It just makes your window look transparent. It's like saying "don't mind me, there's no window here!" Mouse clicks are simply passed on to the window that lies below yours in the Z order as if you weren't there.
HTCLIENT (a value of 1) is the default result when the click occurs anywhere on the window's client area. You would return this (or simply call the default window procedure) when you want everything to work normally. Click events that return this value would go on to be processed normally by the framework, raising either the form's Click event, or getting passed on to child controls located on the form.
So, when you're not drawing, you probably want to return HTTRANSPARENT. When you are drawing, you probably want to return HTCLIENT so that your drawing code can see the mouse events and draw the result.
Fixing your code, then:
// Code for allowing clicking through of the form
protected override void WndProc(ref Message m)
{
const uint WM_NCHITTEST = 0x84;
const int HTTRANSPARENT = -1;
const int HTCLIENT = 1;
const int HTCAPTION = 2;
// ... or define an enum with all the values
if (m.Msg == WM_NCHITTEST)
{
// If it's the message we want, handle it.
if (penMode)
{
// If we're drawing, we want to see mouse events like normal.
m.Result = new IntPtr(HTCLIENT);
}
else
{
// Otherwise, we want to pass mouse events on to the desktop,
// as if we were not even here.
m.Result = new IntPtr(HTTRANSPARENT);
}
return; // bail out because we've handled the message
}
// Otherwise, call the base class implementation for default processing.
base.WndProc(ref m);
}
You might just want to set the visibility of your window to like 5% or so and leave the transparent key deactivated.
you basically won't notice it and jet it's there :D
hope this helps
I am developing an application that maps users eye movements with the cursor movements, hence developing ahands free cursor control system.
I am using Open CV library's .NET Wrapper for C# i.e. Emgu CV for development.
I am stuck at a point where I want to open a file/folder such that when a cursor is placed over a file/folder for say 3 to 5 seconds, the file/folder should open up or just perform a double-click event of a conventional mouse.
What could I use so as to solve this problem?
Timer timer = new System.Timers.Timer(5000);//5 seconds
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
private void form_MouseHover(object sender, System.EventArgs e)
{
timer.Start();
}
private void form_MouseLeave(object sender, System.EventArgs e)
{
timer.Stop();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
timer.Stop();
OpenFileOrFolder();//Edit : implement your file / folder opening logic here
}
I guess you need to break it down:
Detect when the mouse moves or hovers
Send a double click
For 1, I'd be looking at: capturing WM_MOUSEMOVE if you want your own definition of 'hovering'. For example, having a greater threshold for how much movement you'll tolerate and still consider it a 'hover'. Or, you could use the OS defined threshold and look for WM_MOUSEHOVER
For 2, SendInput should get you there
I'm assuming here, you don't actually care what's under the mouse per-se. As in, you're not going to do different behavior depending on what's under the mouse. For example, you'd send the double click when hovering over the titlebar, as well as if you were hovering over the file.
This article on project builds up a Spy++ style app, which should help.
Are you mapping eye control to the mouse pointer? The MouseHover event may be useful:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.mousehover.aspx
As well as MouseEnter, MouseLeave, etc.
If you're controlling a separate element (i.e., not the mouse) with the eyes, then I had to do something similar in WPF. It ultimately came down to mapping control coordinates to mouse location, counting the time within the bounds of that control, then calling the mouse click event handler.
This question already has an answer here:
Block/Nullify mouse movement/click in C#
(1 answer)
Closed 7 years ago.
At work, i'm a trainer. I'm setting up lessons to teach people how to "do stuff" without a mouse... Ever seen people click "login" textbox, type, take the mouse, click "password", type their password, then take the mouse again to click the "connect" button beneath ?
So i'll teach them how to do all that without a mouse (among many other things, of course)
At the end of the course, i'll make them pass a sort of exam.
So i'm building a little wizard based app in which i present some simili-real-life examples of forms to fill in, but i want to disable their mouse programatically while they do this test.
However, further in the wizard, i'll have to let them use their mouse again.
Is there a -- possibly easy -- way to just disable the mouse for a while, and re-enable it later on?
I'm on C# 2.0, programming under VC# 2k5, if that matters
Make your form implement IMessageFilter.
Then add the following code to the form:
Rectangle BoundRect;
Rectangle OldRect = Rectangle.Empty;
private void EnableMouse()
{
Cursor.Clip = OldRect;
Cursor.Show();
Application.RemoveMessageFilter(this);
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0x201 || m.Msg == 0x202 || m.Msg == 0x203) return true;
if (m.Msg == 0x204 || m.Msg == 0x205 || m.Msg == 0x206) return true;
return false;
}
private void DisableMouse()
{
OldRect = Cursor.Clip;
// Arbitrary location.
BoundRect = new Rectangle(50, 50, 1, 1);
Cursor.Clip = BoundRect;
Cursor.Hide();
Application.AddMessageFilter(this);
}
This will hide the cursor, make it so that they can't move it and disable the right and left mousebuttons.
You're looking for the Cursor.Hide() method.
Note that the cursor will still be movable, it just won't be visible.
If you're running with Visual Styles enabled, it would be still possible to use the mouse by tracking hover effects.
However, anyone capable of doing that probably doesn't need your course.
A more "fun" way of doing this would be to hanle the MouseMove event and set Cursor.Position to prevent the mouse from moving into your panel.
How about a different approach (thinking out of the "have to program a solution to everything" box): before you start the lessons, disconnect all the mice... have them reconnect it when the mouse is needed again.
Imho easiest will be to PInvoke the ShowCursor(FALSE) function (see http://msdn.microsoft.com/en-us/library/ms648396.aspx)
[DllImport("user32.dll")]
static extern int ShowCursor(bool bShow);
Edit: This is equivalent to calling Cursor.Hide () (http://msdn.microsoft.com/en-us/library/system.windows.forms.cursor.hide(v=VS.100).aspx) if you are using Windows Forms.