How to Implement a Mouse Hover/Leave Message on the System Tray


Introduction

This article illustrates how to implement a tray mouse hover/leave message.

The Problem

Some programs want to get a mouse hover/leave message from the system tray when they want to show a popup window that is not a tool tip. However, the Windows shell doesn't support it. We can only get mouse move, up, down, and double-click messages from the system tray.

It is very easy to implement a WM_MOUSEHOVER message because the first WM_MOUSEMOVE is that. But, WM_MOUSELEAVE is hard to implement, so I decided to write a compact class to notify the window of a mouse hover/leave message.

The Idea

The basic idea is very simple. It is that no WM_MOUSEMOVE message fires when the mouse is out of the tray icon. This class saves the mouse point whenever a WM_MOUSEMOVE message fires on the system tray, and then another thread compares it with the current mouse point. The thread fires a WM_MOUSELEAVE message when the two points are different.

The following code is the WM_MOUSEMOVE handler.

VOID CTrayPos::OnMouseMove()
{
   EnterCriticalSection(&m_cs);

   GetCursorPos(&m_ptMouse);
   if(m_bTrackMouse == FALSE)
   {
      OnMouseHover();
      m_bTrackMouse = TRUE;
   }

   LeaveCriticalSection(&m_cs);
}

This is a thread function that checks the mouse point.

UINT CALLBACK CTrayPos::TrackMousePt(PVOID pvClass)
{
   POINT       ptMouse;
   CTrayPos    *pTrayPos = (CTrayPos *) pvClass;

   while(WaitForSingleObject(pTrayPos->m_hExitEvent, 2000) ==
                             WAIT_TIMEOUT)
   {

      if(pTrayPos->m_bTrackMouse == TRUE)
      {
         GetCursorPos(&ptMouse);

         if(ptMouse.x != pTrayPos->m_ptMouse.x || ptMouse.y !=
            pTrayPos->m_ptMouse.y)
         {
            pTrayPos->m_bTrackMouse = FALSE;
            pTrayPos->OnMouseLeave();
         }
      }
   }

   return 0;
}

Using the Code

If you want to use this class in your project, just follow these simple steps.

  • Add traypos.h and traypos.cpp file to your project.
  • Declare a variable of this class like that.
    Note that this class instance exists until the tray icon is deleted, so you must declare it a member variable or a global variable.
  • CMsgTrayPos traypos;
  • Add the following code after the register tray by calling Shell_NotifyIcon.
    The three parameters—hwnd, uID, and uMsgID—are the same value as the member of NOTIFYICONDATA.
  • traypos.SetNotifyIconInfo(hwnd, uID, uMsgID);
  • Call CMsgTrayPos::OnMouseMove on your WM_MOUSEMOVE message handler from the system tray.
  • Now, you can add WM_MOUSEHOVER and WM_MOUSELEAVE messages to your tray message handler and write a code there.

CMsgTrayPos API

  • VOID CMsgTrayPos::SetNotifyIconInfo(HWND hwnd, UINT uID, UINT uCallbackMsg);
    This function provides tray icon inforamtion to the class. The three parameters—hwnd, uID, and uCallbackMsg—and members of NOTIFYICONDATA are the same.
  • VOID CMsgTrayPos::OnMouseMove()

  • This function is very important. You must call this function when you get a WM_MOUSEMOVE message from the system tray.
    This function checks the mouse hover status and updates the mouse point internally.
  • BOOL CMsgTrayPos::IsIconHover();
    This function returns the mouse hover status. It returns TRUE if your mouse is on your tray icon.

History

  • 22 Aug 2004—Initial upload.


Downloads

Comments

  • Nice legs

    Posted by Artipol on 07/22/2008 06:05am

    That girl has a very nice-looking pair of legs.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds