I am writing a Windows application in C.
I am hiding the mouse cursor in the client area of the window by handling the WM_SETCURSOR message:
case WM_SETCURSOR:
{
static BOOL HideCursor = FALSE;
if ((LOWORD(LParam) == HTCLIENT) && !HideCursor)
{
HideCursor = TRUE;
ShowCursor(FALSE);
}
else if ((LOWORD(LParam) != HTCLIENT) && HideCursor)
{
HideCursor = FALSE;
ShowCursor(TRUE);
}
Result = DefWindowProc(Window, Message, WParam, LParam);
break;
}
This works fine, but it is a little awkward, because the mouse cursor disappears instantly as soon as it crosses into the client area of the window. The user can easily lose track of where the mouse cursor "should be" when he or she is trying to move the cursor toward the toolbar buttons, or manually resize the window, for example.
How can I add a second or two of delay in there so that the user can move the mouse over the client area of the window without the mouse instantly disappearing, but if the mouse cursor hovers in the client area for more than a second or two, it disappears?
When you are notified that the mouse cursor entered the window, you could use SetTimer(hWnd, ID_MOUSE_TIMER, 2000, NULL) where hWnd is your window handle and ID_MOUSE_TIMER is an arbitrary identifier for a timer, to create a timer that will fire after 2000 milliseconds.
You can then respond to the WM_TIMER message and hide the cursor just as you did before, but also use KillTimer(hWnd, ID_MOUSE_TIMER) to prevent further calls.
When the mouse cursor leaves your window, you should also destroy the timer, and also restore visibility of the mouse cursor if it was hidden just as you did before.
To read up on timers, check the corresponding section in the MSDN.
You could use the WM_MOUSEHOVER message.
Related
I'm wondering how I can get the original HCURSOR of whatever happens to be set as the mouse arrow pointer. I've already tried using GetCursor(), but it just gets whatever cursor is currently displayed on screen. Here's a section of my code:
COLORREF *hide;
HBITMAP bmp;
hide = (COLORREF*) malloc(sizeof(hide) * 1);
bmp = CreateBitmap(1, 1, 1, 32, (void *) hide);
ICONINFO Ico;
Ico.fIcon = false;
Ico.hbmColor = bmp;
Ico.hbmMask = bmp;
HCURSOR c = CreateIconIndirect(&Ico);
HCURSOR orgc = GetCursor();
SetSystemCursor(c, 32512);
Sleep(10);
SetSystemCursor(orgc, 32512);
DeleteObject(bmp);
I intend for it to hide the cursor, then wait for ten milliseconds, then bring the original cursor back without having to use the resize trick. Any suggestions?
I intend for it to hide the cursor, then wait for ten milliseconds, then bring the original cursor back without having to use the resize trick. Any suggestions?
ShowCursor(FALSE);
Sleep(10);
ShowCursor(TRUE);
I don't know what you mean by "the resize trick."
If you meant something else by "the original cursor," then perhaps a deeper understanding of how cursors are selected would be helpful.
Each window is responsible for setting the cursor as the mouse moves across it. Whenever the mouse moves within a window then, assuming the mouse is not captured, that window will receive a WM_SETCURSOR message. The name of the message can be a little confusing. Think of it as a notification to the window that this is its chance to change the cursor.
The window procedure can choose its cursor shape by calling SetCursor and then return TRUE to indicate that no other handlers be given the opportunity to process the message. There's nothing that denotes a particular cursor as an arrow cursor, wait cursor, crosshairs, etc. It's just the currently selected shape.
This (normally) happens for each WM_MOUSEMOVE. So it's very common for a window procedure to set the same cursor over and over again, so the system is designed to optimize for that. But allowing the window to decide what to should after each mouse move gives the window the opportunity to show different characters depending on where exactly within the window the mouse pointer is.
Whenever a SetCursor calls specifies a different cursor than the current one, it returns the HCURSOR of the previously selected one.
Many window procedures do not explicitly handle WM_SETCURSOR messages and instead passes them on to the default window procedure (DefWndProc). The default window procedure first relays the message to the parent window if there is one. This can happen recursively so that the root ancestor is the first window to get a choice to change the cursor.
If the parent handles the message and returns TRUE, then processing stops. So your application's main window can decide that the cursor should look like a chicken even if some of its child windows would want to select something else.
If no ancestor windows handle the message, then DefWndProc will check to see if the window has an HCURSOR set in its window class (WNDCLASS or WNDCLASSEX). If the windows class does specify a cursor, then DefWndProc will set that as the cursor. If the class cursor is NULL, DefWndProc does not set any cursor.
The system cursors are a set of defaults for different modes. If an application wants a wait cursor, it can call LoadCursor(NULL, IDC_WAIT) and get the HCURSOR of whatever cursor the user has selected as the system's default wait cursor. You shouldn't set the system cursors unless you're providing an interface for the user to set the system defaults.
I am starting using Allegro in my program in C, but I'm having difficulties creating the buttons. I am using this kind of logic:
if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
{
if ((event.mouse.x >= 442) &&(event.mouse.x <= 471) &&(event.mouse.y >= 202) &&(event.mouse.y <= 238))
{
dig = '1';
entr = 1;
}
But this spaces defined by the axis are non 'clickable'.Somebody here has some tip about the typo of command I should use?
I can only guess what was wrong, but there is no answer yet, so I will provide some tips about the possible problem. Your thread is titled enabling the mouse in allegro 5, so I can only assume you're not getting mouse input.
1) You need to install the mouse driver before you will get any mouse input :
if (!al_install_mouse()) {Fail();}
2) The mouse needs to be registered with your event queue.
al_register_event_source(event_queue , al_get_mouse_event_source());
In a typical GUI, most buttons are only considered 'pressed' if they receive both a mouse button down event over their click area, AND a mouse button up event over the same area. This way you don't get a button press when you click on something else, move the mouse over your button and release it. You also prevent button events from pressing the mouse, moving it off the click area and releasing it.
I have a C GTK3 application using a GtkScrolledWindow with a GtkGrid inside it. I'm happy with how everything is laid out, but the ScrolledWindow only scrolls via the mouse wheel if the cursor is over the scroll bar, or if I move the scroll bar with my cursor. The behavior I'm looking for is for the mouse wheel to always scroll the ScrolledWindow when the mouse wheel is used or at least when the cursor is over the ScrolledWindow (which is what I thought the default would be).
Here is where the ScrolledWindow is created :
scroll = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scroll), BANNER_HIGHT * 4);
(The location of these lines in the application (GitHub))
I'm wondering now if I have to pass a GtkAdjustment to the constructor but it seems like all that does is set the scrolling bounds. I'm also wondering if I could connect a mousescroll event on the main window and try to trigger it manually on the callback, but I don't see a way to do that either.
This actually seems to be a bug in GTK and/or the OS (Ubuntu), I was trying to use the multi-touch scroll gesture on my laptop's trackpad to scroll and that wasn't working. Today, I happened to have a regular mouse with an actual scroll wheel plugged in and noticed it works just fine.
UPDATE: I added the behavior I was looking for by subscribing to scroll events and adjusting the Scrolled Window manually using a GtkAdjustment after all:
bool scroll_entrires(GtkWidget * widget, GdkEvent * event, gpointer data) {
double delta_x, delta_y; // delta_y is not used
if (gdk_event_get_scroll_deltas(event, &delta_x, &delta_y)) {
GtkAdjustment * adj = gtk_scrolled_window_get_vadjustment(
GTK_SCROLLED_WINDOW(scroll));
gtk_adjustment_set_value(adj,
gtk_adjustment_get_value(adj) + 30 * delta_y);
// 30 is a number that I like for my setup but can
// be changed for other situations.
return true; // We have responded to the event
}
return false; // Let other handlers respond to this event
}
// ... (In my init code)
g_signal_connect(window, "scroll-event", G_CALLBACK(scroll_entries), NULL);
What I am trying to do: I am currently hosting an OpenTK glControl (through a WindowsFormsHost) in my WPF application. The application has many buttons, but we will focus on the pause and play buttons. I use VBO's and this is how I animate GL.DrawArrays(PrimitiveType.LineStrip, 0, frameCount );. It is drawing the range of vertices from 0 to framecount, so when I hit play, it just starts incrementing framecount, which starts animating. When just using a mouse, everything works perfectly.
The Problem: My app needs to work with a touch screen also (FWIW, when I say touch, WPF is seeing it as a stylus, not touch). When the app is NOT animating, touch works like it should, I don't handle touch events so touching buttons just raised the Click event. If we aren't animating, I don't have any problems. So when I use my mouse Click the play button, the UI still responds to my Mouse (clicks work, hovering changes colors as it should, etc), but then touches seemingly get ignored for some period of time. I have to touch a button 3 to 5 times before it does what it is supposed to (like pause). Lets go back and now we aren't animating, this time, if I TOUCH the play button to raise the Click event, it will start animating, but my touches now have the same problem of having to touch multiple times to raise Click event, and on top of that, the UI now does not respond to the mouse (the WindowsFormsHost still reacts to mouse events properly). Clicking on buttons or hovering over buttons doesn't do anything. It is not until I can get the animation to pause again that the UI starts responding to Mouse again.
What I have tried and what (I think) I know: When the UI stops responding to mouse input and touch input is messsed up, if I use MOUSE or TOUCH to click anywhere outside of my app, it works as expected. This leads me to believe it is not a touch screen driver problem or anything. I also used Snoop to see what events were being raised (or not) to see the stylus and the mouse being captured and released and what has focus. I could not find an instance where one was not released. If anyone would like, I can post Snoop results showing differences between mouse and touch clicking. I tried putting a preview mouse down on the MainWindow, but after TOUCHING play, no Mouse clicks raise this event, and the first touch after touching the play button touches randomly will fire this event. I also tried hiding the WindowsFormsHost, and mouse and touch clicks all work like they should minus the glControl. Because I hide the WindowsFormsHost, the paint event never gets fired, leading me to believe there might a problem with the paint function. I am aware of this bug WPF Touch Bug, however I don't really think that this is my problem. Something tells me the interop is what is giving me problems but I am not sure.
My Code:
private void playFwdFunc()
{
//disable undrawing and enable drawing
undraw = false;
draw = true;
//unpause animation
paused = false;
//enable/disable appropriate buttons
pauseBtn.IsEnabled = true;
stepBackBtn.IsEnabled = false;
stepFwdBtn.IsEnabled = false;
clearStart.IsEnabled = true;
clearCurrent.IsEnabled = true;
//refresh control
glControl1.Invalidate();
}
private void playFwdClick(object sender, RoutedEventArgs e)
{
playFwdFunc();
}
In my glPaint event:
if (frameCount < vertices.Length && !paused)
{
//draw more vertices
if (draw)
{
if (0 < (int)(vertices.Length / (25000 / speedTrack.Value)))
frameCount += (int)(vertices.Length / (25000 / speedTrack.Value));
else
frameCount++;
}
//draw less vertices
else if (undraw)
{
if (0 < (int)(vertices.Length / (25000 / speedTrack.Value)))
frameCount -= (int)(vertices.Length / (25000 / speedTrack.Value));
else
frameCount--;
}
//make sure we dont have a negative framecount (null pointer)
if (frameCount < 0)
{
paused = true;
frameCount = 0;
// manageCodeBox();
}
//make sure we dont exceed # of vertices (null pointer)
else if (frameCount > vertices.Length)
{
frameCount = vertices.Length;
paused = true;
// manageCodeBox();
}
}
My Question: Why is clicking a button with mouse making the UI react differently than touching a button, even though they raise the same event? Any input is appreciated.
So I found what was causing the behavior, in my paint function I was constantly raising an event that had a glControl1.Invalidate().
My Best Guess: My only real guess is that certain events like touches which occur on the stylus thread some how gets into a live-lock with the UI thread when calling glControl1.Invalidate(). I think that that is why some touches got accepted, but the UI thread never reached mouse event listeners. As I said: best guess.
My Workaround: I originally made a DispatcherTimer to call glControl1.Invalidate(). Mouse events worked fine, but because touches got promoted to mouse clicks, there was a delay unless I handled the touch event (which I did not want to do for each button on my UI). My next solution seems to be working so far.
In my windows constructor: CompositionTarget.Rendering += invalidateProcessor;.
The function:
private void invalidateProcessor(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(new Action(() => { if (!paused) glControl1.Invalidate(); }), DispatcherPriority.Background);
}
I chose DispatcherPriority.Background because the higher priorities cause a delay in the touches again.
I am a bit confused:
We have a chat application that has a requirement to NOT scroll chat, if the user is scrolled up; and we have a scrollInfo class that provides us with the ability to check if the scroll bar thumb is at the bottom of the scrollbar, so that we can identify if we should scroll or not.
Unfortunately, there are many different ways to scroll chat. One could use the scrollbars up/down boxes, or the scrollbar thumb, or just scroll using the mouse wheel.
However, if the up/down arrows are used, we have no issue.
And, if the scrollbar thumb is used, the VScroll event does fire, but we have no way of identifying which DIRECTION the thumb is moved, or how to check if it's being held down, without using a timer to constantly query the left mouse button status.
And, lastly, if mousewheel is scrolled, while we can tell which direction it's going by looking at the Delta property, the VScroll event still fires after the Mouse Wheel event is handled. So, we essentially have a duplicate scroll happen.
I need some help with this. Our chat application is as follows:
.NET 4.0 Windows Forms C# Application
Built in Visual Studio 2010
*Chat Output: * RichTextBox that auto formats text entering it.
Here's an example of our logic, that just isn't working:
User Scrolls Up using Mouse wheel: When new messages come in, they should NOT scroll the chat output box back down. Instead, when a scroll event happens, it should be able to detect where the scroll thumb is, and make that determination.
User Scrolls up using the ScrollBar thumb: VScroll event is fired, which checks if the scrollbar is at the 'bottom' of the scroll box. And, if it is, it does the full scroll event, to ensure that the caret is always placed at the end of the scroll box, and is hidden (so that the READ ONLY chat ouput, has no actual blinking I beam).
User scrolls using the scrollbar up/down arrows: works just fine. (no need to explain this one, as it's already working).
I need some clarification here, how can i properly check these events?
-------- EDIT FOR CLARIFICATION ---------
Contents of scrollInfo class:
internal class Scrollinfo
{
internal const uint ObjidVscroll = 0xFFFFFFFB;
[DllImport("user32.dll", SetLastError = true, EntryPoint = "GetScrollBarInfo")]
private static extern int GetScrollBarInfo(IntPtr hWnd,
uint idObject,
ref Scrollbarinfo psbi);
internal static bool CheckBottom(Control rtb, int postion)
{
var info = new Scrollbarinfo();
info.CbSize = Marshal.SizeOf(info);
var chk = GetScrollBarInfo(rtb.Handle,
ObjidVscroll,
ref info);
if (chk == 0)
GetScrollBarInfo(rtb.Handle,
ObjidVscroll,
ref info);
bool isbottom = info.XyThumbBottom
>= (info.RcScrollBar.Bottom - info.RcScrollBar.Top - (info.DxyLineButton + 1));
if (info.DxyLineButton <= 0) isbottom = true;
if (info.XyThumbBottom <= 0) isbottom = true;
return isbottom;
}
}
internal struct Scrollbarinfo
{
internal int CbSize;
internal Rect RcScrollBar;
internal int DxyLineButton;
internal int XyThumbTop;
internal int XyThumbBottom;
internal int Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
internal int[] Rgstate;
}
internal struct Rect
{
internal int Left;
internal int Top;
internal int Right;
internal int Bottom;
}}
You could try something like this:
Update the box with the new text to be displayed and then find the last visible line using the following code:
rtb.GetLineFromCharIndex(rtb.GetCharIndexFromPosition(new Point(rtb.Width, rtb.Height)));
Now next time that you need to put text into the RichTextBox, just check for the last visible line using the same code as above.
If the new last visible line is less than the older one, it means the user has scrolled upwards (or the RichTextBox has been resized). In either case, you'll just have to move the caret to the end of the text and then call the RichTextBox.ScrollToCaret() method to restore the position.
I also recommend you take a look at the following on the MSDN site:
RichTextBox Methods
RichTextBox.GetCharIndexFromPosition Method
RichTextBox.GetLineFromCharIndex Method
RichTextBox.Select Method¹
RichTextBox.ScrollToCaret Method
¹ This can be used to set the caret position.