Getting Started
Introduction
Sample Programs
IDEs
History
Advice
Mini-Tutorial
Tutorials
Code Snippets

Resources
Web Sites
More Tutorials
Forums
Vendors/Tools
Books
Magazines
Newsletters
NewsGroups
User Groups
Talk Shows
Blogs

Controls
Overview
Button
Check3State
Checkbox
ComboBox
Frame
Graphic
Image
ImageX
ImgButton
ImgButtonX
Label
Line
ListBox
ListView
Option
Progress Bar
Scrollbar
StatusBar
TAB
TextBox
Toolbar
TreeView

GBIC >> PowerBASIC >> Tutorials >> Messages: Mouse

PowerBASIC Information Center Tutorials
These tutorials were written to help you get a quick, but thorough, understanding of PowerBASIC - the scope of the language as well as it's specific capabilities.

Introduction       Projects       Language           Messages       Functions           Advanced
  • Overview
  • Examples
  • IDE
  • Compilation
  • Distribution
  • Project Files
  • DDT Windows
  • Controls
  • Menus
  • Dialogs  
  • Help Files
  • Resources  
  • Templates  
  • Project Shell  
  • Syntax
  • Operators
  • Data Types
  • Variables
  • Scope
  • Declarations  
  • Procedures
  • Flow Control
  • Windows
  • Messages
  • Callbacks
  • Mouse
  • Keyboard
  • Dialogs
  • Controls
  • Subclassing
  • Arithmetic
  • Trig  
  • Strings
  • Arrays
  • Date/Time
  • Printing
  • Files
  • Folders
  • Keyboard
  • Mouse
  • Sound
  • System
  • Error Traps
  • Debugging
  • Objects
  • Graphics
  • Databases
  • API
  • DLLs
  • ASM
  • Threads
  • Handling Mouse Messages
    Many applications need to know where the cursor is (xy coordinates), what window (dialog/control) it is over, if a mouse event has occurred (click, etc.), and details about the mouse event.

    There are two general methods of getting the information - repetitive use of API to check mouse/cursor status (such as within a message loop or timer) or responding to Windows messages when they are sent to notify an application that a mouse events has occurred.

    As we will see, either method can be used in a PowerBASIC application, but the use of Windows messages often provides a more convenient method of getting to the needed information.

    This page covers methods to detect and use the various mouse events (mouse down, mouse up, etc.).

    However, it is worth mentioning that all of the common controls provide their own messages on mouse events in areas of interest in the control. Most often, the messages supplied by the common controls are all that a programmer needs to create an application.

    But since common control messages do not cover all possible mouse actions, the additional of use of Windows API often proves useful in many applications.

    Using Only API to Monitor Mouse Status
    Information about the cursor/mouse can be retrieved at any time, regardless of whether a mouse event has taken place. In particular, the cursor location (x,y coordinates) within a dialog, the mouse buttons pressed (left/right/middle), the keys pressed (Ctrl/Alt/Shift), and the handle/control ID of the child window beneath the cursor can be retrieved using API calls.

    This code gets the location, control handle, and control ID.

        Local hTemp As Dword, ID as Integer, pt As Point, iResult&
    
        'get xy coordinates
        GetCursorPos pt               'pt has xy screen coordinates
        ScreenToClient hDlg, pt       'pt now has client coordinates
    
        'get child handle and ID
        hTemp = ChildWindowFromPoint(hDlg, pt.x, pt.y) 'child control handle
        ID = GetDlgCtrlID (hTemp)     'returns control ID from control handle
    

    The next code shows how to use API to get the up/down status of mouse buttons and of the ctrl/alt/shift keys (commonly used with mouse actions). In particular, the GetKeyState() and GetAsyncKeyState() API can access button/key states.

       'mouse buttons (left/right/middle)
       iResult& = GetAsyncKeyState(%vk_lbutton)
       iResult& = GetAsyncKeyState(%vk_rbutton)
       iResult& = GetAsyncKeyState(%vk_mbutton)
    
       'keyboard keys (Ctrl/Alt/Shift)
       iResult& = GetAsyncKeyState(%vk_shift)
       iResult& = GetAsyncKeyState(%vk_control)
       iResult& = GetAsyncKeyState(%vk_menu)
    
       'alternate way to get keyboard keys status
       iResult& = GetKeyState(%vk_shift)
       iResult& = GetKeyState(%vk_control)
       iResult& = GetKeyState(%vk_menu)       
    

    There are complexities with using these two API, making them not as popular with programmers as the seemingly straight-forward code might suggest. See my tutorial section on key monitoring for more information.

    An inconvenience of the all-API approach is that the program must include code to repeatedly test for the mouse information, usually as part of a message loop or by using a timer to trigger periodic use of the code to get the mouse information.

    It is generally more convenient to let the Windows operating system send a mouse event message, which contains much of the needed information, to the application for a program response.

    Sample Application - Monitoring Mouse Without Messages
    Here is a complete sample application using the code above. Note that in this example, a PowerBASIC Dialog DoEvents loop is used to repeatedly call the monitoring code. When the sub MouseInfo is run, the results are placed in a pair of labels.

       #Compile Exe
       #Include "win32api.inc"
       Global hDlg As Dword
       Function PBMain() As Long
          Dialog New Pixels, 0, "Button Test",300,300,200,200, )
                                 %WS_OverlappedWindow, 0 To hDlg
          Control Add Label, hDlg, 100,"", 50,50,100,20, %WS_Border
          Control Add Label, hDlg, 101,"", 50,80,100,20, %WS_Border
          Dialog Show Modeless hDlg
          Do
              Dialog DoEvents 0 To Count&
              MouseInfo
          Loop While Count&
       End Function
       
       Sub MouseInfo
           Local hTemp As Dword, Id As Integer, pt As PointAPI
           GetCursorPos pt             'pt has screen position of cursor
           ScreenToClient hDlg, pt     'pt now has hDlg client coordinates
           hTemp = ChildWindowFromPoint(hDlg, pt.x, pt.y)  'handle of child
           Id = GetDlgCtrlID (hTemp)     'returns control ID
           hTemp = GetDlgItem(hDlg, Id)  'returns control handle
           Control Set Text hDlg, 100, Str$(htemp)
           Control Set Text hDlg, 101, Str$(Id)
           Control ReDraw hdlg, 100
           Control ReDraw hdlg, 101
       End Sub
    

    As was noted above, this example displays the dialog as modeless and uses a message loop to continually monitor mouse information.

    An alternative to the DDT DoEvents loop would be to create a timer, allowing the MouseInfo subroutine to run from within the recurring %wm_timer event messages.

    More often, however, the cursor information is only needed when a mouse event (click, etc.) takes place. That's where Mouse messages come into play.

    API vs DDT Comparison: Retrieving Control ID and Control Handle
    This might be as good a time as any to mention some code that works both inside and outside mouse events. Given either the ID or the handle of a child control, PowerBASIC and the Windows API offers functions which allow you to get the other value.

        ID = GetDlgCtrlID (hTemp)         'API: use handle to get ID
        hTemp = GetDlgItem(hDlg, ID)      'API: use ID to get handle 
    
        Window Get ID hTemp to ID         'DDT: use handle to get ID
        Control Handle hDlg, ID TO hTemp  'DDT: use ID to get handle
    

    The API mentioned here were used in the first example on this page. The DDT code is provided by PowerBASIC as an alternative to the API solutions. The choice of which code to use is a personal selection, however more experienced programmers tend to use API solutions which are considered more portable between languages.

    Now, on to discussing mouse messages.

    Mouse Messages: Overview
    Whenever a mouse event (move, up, down, doubleclick, scroll and hover) takes place, Windows sends one or more messages to the PowerBASIC application. The messages are sent to the callback function of the control in which the mouse event took place. If no control callback function is available, the mouse message is sent to the dialog callback function of the control's parent dialog.

    PowerBASIC programmers commonly use a dialog callback function to handle all messages, avoiding the use of creating a callback function for each control.

    The following table lists the available mouse messages.

        Client Area            Non-Client Area          Miscellaneous
        ----------------	   -----------------        -------------------
        WM_LBUTTONDBLCLK       WM_NCLBUTTONDBLCLK       WM_MOUSEMOVE
        WM_LBUTTONDOWN	   WM_NCLBUTTONDOWN	    WM_NCMOUSEMOVE
        WM_LBUTTONUP	   WM_NCLBUTTONUP	    WM_NCHITTEST
        WM_MBUTTONDBLCLK       WM_NCMBUTTONDBLCLK	    WM_MOUSEACTIVATE
        WM_MBUTTONDOWN         WM_NCMBUTTONDOWN         WM_CAPUTRECHANGED
        WM_MBUTTONUP           WM_NCMBUTTONUP           WM_MOUSEHOVER
        WM_RBUTTONDBLCLK       WM_NCRBUTTONDBLCLK	    WM_NCMOUSEHOVER
        WM_RBUTTONDOWN         WM_NCRBUTTONDOWN	    WM_MOUSELEAVE
        WM_RBUTTONUP           WM_NCRBUTTONUP           WM_NCMOUSELEAVE
        WM_XBUTTONDBLCLK       WM_NCXBUTTONDBLCLK       WM_MOUSEWHEEL
        WM_XBUTTONDOWN	   WM_NCXBUTTONDOWN         WM_MOUSEHWHEEL
        WM_XBUTTONUP	   WM_NCXBUTTONUP
    

    Note that there are equivalent messages for client and non-client area mouse events (up/down/doubleclick) in the first two columns. The messages in the third column cover a wide range of events.

    The purpose of many of these messages is self-explanatory, but additional discussion is provided below - particularly for the messages in the "Miscellaneous" column.

    Mouse Terminology - Background
    But before discussing how to use the mouse messages from the table above, some mouse/cursor background information and definitions are needed.

    • Non-Client Area
      The non-client area of a window consists of its border, menu bar, title bar, scroll bar, window menu, minimize button, and maximize button.

    • Client Area
      The client area of a window is the central area of a window, where child controls are placed. It excludes all of the non-client elements.

    • Click
      A click occurs when any mouse button is pressed and released. Windows provides message for both the press and release events, as in the following list of left mouse button events.

         1. WM_LBUTTONDOWN
         2. WM_LBUTTONUP
         

      There is no "click" event (such as WM_LBUTTONCLICK), but there is a doubleclick event.

    • DoubleClick
      A doubleclick occurs when two buttondown events occurs within a default interval. The doubleclick event generates the following four-message series. The second mousedown event generates the double-click message followed by another button-up message.

         1. WM_LBUTTONDOWN
         2. WM_LBUTTONUP
         3. WM_LBUTTONDBLCLK
         4. WM_LBUTTONUP
         

    • XButton
      Windows supports 5 buttons on a mouse - left, right, middle, XButton1 and XButton2. XButton1 and XButton2 are typically small buttons to either side of the middle button (or scroll wheel, depending on the mouse construction). Determination of which XButton has been pressed is usually included in the wParam message parameter.

    • Wheel
      A mouse wheel can be pressed and acts as a middle button. It also can be rotated, which results in WM_MOUSEWHEEL messages. Not all common controls recognize a mouse wheel. Here's the list of those which do.

         Edit Control		TreeView		Trackbar Scrolls
         ListBox		ListView		Rich Edit Control
         ComboBox		Up/Down Scrollbars
         

    Mouse Message Content
    Like any Windows message, the mouse messages listed above contain 4 numbers, all Long data types.

      hWndhandle of the dialog/control in which the event occurred
      Msgmessage description (WM_MOUSEMOVE, WM_LBUTTONUP, ...)
      wParam     content is message dependent
      lParam  content is message dependent

    The Msg value is a numerical named_constant defined by Windows. Msg values are documented on MSDN and are included in the PowerBASIC win32api.inc include file.

    Within a PowerBASIC application, the actual numerical value or text description of a Msg is not used. Only the named constants (WM_MOUSEMOVE, etc.) are used in the code.

    To know what a named constants means, you'll have to visit MSDN. There is no Windows API or utility which can return a text string description of a mouse event named constant. However, a DLL (winmsg.dll) is distributed with the PowerBASIC sample applications which offers a lookup capability.

    There are even a few web pages - here, here, and here - which provide lists.

    Mouse Messages: wParam and lParam Data Extraction
    As noted above, wParam and lParam contain values which vary from message to message. To maximize the information that these values can send to an application, it is common to place two numerical values into these Long (4 bytes) variables - using the lower two bytes (low word) to store one integer value and the upper two bytes (high word) to store a second integer value. Many, but not all, messages use this technique.

    Getting the Lo/Hi word from a Long or DWord (also 4 bytes) variable can be done in several ways, using API, mathematical operations, or with DDT commands.

    Here's example code that uses the PowerBASIC Lo/Hi functions to extract lo/hi values from a wParam value. There's also a line of code which will place integer values in the low and high words of a Long/DWord variable.

        LoValue% = Lo(Word, wParam)
        HiValue% = Hi(Word, wParam)
        Result = Mak(DWORD, LoValue%, HiValue%)
    

    In a PowerBASIC program, the wParam value is normally retrieved within a callback function using the CB function, so wParam would be normally be replaced with CB.wParam, as would the lParam message value be retrieved with CB.lParam.

    Mouse Messages: Up, Down, DblClick
    Finally - we're getting to actual mouse messages! Here's the listing of the 24 mouse messages corresponding to the up/down/dblclick (remember, Windows has no "click" mouse event) messages. There are corresponding messages for the client area and non-client area mouse messages.

        Client Area            Non-Client Area   
        ----------------	   ----------------- 
        WM_LBUTTONDBLCLK       WM_NCLBUTTONDBLCLK
        WM_LBUTTONDOWN	   WM_NCLBUTTONDOWN
        WM_LBUTTONUP	   WM_NCLBUTTONUP
        WM_MBUTTONDBLCLK       WM_NCMBUTTONDBLCLK
        WM_MBUTTONDOWN         WM_NCMBUTTONDOWN 
        WM_MBUTTONUP           WM_NCMBUTTONUP   
        WM_RBUTTONDBLCLK       WM_NCRBUTTONDBLCLK
        WM_RBUTTONDOWN         WM_NCRBUTTONDOWN
        WM_RBUTTONUP           WM_NCRBUTTONUP  
        WM_XBUTTONDBLCLK       WM_NCXBUTTONDBLCLK
        WM_XBUTTONDOWN	   WM_NCXBUTTONDOWN 
        WM_XBUTTONUP	   WM_NCXBUTTONUP
    

    The great thing about these messages is that the message values all have the same content.

    • hWnd handle of the control in which the event occurred
    • Msg message description (WM_MOUSEMOVE, WM_LBUTTONUP, ...)
    • wParam list of mouse keys and keyboard keys pressed
    • lParam xy coordinates of the cursor (client area)

    Here's more information about the content of wParam and lParam, and how to extract the information. Remember, this only applies to the 24 mouse events listed above. The Miscellaneous column of mouse messages have different wParam/lParam message value content.

    • wParam
      The lo word value of wParam consists of one or more of the following values.

          MK_LBUTTON - Left button	  MK_CONTROL  - Ctrl Key    
          MK_MBUTTON - Middle button	  MK_SHIFT    - Shift Key
          MK_RBUTTON - Right button     MK_XBUTTON1 - 1st XButton
      				  MK_XBUTTON2 - 2nd XButton
      

      To test if any button/key was pressed, use the following code (substituting %MK_LBUTTON with any of the key constants listed above).

          If Lo(Word, CB.wParam) AND %MK_LBUTTON Then ...   'left button was pressed
      

      Except for the XButton messages, the hi word of wParam is empty. So for the Left/Right/Middle button message, the entire value of CB.wParam can be used instead of having to first extract the lo word.

      The high word of wParam is not used except for the XButton messages, in which case the hi word of wParam indicates whether XButton1 or XButton2 was pressed.

    • lParam
      To determine the x,y client coordinates of the cursor, use the PowerBASIC Lo/Hi functions.

          x = Lo(Word, CB.lParam)     'returns x coordinate
          y = Hi(Word, CB.lParam)     'returns y coordinate
      

      Then, the handle and ID of a child control under the cursor can be retrieved from this code from the first example at the top of this page.

          'get child handle and ID
          hTemp = ChildWindowFromPoint(hDlg, x, y) 'get control handle
          ID = GetDlgCtrlID (hTemp)     'get control ID
      

    It's worth mentioning again that almost all of the common controls provide their own events to indicate when a mouse clicks on areas of the control. Most often, those events are all that a programmer needs to create a user interface. However the dialog does not provide such events, nor do the control events cover all possible mouse actions, so the information just presented can be useful.

    As helpful as these events might seem, monitoring 24 different mouse events can be pretty cumbersome. In the following discussion of the Miscellaneous column of mouse messages, we'll see that other mouse messages can simplify the task of monitoring for mouse events.

    Miscellaneous Mouse Messages
    Here is a description of the remaining mouse messages. Though fewer in number, you'll find several of these to be generally more useful than the messages already discussed.

        WM_MOUSEMOVE	- moves within the client area
        WM_NCMOUSEMOVE	- moves within the non-client area
    
        WM_NCHITTEST	- determines if event was in non-client area
    
        WM_MOUSEACTIVATE	- set top-level window as active
        WM_CAPTURECHANGED	- sent to window losing mouse capture
    
        WM_MOUSEHOVER	- hovers for a certain time period over client area
        WM_NCMOUSEHOVER	- hovers for a certain time period over non-client area
        WM_MOUSELEAVE	- leaves the client area
        WM_NCMOUSELEAVE	- leaves the non-client area
    
        WM_MOUSEHWHEEL	- detects movement of mouse wheel
        WM_MOUSEWHEEL	- detects movement of mouse wheel
    

    Each of these are discussed below, including the content of wParam/lParam and how it might be used.

    WM_PARENTNOTIFY
    Surprise! This message was not discussed earlier, because it is not a mouse message, but rather a dialog message. This message is sent to the dialog when the user clicks a mouse on a child window. This is one of the most common mouse clicks. So if the child control does not provide an event for the click, then the WM_PARENTNOTIFY event is the first place to go, even before the dedicated mouse event messages!

    Which mouse button was pressed and the xy coordinates of the cursor (client coordinates) are provided by WM_PARENTNOTIFY.

    • wParam
      The low order word in wParam consists of one of the following value. The high order word in wParam is not used.

          WM_LBUTTONDOWN       WM_RBUTTONDOWN        WM_MBUTTONDOWN
      

      To test if any button/key was pressed, use the following code with one of the above values.

          If CB.wParam AND %WM_LBUTTONDOWN Then ...   'left button was pressed
      

    • lParam
      To determine the x,y client coordinates of the cursor, use the PowerBASIC Lo/Hi functions discussed earlier on this page.

          x = Lo(Word, CB.lParam)     'returns x coordinate
          y = Hi(Word, CB.lParam)     'returns y coordinate
      

      Then, the handle and ID of a child control under the cursor can be retrieved from this code, which has been discussed already.

          'get child handle and ID
          hTemp = ChildWindowFromPoint(hDlg, x, y) 'child control handle
          ID = GetDlgCtrlID (hTemp)     'returns control ID from control handle
      

    WM_SETCURSOR
    Surprise, again! This message was not discussed earlier, because it is not a mouse message, but rather a cursor message (the only cursor message Windows provides).

    Nonetheless, it provides information useful to a PowerBASIC programmer in working with a mouse. Whereas the WM_MOUSEMOVE and WM_NCMOUSEMOVE work only on either the client and non-client areas, respectively, the WM_SETCURSOR message is sent when mouse movement occurs anywhere within a window.

    The dialog/control where the mouse was located, the message identifier, and the section of the window beneath the cursor are provided by WM_SETCURSOR.

    • wParam
      The handle of the window (dialog or control) that contains the cursor is found in wParam. There is no lo/hi word split, since a handle requires the entire 4 bytes of the Long wParam value.

          hWnd = CB.wParam     'may be a dialog or child control
      

    • lParam
      The low order word contains the hit-test code, while the high order word contains the identifier of the mouse message.

      The hit-test returns one of these values, indicating where the cursor is located.

      HTBORDER     	border of a window that does not have a sizing border
      HTBOTTOM     	lower-horizontal border of a resizable window
      HTBOTTOMLEFT 	lower-left corner of a border of a resizable window
      HTBOTTOMRIGHT	lower-right corner of a border of a resizable window
      HTCAPTION    	title bar
      HTCLIENT     	client area
      HTCLOSE      	close button
      HTERROR      	screen background or on a dividing line between windows
      HTGROWBOX    	size box (same as HTSIZE)
      HTHELP       	Help button
      HTHSCROLL    	horizontal scroll bar
      HTLEFT       	left border of a resizable window
      HTMENU       	menu
      HTMAXBUTTON  	Maximize button
      HTMINBUTTON  	Minimize button
      HTNOWHERE    	screen background or on a dividing line between windows
      HTREDUCE     	Minimize button
      HTRIGHT      	right border of a resizable window
      HTSIZE       	size box (same as HTGROWBOX)
      HTSYSMENU    	window menu or in a Close button in a child window
      HTTOP        	upper-horizontal border of a window
      HTTOPLEFT    	upper-left corner of a window border
      HTTOPRIGHT   	upper-right corner of a window border
      HTTRANSPARENT	window currently covered by another window in the same thread
      HTVSCROLL    	vertical scroll bar
      HTZOOM       	Maximize button
      

      To test which area the cursor is over, use this code with one of the above values.

          If CB.lParam = %HTCLIENT Then ...   'mouse moved over client area
      

      With the handle available, the xy coordinates and control ID can be retrieved with these lines of API code. The alternate approach of using DDT code to get the control ID is also shown.

          'get xy coordinates
          GetCursorPos pt               'pt has xy screen coordinates
          ScreenToClient hDlg, pt       'pt now has client coordinates
      
          'get control handle and ID
          hTemp = ChildWindowFromPoint(hDlg, pt.x, pt.y) 'get control handle
          ID = GetDlgCtrlID (hWnd)     'API: get control ID
          Window Get ID hTemp to ID    'DDT: get control ID
      

    WM_MOUSEMOVE, WM_NCMOUSEMOVE
    These messages are sent when a mouse is moved in the client or non-client areas, respectively.

    • wParam
      The lo word value of wParam consists of one or more of the following values.

          MK_LBUTTON - Left button	  MK_CONTROL  - Ctrl Key    
          MK_MBUTTON - Middle button	  MK_SHIFT    - Shift Key
          MK_RBUTTON - Right button     MK_XBUTTON1 - 1st XButton
      				  MK_XBUTTON2 - 2nd XButton
      

      To test if any button/key was pressed, use the following code (substituting %MK_LBUTTON with any of the key constants listed above).

          If Lo(Word, CB.wParam) AND %MK_LBUTTON Then ...   'left button was pressed
      

      Except for the XButton messages, the hi word of wParam is empty. So for the Left/Right/Middle button message, the entire value of CB.wParam can be used instead of having to first extract the lo word.

      The high word of wParam is not used except for the XButton messages, in which case the hi word of wParam indicates whether XButton1 or XButton2 was pressed.

    • lParam
      To determine the xy client coordinates of the cursor, use the PowerBASIC Lo/Hi functions discussed earlier on this page.

          x = Lo(Word, CB.lParam)     'returns x coordinate
          y = Hi(Word, CB.lParam)     'returns y coordinate
      

      Then, the handle and ID of a child control under the cursor can be retrieved from this code, which has been discussed already. Note that since xy are screen coordinates, they must first be converted to dialog coordinates.

          'get child handle and ID
          hTemp = ChildWindowFromPoint(hDlg, x, y) 'returns control handle
          ID = GetDlgCtrlID (hTemp)     'returns control ID
      

    WM_NCHITTEST
    This message is sent to a window when the cursor moves, or when a mouse button is pressed or released - basically the entire waterfront of events.

    The only information provided is the xy coordinates of the cursor (screen coordinates). But, once the user sends this message on to the DefWindowProc, a return value will be received which is one of the hit-test position indicators (see values in WM_SETCURSOR discussion above).

    To send the message on the DefWindowProc, use the following code:

        iResult& = DefWindowProc(CB.hWnd,CB.Msg,CB.wParam,CB.lParam)
    

    And here's the information provided by wParam and lParam.

    • wParam
      not used.

    • lParam
      To determine the x,y client coordinates of the cursor, use the PowerBASIC Lo/Hi functions discussed earlier on this page.

          pt.x = Lo(Word, CB.lParam)     'returns x coordinate
          pt.y = Hi(Word, CB.lParam)     'returns y coordinate
      

      Then, the handle and ID of a child control under the cursor can be retrieved from this code, which has been discussed already. Note that since xy are screen coordinates, they must first be converted to dialog coordinates.

          'get child handle and ID
          ScreenToClient hDlg, pt     'pt now has hDlg client coordinates
          hTemp = ChildWindowFromPoint(hDlg, pt.x, pt.y) 'returns control handle
          ID = GetDlgCtrlID (hTemp)     'returns control ID
      

    WM_MOUSEACTIVATE
    This message is sent when the cursor is over an inactive window and the user presses a mouse button.

    • wParam
      Contains the handle to the parent window of the window being activated.

    • lParam
      The low order word contains the hit-test code, while the high order word contains the identifier of the mouse message.

      The hit-test returns one of these values, indicating where the cursor is located. See the list of hit-test values in WM_SETCURSOR above

      To test which area the cursor is over, use this code with one of hit-test values.

          If CB.lParam = %HTCLIENT Then ...   'mouse moved over client area
      

      With the handle available, the xy coordinates and control ID can be retrieved with these lines of API code. The alternate approach of using DDT code to get the control ID is also shown.

          'get xy coordinates
          GetCursorPos pt               'pt has xy screen coordinates
          ScreenToClient hDlg, pt       'pt now has client coordinates
      
          'get control handle and ID
          hTemp = ChildWindowFromPoint(hDlg, pt.x, pt.y) 'get control handle
          ID = GetDlgCtrlID (hWnd)     'API: get control ID
          Window Get ID hTemp to ID    'DDT: get control ID
      

    WM_CAPTURECHANGED
    At any one time, only one window can receive mouse inputs. That window is said to have gained the mouse capture.

    Normally, clicking on a window gives it focus and captures the mouse. However, a window can use SetCapture to capture the mouse. A window that has captured the mouse receives all mouse input, regardless of the position of the cursor, except when a mouse button is clicked while the cursor is in the window of another thread. The ReleaseCapture functions releases mouse capture from a window and restores normal mouse input processing.

    When a window loses mouse capture, it is sent the message WM_CAPTURECHANGED.

    • wParam
      Not used.

    • lParam
      Contains handle to the window gaining the mouse capture.

    WM_MOUSEHOVER
    Hovering is only tracked when a TrackMouseEvent function is called, specifying a window to track and the time interval which constitutes "hovering". Once TrackMouseEvent is called, the WM_MOUSEHOVER, WM_NCMOUSEHOVER, WM_MOUSELEAVE, and WM_NCMOUSELEAVE messages will be generated.

    WM_MOUSEHOVER is posted when the cursor hovers over the non-client area for a specified time.

    • wParam
      The lo word value of wParam consists of one or more of the following values.

          MK_LBUTTON - Left button	  MK_CONTROL  - Ctrl Key    
          MK_MBUTTON - Middle button	  MK_SHIFT    - Shift Key
          MK_RBUTTON - Right button     MK_XBUTTON1 - 1st XButton
      				  MK_XBUTTON2 - 2nd XButton
      

      To test if any button/key was pressed, use the following code (substituting %MK_LBUTTON with any of the key constants listed above).

          If Lo(Word, CB.wParam) AND %MK_LBUTTON Then ...   'left button was pressed
      

      Except for the XButton messages, the hi word of wParam is empty. So for the Left/Right/Middle button message, the entire value of CB.wParam can be used instead of having to first extract the lo word.

      The high word of wParam is not used except for the XButton messages, in which case the hi word of wParam indicates whether XButton1 or XButton2 was pressed.

    • lParam
      To determine the xy client coordinates of the cursor, use the PowerBASIC Lo/Hi functions discussed earlier on this page.

          x = Lo(Word, CB.lParam)     'returns x coordinate
          y = Hi(Word, CB.lParam)     'returns y coordinate
      

      Then, the handle and ID of a child control under the cursor can be retrieved from this code, which has been discussed already. Note that since xy are screen coordinates, they must first be converted to dialog coordinates.

          'get child handle and ID
          hTemp = ChildWindowFromPoint(hDlg, x, y) 'returns control handle
          ID = GetDlgCtrlID (hTemp)     'returns control ID
      

    WM_NCMOUSEHOVER
    Hovering is only tracked when a TrackMouseEvent function is called, specifying a window to track and the time interval which constitutes "hovering". Once TrackMouseEvent is called, the WM_MOUSEHOVER, WM_NCMOUSEHOVER, WM_MOUSELEAVE, and WM_NCMOUSELEAVE messages will be generated.

    WM_NCMOUSEHOVER is posted when the cursor hovers over the non-client area for a specified time.

    • wParam
      The low order word contains the hit-test code, while the high order word contains the identifier of the mouse message.

      The hit-test returns one of these values, indicating where the cursor is located. See the list of hit-test values in WM_SETCURSOR above

      To test which area the cursor is over, use this code with one of hit-test values.

          If CB.lParam = %HTCLIENT Then ...   'mouse moved over client area
      

      With the handle available, the xy coordinates and control ID can be retrieved with these lines of API code. The alternate approach of using DDT code to get the control ID is also shown.

          'get xy coordinates
          GetCursorPos pt               'pt has xy screen coordinates
          ScreenToClient hDlg, pt       'pt now has client coordinates
      
          'get control handle and ID
          hTemp = ChildWindowFromPoint(hDlg, pt.x, pt.y) 'get control handle
          ID = GetDlgCtrlID (hWnd)     'API: get control ID
          Window Get ID hTemp to ID    'DDT: get control ID
      

    • lParam
      Contains the xy screen coordinates in a POINTS structure. The xy coordinates can be retrieved as follows.

          Dim pt as POINTS	'a Type Points is contained in "win32api.inc"
          pt = @CB.lParam	'lParam has pointer to POINTS structure	    
      

    WM_MOUSELEAVE, WM_NCMOUSELEAVE
    These messages work with WM_MOUSEHOVER and WM_NCMOUSEHOVER, and are posted when the cursor leaves the client (WM_MOUSELEAVE) or the non-client (WM_NCMOUSELEAVE) area of the window specified in a prior call to TrackMouseEvent.

    Tracking requested by TrackMouseEvent is canceled when this message is generated.

    • wParam
      Not used. Must be zero.

    • lParam
      Not used. Must be zero.

      The TrackMouseEvent() specifies a handle of the window to track, so any information supplied to wParam/lParam would be redundant.

    WM_MOUSEWHEEL, WM_MOUSEHWHEEL
    The wheel on a mouse can be pressed, or rotated.

    When pressed, it is treated as a middle mouse button, whose events were covered further up this page.

    When the wheel is rotated, the WM_MOUSEWHEEL message is sent to the focus window.

    The WM_MOUSEWHEEL message return the amount of rotation, which keys are down, and the xy screen coordinates of the pointer.

    • wParam
      The lo word value of wParam consists of one or more of the following values.

          MK_LBUTTON - Left button	  MK_CONTROL  - Ctrl Key    
          MK_MBUTTON - Middle button	  MK_SHIFT    - Shift Key
          MK_RBUTTON - Right button     MK_XBUTTON1 - 1st XButton
      				  MK_XBUTTON2 - 2nd XButton
      

      To test if any button/key was pressed, use the following code (substituting %MK_LBUTTON with any of the key constants listed above).

          If Lo(Word, CB.wParam) AND %MK_LBUTTON Then ...   'left button was pressed
      

      The hi word value of xParam gives the distance the wheel is rotated. Positive and negative values are returned.

    • lParam
      To determine the xy client coordinates of the cursor, use the PowerBASIC Lo/Hi functions discussed earlier on this page.

          x = Lo(Word, CB.lParam)     'returns x coordinate
          y = Hi(Word, CB.lParam)     'returns y coordinate
      

      Then, the handle and ID of a child control under the cursor can be retrieved from this code, which has been discussed already. Note that since xy are screen coordinates, they must first be converted to dialog coordinates.

          'get child handle and ID
          hTemp = ChildWindowFromPoint(hDlg, x, y) 'returns control handle
          ID = GetDlgCtrlID (hTemp)     'returns control ID
      

    MousePTR DDT Function
    Slightly outside the topic of mouse messages, is the PowerBASIC function MousePTR, which can set the mouse pointer to a new shape. MousePTR is often used as part of the response to mouse events.

        MOUSEPTR iStyle& TO iResult&    'TO is optional
    

    iResult is set to zero if the operation fails, or to a handle for the old cursor if it succeeds. The handle may be used to restore the cursor by using it in place of iStyle&

    iStyle options are:

        0 -  Hide                        7 - Pointer: Vertical
        1 -  Arrow                       8 - Pointer: NW-SE diagonal
        2 -  Cross                       9 - Pointer: Horizontal
        3 -  I-Beam                     10 - Up arrow
        4 -  Arrow                      11 - Hourglass
        5 -  Pointer: all directions    12 - No mouse pointer
        6 -  Pointer: NE-SW diagonal    13 - Arrow w/hourglass
    

    If you have any suggestions or corrections, please let me know.