Recognizing unknown mouse buttons - c++

So I've been writing a simple Windows program, and it really irks me how in some other programs, they can't recognize the full range of input. For example, in Starcraft 2, you can't bind the extra two mouse buttons on a five-button mouse. For keyboard input, I've been using the WPARAM of the WM_KEYDOWN message, so that if it's unrecognized, I can still recognize it later, even if not display it in a usable form. But for mouse buttons, I've come a cropper, because they have their own messages. So if in the future, I get a seven-button mouse, how can I recognize the sixth and seventh buttons without having to re-write my application?

I don't think there is a generic "WM_BUTTONDOWN" message available.
The best way to check that out is to use Spy++ on a window. You'll see that there is no generic message sent out. Plus the actual values of all the WM_xxBUTTONDOWN do not follow any pattern either.
What I would do is configure the app to be able to understand 6 new messages entered manually or configured somewhere, for WM_[Z]BUTTONDOWN, WM_[Z]BUTTONUP and WM_[Z]BUTTONDBLCLK, plus all the corresponding WM_NCxxx messages, because luckily (sort of...), all existing messages more or less share the same wParam + lParam pattern.

Related

WinAPI mouse click does not work properly

I am creating program in C++ (Windows 7 ), that controls one specific window by reading its screen and sending back mouse signals (only left-clicks). I am using WinAPI obviously. Problem is with the mouse signals. My target is to send mouse events independently on actual cursor position. (i.e. it can run on "the background" and the window does not have to be visible).
I tried the obvious solution using SendMessage (or PostMessage):
PostMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(x, y));
this_thread::sleep_for (std::chrono::milliseconds(100));
PostMessage(hwnd, WM_LBUTTONUP , MK_LBUTTON, MAKELPARAM(x, y));
I think the commands work fine but there is some problem with how the application process the click events. It seems it does not take into account the parameters x,y and instead when WM_LBUTTONUP is called, it asks OS where the cursor is and make the click on that location. So in the end the click occurs always on the location of cursor (if it is inside the window).
I also tried to send WM_MOUSEMOVE event before WM_LBUTTONUP but it didn't help.
This behavior is really strange, and I fully blame the application not WinAPI. Any ideas how to solve this? Can I maybe somehow trick the window so it thinks that cursor is elsewhere?
If this is the only thing you need then use SendInput with the MOUSEINPUT structure.
If you want to understand why then read on. What you are doing does not work because mouse messages are special. They are not regular messages that arrive and wait for you in the message queue. They are synthesized on demand when you call GetMessage and therefore they get their data from a secret, hidden place . In fact, generally speaking input messages are treated differently than posted messages. Here is some reading material.

WM_LBUTTONDOWN + WM_LBUTTONUP combination making drag view

I am using below code in my application's view on particular event to simulate a left mouse click.
SendMessage(WM_LBUTTONDOWN);
SendMessage(WM_LBUTTONUP);
Once this code executed a mouse drag view appears. How to avoid this drag view after simulating the mouse click?
When I monitored via SPY++ I got the both messages are sent like below,
WM_LBUTTONDOWN fwKeys: MK_LBUTTON xPos : 752 yPos:85
WM_BUTTONUP fwKeys:0000 xPos:752 yPos 85
I suspect the WM_LBUTTONUP message not sent properly.
What is the fwKeys : 0000 indicates?
Is there any think wrong in sendMessage of WM_LBUTTON up in the above code?
First of all, if that is your real code, you are "simulating" the mouse click improperly. There's more to a WM_LBUTTONDOWN or WM_LBUTTONUP than the message itself: there's data packed in the wParam and lParam values of the message.
You could easily see that if you had taken a second to look at the MSDN pages for WM_LBUTTONDOWN and WM_LBUTTONUP. They describe exactly what the wParam and lParam values mean in this context. And, by the way, this would also answer your question about the meaning of "fwKeys" in Spy++.
But really, if you need to simulate mouse events, then do it the right way: call the mouse_event function. It's whole purpose in life is to synthesize mouse events.
On to your other question: how to disable the drag view: it depends on what kind of control you're dealing with. For example, if you had a tree view control, then you could set the TVS_DISABLEDRAGDROP style on the control, as stated on MSDN. If you want to disable drag & drop for that control permanently, then set the flag when you create the control. If you only want to disable it temporarily, during your synthesized input operations, then that's a bit trickier - you can use CWnd::ModifyStyle to temporarily remove the TVS_DISABLEDRAGDROP but you will also need to add code to enable it again, after you finish sending your synthesized mouse movements and the control has finished processing them.
With all that said, what exactly are you trying to achieve? There may be an easier way to solve the problem that you are trying to address.
Thanks for all your answers and support.
I am working on a already developed application which requires this solution. Finally I found that the WM_LBUTTONDOWN handler was already defined in my view. This takes time to execute. Since I used SendMessage which posts message to a thread's message queue and return immediately, before the WM_LBUTTONDOWN finished, the next message WM_LBUTTONUP is called. So the WM_LBUTTONUP was failing.
I used PostMessage as below,
PostMessage(WM_LBUTTONDOWN);
PostMessage(WM_LBUTTONUP);
This resolves my problem.

Getting title bar double-clicks

I am working on a MFC C++ application. I was working on a dialog that has SystemMenu property set to FALSE, so it does not have the ability to maximize. I want to handle the double-click message on the title bar. How can I do that?
EDIT:
I hope this time it will be clear for everybody. I have a dialog that does not have system menu (and system buttons or icon). When the user double-clicks the titlebar of that dialog, I want the program to call function x();.
Technically, you would have to handle WM_NCLBUTTONDBLCLK and check if the double click occurred in the caption area of the window, possibly by sending it WM_NCHITTEST and testing that the return value is HTCAPTION.
(Update: As JohnCz rightfully points out, sending WM_NCHITTESTis not actually necessary, since WM_NCLBUTTONDBLCLK already carries its result in wParam.)
Then you would only have to send WM_SYSCOMMAND with SC_MAXIMIZE in wParam to the window to maximize it.
In practice, however, it will not achieve much if your dialog box is not ready to handle size changes and layout its controls accordingly. This feature did not come out of the box in MFC last time I checked.
I think there is some kind of confusion here:
Frédéric Hamidi
You are correct, handling WM_NCLBUTTONDBLCLK message is the right way to go, however it is no necessary to call HitTest, since WM_NCLBUTTONDBLCLK message delivers hit information that MFC framework translates in the WM_NCLBUTTONDBLCLK handler.
Victor,
What is exactly that you are trying to achieve by handling WM_NCLBUTTONDBLCLK message?
Maybe there is some other way to fulfill your requirement once you make it clear to us.
The fact that you do not have system menu, does not prevent your app from receiving non-client area messages.

Sending text/keystrokes to unselected window?

Is there a way to send keystrokes to a window that is not currently selected in C++? For example, if I have a notepad window minimized and want some text to be typed in it without bringing the window to the front.
I'm using Windows 7 64-bit.
Faking input is rather hard to achieve, in full generality, without using SendInput().
Yes you can try PostMessage(), but the answer from eznme is misleading at best when it talks about SendMessage. As I, and others, seem to say many times a day here, input is posted to the message queue rather than sent to a window handle.
All that said, if you don't want to give the Notepad window input focus then it's going to be hard to get the text in there by faking. The very simple alternative that works better and is easier to use, is to find the window handle of the Notepad EDIT window and use WM_GETTEXT and WM_SETTEXT, for example, to modify its contents directly.
In fact there is an enormous multitude of functionality available once your have this window handle at your mercy!
Absolutely: Check out PostMessage() and SendMessage(), they are part of the Windows API:
http://msdn.microsoft.com/en-us/library/ms644944%28VS.85%29.aspx
http://msdn.microsoft.com/en-us/library/ms644950%28VS.85%29.aspx
Specifically you probably want to send WM_KEYUP
http://msdn.microsoft.com/en-us/library/ms646281%28VS.85%29.aspx

Can a CRichEditCtrl know when someone sets its text?

When typing into a CRichEditCtrl, EN_CHANGE messages are generated. However MSDN says:
Rich Edit: Supported in Microsoft Rich
Edit 1.0 and later. To receive
EN_CHANGE notifications, specify
ENM_CHANGE in the mask sent with the
EM_SETEVENTMASK message. For
information about the compatibility of
rich edit versions with the various
system versions, see About Rich Edit
Controls.
The EN_CHANGE notification is not sent
when the ES_MULTILINE style is used
and the text is sent through
WM_SETTEXT.
I have several dialogs using a multi-line rich edit control, actually my custom CMyRichEdit class. That class automatically performs analysis when the text changes, but in the important case where the dialog is initially populated, no notification is seen.
The point is to avoid having to change our code-base more than absolutely necessary - the new control is being dropped in to replace existing ones. Chasing down every instance where getDlgItem(IDC_EDIT)->SetWindowText is used, or where DDX_Text(pDX, IDC_EDIT, m_strEdit) automatically links a string contents with the control, would mean a lot of trawling through code and re-testing everything altered.
Is there an easy way? Can MyRichEdit catch its own WM_SETTEXT messages?
ON_MESSAGE(WM_SETTEXT, OnSetText)
// fires every time someone calls SetWindowText
LRESULT MyRichEditCtrl::OnSetText(WPARAM wParam, LPARAM lParam)
{
return CWnd::Default();
}