How to capture user's click action when clicking on notifications - c++

Currently, I want to show a balloon notification on Windows, then I want to capture the action when a user clicks on the balloon notification.
Then I will do another action after capturing this action.
How can I do that?
And can I do that on all of the Windows platforms (from Windows 7 to Windows 10)?

You said in comments that you are using Shell_NotifyIcon() to display the balloon. The answer to your question is in the documentation:
As of Windows XP (Shell32.dll version 6.0), if a user passes the mouse pointer over an icon with which a balloon notification is associated, the Shell sends the following messages:
NIN_BALLOONSHOW. Sent when the balloon is shown (balloons are queued).
NIN_BALLOONHIDE. Sent when the balloon disappears. For example, when the icon is deleted. This message is not sent if the balloon is dismissed because of a timeout or if the user clicks the mouse.
As of Windows 7, NIN_BALLOONHIDE is also sent when a notification with the NIIF_RESPECT_QUIET_TIME flag set attempts to display during quiet time (a user's first hour on a new computer). In that case, the balloon is never displayed at all.
NIN_BALLOONTIMEOUT. Sent when the balloon is dismissed because of a timeout.
NIN_BALLOONUSERCLICK. Sent when the balloon is dismissed because the user clicked the mouse.
In addition to those messages, as of Windows Vista (Shell32.dll version 6.0.6), if a user passes the mouse pointer over an icon with which a balloon notification is associated, the Windows Vista Shell also adds the following messages:
NIN_POPUPOPEN. Sent when the user hovers the cursor over an icon to indicate that the richer pop-up UI should be used in place of a standard textual tooltip.
NIN_POPUPCLOSE. Sent when a cursor no longer hovers over an icon to indicate that the rich pop-up UI should be closed.
Regardless of the operating system version, you can select which way the Shell should behave by calling Shell_NotifyIcon with dwMessage set to NIM_SETVERSION. Set the uVersion member of the NOTIFYICONDATA structure pointed to by lpdata to indicate whether you want Windows 2000, Windows Vista, or pre-version 5.0 (Windows 95) behavior.
Note The messages discussed above are not conventional Windows messages. They are sent as the lParam value of the application-defined message that is specified in the uCallbackMessage member of the NOTIFYICONDATA structure pointed to by lpdata, when Shell_NotifyIcon is called with the NIM_ADD flag set in dwMessage.
So, to receive these messages, you need to specify an HWND and Callback message ID in the NOTIFYICONDATA struct when calling Shell_NotifyIcon() with dwMessage set to NIM_ADD or NIM_MODIFY:
hWnd
Type: HWND
A handle to the window that receives notifications associated with an icon in the notification area.
...
uCallbackMessage
Type: UINT
An application-defined message identifier. The system uses this identifier to send notification messages to the window identified in hWnd. These notification messages are sent when a mouse event or hover occurs in the bounding rectangle of the icon, when the icon is selected or activated with the keyboard, or when those actions occur in the balloon notification.
When the uVersion member is either 0 or NOTIFYICON_VERSION, the wParam parameter of the message contains the identifier of the taskbar icon in which the event occurred. This identifier can be 32 bits in length. The lParam parameter holds the mouse or keyboard message associated with the event. For example, when the pointer moves over a taskbar icon, lParam is set to WM_MOUSEMOVE.
When the uVersion member is NOTIFYICON_VERSION_4, applications continue to receive notification events in the form of application-defined messages through the uCallbackMessage member, but the interpretation of the lParam and wParam parameters of that message is changed as follows:
LOWORD(lParam) contains notification events, such as NIN_BALLOONSHOW, NIN_POPUPOPEN, or WM_CONTEXTMENU.
HIWORD(lParam) contains the icon ID. Icon IDs are restricted to a length of 16 bits.
GET_X_LPARAM(wParam) returns the X anchor coordinate for notification events NIN_POPUPOPEN, NIN_SELECT, NIN_KEYSELECT, and all mouse messages between WM_MOUSEFIRST and WM_MOUSELAST. If any of those messages are generated by the keyboard, wParam is set to the upper-left corner of the target icon. For all other messages, wParam is undefined.
GET_Y_LPARAM(wParam) returns the Y anchor coordinate for notification events and messages as defined for the X anchor.
...
If you set the NIF_INFO flag in the uFlags member, the balloon-style notification is used. For more discussion of these notifications, see Balloon tooltips.
So, to answer your question, in the WndProc for the HWND that you specify in the NOTIFYICONDATA::hWnd field, you would look for the message ID you specify in the NOTIFYICONDATA::uCallbackMessage field, and then look for the NIN_BALLOONUSERCLICK notification in the message's lParam or LOWORD(lParam) value, depending on how you set the NOTIFYICONDATA::uVersion field.

Related

The CBN_SELCHANGE notification not works when i use the function ComboBox_SetCurSel

I have a ComboBox in a window and i want to execute a function after changing selected item.
When i change the selected item of the combobox by mouse or keyboard,
the CBN_SELCHANGE event in the window message WM_COMMAND works well and my function execute.
But if i use the function ComboBox_SetCurSel for changing the selected item ,it not works.
What window message WM_**** and combox notification do i use for processing the event changing selected item.
In general, when you programmatically manipulate a control, the corresponding notification is not sent to its parent. The notification only gets sent when the user manipulates the control.
So, when you call ComboBox_SetCurSel (which is a macro that performs the same task as sending the CB_SETCURSEL message), that programmatically changes the control's current selection and therefore does not send the CBN_SELCHANGE notification. However, CBN_SELCHANGE does get sent if the user changes the combobox's selection.
This is called out explicitly in the "Remarks" section of the documentation for CBN_SELCHANGE:
The CBN_SELCHANGE notification code is not sent when the current selection is set using the CB_SETCURSEL message.
To work around this, you can do one of two things:
Call your event-handler method directly. For example, in MFC, you would have the framework attach an OnCbnSelChange member function to handle the combobox's CBN_SELCHANGE notification. After your code that called ComboBox_SetCurSel, you would simply call that OnCbnSelChange member function manually:
ComboBox_SetCurSel(hwndComboBox, 0); // select 1st item
this->OnCbnSelChange(); // invoke the change event-handler
Your GUI framework undoubtedly has something similar.
Manually send the CBN_SELCHANGE notification to the control's parent. I don't really know why you would ever do this, because the default window procedure doesn't do anything interesting upon receipt of this notification; you would be much better off just calling your own handler directly.
::PostMessage(hwndParent,
WM_COMMAND,
MAKEWPARAM(IDC_COMBOBOX, CBN_SELCHANGE),
reinterpret_cast<LPARAM>(hwndComboBox);
Or, if you were doing this from a subclass of the combobox:
HWND hwndParent = ::GetAncestor(hwndComboBox, GA_PARENT);
int ctrlID = static_cast<int>(::GetWindowLongPtr(hwndComboBox, GWLP_ID));
::PostMessage(hwndParent,
WM_COMMAND,
MAKEWPARAM(ctrlID, CBN_SELCHANGE),
reinterpret_cast<LPARAM>(hwndComboBox));

MFC Message flow for controls?

In MFC, suppose I have a dialog box, and in this box, it has a child CListCtrl, then I use mouse to click this CListCtrl, we know that eventually an WM_LBUTTONDOWN message is sent to CListCtrl. My question is: How does this WM_LBUTTONDOWN message get there?
Two possibilities:
Dialog box first gets this WM_LBUTTONDOWN message , and it finds that mouse click occurs in its child window, then it forwards this message to CListCtrl.
CListCtrl first gets this WM_LBUTTONDOWN message, it can process this message, and if it doesn't care it will forward this message to parent window, i.e. dialog box for further processing.
Which one is true?
Thanks.
Input messages are never sent to a window. They are posted to the message queue associated with a window, waiting to be retrieved through one of the message retrieval functions (GetMessage, PeekMessage, etc.).
Depending on whether the dialog box is modal or modeless, messages are retrieved by the nested modal loop (for modal dialogs) or the application's message loop. The message is then passed on to DispatchMessage, to find the recipient (starting from the topmost visible window under the mouse pointer, that is neither disabled nor transparent), and call into the associated window's window procedure. The window procedure can decide, whether it handles the message or not. A window procedure typically calls DefWindowProc to perform default processing, if it doesn't handle a message.
To summarize: The application's message loop (or the nested modal message loop) gets to see the message first, and instructs the window manager to deliver the message to the respective recipient.
A thorough description on Windows message processing is available at About Messages and Message Queues. The description is specific to the Windows API. Since MFC is just a wrapper around the Windows API, the contents apply to MFC as well, even though some of the concepts are hidden in a typical MFC application.

MFC button can not receive touch event

the list control can receive the touch event, but the push button can not receive the touch event, it always receive the mouse move event.
I want to send the touch event to the button's parent, how to resole this?
code like below can tell if it is a mouse or touch event, but can not forward the event to its parent to handle the touch event.
#define MOUSEEVENTF_FROMTOUCH 0xFF515700
if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) {
// Click was generated by wisptis / Windows Touch
}else{
// Click was generated by the mouse.
}
by the way, how to stop converting touch event to mouse event?
With WM_TOUCH/WM_GESTURE you get a handle to the touch input event list. The TOUCHINPUT data isn't dedicated to a specific window. Different to GESTUREINFO. But it shouldn't be complicated to translate the info.
An unhandled WM_GESTURE message passed to DefWindowProc will be propagated to the parent window. When forwarding gesture messages between windows, avoid sending messages from parent to child windows in order to prevent closed loops from occurring.
http://msdn.microsoft.com/en-us/library/ee220935.aspx
For a WM_TOUCH message you can use a user defined message and post this message with the lParam value to the parent of the button. But you must handle this message there and need to call CloseTouchInputHandle
If you don't pass the WM_TOUCH/WM_GESTURE message to DefWidnowProc no further translation is done.
Touch events are converted to mouse messages in the DefWindowProc processing.
What gestures are supported and converted to mouse messages is listed here.
The list control can receive the touch event, but the push button or textedit can not receive the touch event, it always receive the mouse move event.
code like below can tell if it is a mouse or touch event, but when flick up & down for a while, it can not receive the event.
Then flick left & right can always receive the mouse move event
#define MOUSEEVENTF_FROMTOUCH 0xFF515700
if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) {
// Click was generated by wisptis / Windows Touch
}else{
// Click was generated by the mouse.
}
I put this button in a scrollview which has the vertical scroll bar.

How to get notified of textbox focus?

Using a Windows 7 touch device Windows shows this little touch-keyboard indicator (tabing this will bring up the touch on screen keyboard) when you tab/focus a textbox or kind of input field (Notepad etc.).
I want to write an application that gets notified when exactly that happens, a textbox (etc.) gets focused (no matter which application).
Are applications informed about focusing in other applications, do I need to hook something?
Is there a way in doing so in c++?
I believe the SetWinEventHook function and specifically the EVENT_OBJECT_FOCUS event is what you are looking for.
From the MSDN description:
An object has received the keyboard focus. The system sends this event for the following user interface elements: list-view control, menu bar, pop-up menu, switch window, tab control, tree view control, and window object. Server applications send this event for their accessible objects.
The hwnd parameter of the WinEventProc callback function identifies the window that receives the keyboard focus.

"?" help button triggers WM_HELP _and_ WM_LBUTTONUP

I have a Windows application that registers one CALLBACK procedure that handles WM_HELP messages for the dialog, and one CALLBACK procedure that handles WM_LBUTTONUP messages for a custom button.
Now, when the user clicks the "?" button, then clicks the custom button, the help opens up as expected (on mouse down), BUT if the help window is not occluding the button, a WM_LBUTTONUP message is triggered as well for the custom button (on mouse up). This causes the button to trigger when the user was only asking for help.
Is there any way to stop the WM_LBUTTONUP message from being sent if the button press is for help?
EDIT: The custom button is implemented using a STATIC control. I believe this is because it needs to have an image and no border. So, it does not send BN_CLICKED notifications. In fact, it does not seem to trigger WM_COMMAND in the parent at all.
Thanks
This is normal. Be sure to use the button's BN_CLICKED notification to see the difference. Generated when the user clicks the button, not generated when the user uses the help cursor. The button still sees the normal button up/down messages so that's not a good trigger to detect a click. Extra bonus is that the button can now also be clicked with the keyboard (space bar).
A good class library takes care of these nasty little details.
A better way would be to create ? as a custom control with BS_CHECKBOX | BS_PUSHLIKE style and capture the mouse. After that you will get all the WM_LBUTTONDOWN message to this custom control and then you can use WindowFromPoint to get the window where the WM_LBUTTONDOWN happened and can send a custom notification to the parent window. The parent window can then show a the tooltip or open the help doc or discard it.
The advantage is, you create the control only once and you can use it in multiple places.
Okay, I fixed it by creating the custom button (static control) with the SS_NOTIFY style, then handling the STN_CLICKED notification in the WM_COMMAND message. (SS_NOTIFY causes WM_COMMAND to trigger in the parent when it is clicked.) This does not trigger when using the "?" button. Thanks!