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.
Related
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?
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.
I'm writing a complex GUI for my game's main menu. I have already created a ButtonGUI class with it's own constructor with the parameters of button text, text color etc. I have a background texture drawn behind the text for every button, to make it look pretty. So I implemented a simple mouse input system:
void DetectBtnInput(ButtonGUI btn)
{
if (mouseRect.Intersects(btn.SourceRect))
{
btn.IsHovered = true;
if (mouseState.LeftButton == ButtonState.Pressed) settingsWindow.isOpen = true;
}
}
This method is called in Update(GameTime gameTime) for each instance of the ButtonGUI class. So mouseRect = new Rectangle(mouseState.X, mouseState.Y, 1, 1);
each instance of the ButtonGUI class has a Rectangle SourceRect property, which is equal to the position of the button passed to the constructor (obviously the button's size is the same every time). The logic behind the above code is simple, if the mouse is hovering the button instance's SourceRect, btn.IsHovered is set to true, it changes text color. When clicked, my WindowGUI class instance opens with additional settings.
So my aim is at making these buttons look nice and have the Windows styled button mechanics. So I am looking for a code to check for mouse hold-like event and have for example a bool that changes the button texture or whatever I can do myself. But the problem is that I tried incorporating the solution people give about the previousMouseState and the newMouseState, but I am not certain as if it works in Monogame as it worked in XNA... Or was my implementation wrong? Can I have a clearer example on how you handle mouse-hold in your games? Thanks in advance!
If you mean the player can click and hold (as per question title), and nothing happens until they then release. previous and current state should work fine as an implementation such as.
Forgive any incorrections in syntax, hopefully you can take this as pseudo code enough to make your own.
MouseState prev, curr;
curr = GetMouseState();
update()
{
prev = curr;
curr = GetMouseState();
// Simple check for a mouse click (from being held down)
if (curr == MouseState.Up && prev == MouseState.Down)
{
// Do mouse stuff here
}
}
In my WinForm application I have drawn a rectangle (System.Drawing.Rectangle) on a form.
I need to handle double click anywhere on the form
I could attach MouseDoubleClick event handler to the form. It works only when double click was made outside the rectangular shape.
How do I achieve this?
EDIT:
I have drawn a rectangle which is center aligned and covers only 40% of the whole winform area. When user double clicks on the rectangle I need to expand rectangle size to occupy full screen. That's all!
EDIT 2:
My friends who have down voted, write a comment please so that I could improve, please!
The best way I know to do what you are looking for is to use the "WndProc" method. This allows you to collect "messages" (events) from the message queue before they are sent to the form. You then have the option of either responding to those events or allowing them to continue through the normal message process. For more information, take a look at the MSDN page here.
A brief example of how you might use this:
protected override void WndProc(ref Message m)
{
// http://msdn.microsoft.com/en-us/library/windows/desktop/hh454920(v=vs.85).aspx
// 0x210 is WM_PARENTNOTIFY
// 513 is WM_LBUTTONCLICK
if (m.Msg == 0x210 && m.WParam.ToInt32() == 513)
{
var x = (int)(m.LParam.ToInt32() & 0xFFFF);
var y = (int)(m.LParam.ToInt32() >> 16);
var childControl = this.GetChildAtPoint(new Point(x, y));
if (childControl == cancelButton)
{
// ...
}
}
base.WndProc(ref m);
}
Credit for this example goes to: this stack question.
Remember too, that "double click" is just two single clicks, so you are going to have to monitor and find the time between clicks yourself to decide what actually represents a double click.
Unfortunately Rectangle does not contain any fire any events (at all) as System.Drawing merely provides "grahpics" for a form.
There are options (such as provided by #drew_w) however such workarounds that require interaction with COM objects is usually indicate it's time to re-evaluate the requirements.
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