Windows API messages
How to detect mouse leaving a window
When the mouse cursor is leaving a window a message is send to the window indicating this.
But to enable this feature, you will have to call the Windows API function TrackMouseEvent first to register the window.
This is the declaration for TrackMouseEvent
Library name: USER32.DLL Function: TrackMouseEvent Export Ordinal: 0 Returns Boolean: BOOL Parameters structPointer Number: DWORD Number: DWORD Window Handle: HWND Number: DWORD
The following list of possible constant declarations for the function TrackMouseEvent
(The NC constants are for the non-client area's like caption or borders)
! Below the flags for TrackMouseEvent Number: TME_HOVER = 0x0001 Number: TME_LEAVE = 0x0002 Number: TME_NONCLIENT = 0x0010 ! Below the message constants being send on notification Number: WM_NCMOUSEHOVER = 0x02A0 Number: WM_MOUSEHOVER = 0x02A1 Number: WM_NCMOUSELEAVE = 0x02A2 Number: WM_MOUSELEAVE = 0x02A3 ! Below the mousemove message as used in the sample Number: WM_MOUSEMOVE = 0x0200
To register a window to receive messages when leaving or hovering the window
! Below register window to receive LEAVE notification Call TrackMouseEvent( 16, TME_LEAVE, hWndForm, 1 ) ! Below register window to receive HOVER notification Call TrackMouseEvent( 16, TME_HOVER, hWndForm, 400 )
The next sample shows an implementation of this feature.
When the user moves the mouse within the window, the message WM_MOUSEMOVE is received.
There the window will be registered to be notified when the mouse is leaving.
A boolean (wbTracking) is used to hold if the window is already registered.
The window will be registered until it receives a notification.
Form Window: frmSample Window Variables Boolean: wbTracking Message Actions On WM_MOUSELEAVE ! The mouse is leaving the window, do custom actions here Set wbTracking = FALSE On WM_MOUSEMOVE If NOT wbTracking If TrackMouseEvent( 16, TME_LEAVE, hWndForm, 1 ) Set wbTracking = TRUE
Here you can download a sample:
How to detect (double) clicks on a window
Several windows messages are send to the window when clicking.
- Received when the user presses the left mousebutton
- Received when the user releases the left mousebutton
- Received when the user doubleclicks the left mousebutton
- Received when the user presses the right mousebutton
- Received when the user releases the right mousebutton
- Received when the user doubleclicks the right mousebutton
Below the constant declarations for the messages:
! Left button Number: WM_LBUTTONDOWN = 0x0201 Number: WM_LBUTTONUP = 0x0202 Number: WM_LBUTTONDBLCLK = 0x0203 ! Right button Number: WM_RBUTTONDOWN = 0x0204 Number: WM_RBUTTONUP = 0x0205 Number: WM_RBUTTONDBLCLK = 0x0206
-> TODO MIDDLE AND X BUTTONS (INCL NC CLICKS)
When a window does not have a caption or you want to be able to drag a window
while clicking anywhere on the window, this is the easiest way.
First you will have to declare the next constants.
Number: WM_NCLBUTTONDOWN = 0x00A1 Number: WM_LBUTTONDOWN = 0x0201 Number: HTCAPTION = 2
When clicking on a window (anywhere in the client area) send a message
to the window indicating the mouse is within the caption area.
Form Window: frmSample Message Actions On WM_LBUTTONDOWN ! The user clicks somewhere in the client area of the window. ! Send a message to trick windows the user has clicked on the caption. ! While moving the mouse, the window will be dragged Call SalSendMsg( hWndForm, WM_NCLBUTTONDOWN, HTCAPTION, NUMBER_Null )
Here you can download a sample:
How to detect/suppress system commands from a window (minimise, maximize, close etc)
A window receives the WM_SYSCOMMAND message when the user presses any of the syscommand options of a window.
First you will have to declare the constant for this message
Number: WM_SYSCOMMAND = 0x0112
The wParam of this message contains the action taken.
Next is a list of all possible action values.
Number: SC_SIZE = 0xF000 Number: SC_MOVE = 0xF010 Number: SC_MINIMIZE = 0xF020 Number: SC_MAXIMIZE = 0xF030 Number: SC_NEXTWINDOW = 0xF040 Number: SC_PREVWINDOW = 0xF050 Number: SC_CLOSE = 0xF060 Number: SC_VSCROLL = 0xF070 Number: SC_HSCROLL = 0xF080 Number: SC_MOUSEMENU = 0xF090 Number: SC_KEYMENU = 0xF100 Number: SC_ARRANGE = 0xF110 Number: SC_RESTORE = 0xF120 Number: SC_TASKLIST = 0xF130 Number: SC_SCREENSAVE = 0xF140 Number: SC_HOTKEY = 0xF150 Number: SC_DEFAULT = 0xF160 Number: SC_MONITORPOWER = 0xF170 Number: SC_CONTEXTHELP = 0xF180 Number: SC_SEPARATOR = 0xF00F
Here is a short description of the values:
- SC_CLOSE - Closes the window.
- SC_CONTEXTHELP - Changes the cursor to a question mark with a pointer. If the user then clicks a control in the dialog box, the control receives a WM_HELP message.
- SC_DEFAULT - Selects the default item; the user double-clicked the window menu.
- SC_HOTKEY - Activates the window associated with the application-specified hot key. The lParam parameter identifies the window to activate.
- SC_HSCROLL - Scrolls horizontally.
- SC_KEYMENU - Retrieves the window menu as a result of a keystroke. For more information, see the Remarks section.
- SC_MAXIMIZE - Maximizes the window.
- SC_MINIMIZE - Minimizes the window.
- SC_MONITORPOWER - Sets the state of the display. This command supports devices that have power-saving features, such as a battery-powered personal computer. The lParam parameter can have the following values: 1 - the display is going to low power 2 - the display is being shut off
- SC_MOUSEMENU - Retrieves the window menu as a result of a mouse click.
- SC_MOVE - Moves the window.
- SC_NEXTWINDOW - Moves to the next window.
- SC_PREVWINDOW - Moves to the previous window.
- SC_RESTORE - Restores the window to its normal position and size.
- SC_SCREENSAVE - Executes the screen saver application specified in the [boot] section of the System.ini file.
- SC_SIZE - Sizes the window.
- SC_TASKLIST - Activates the Start menu.
- SC_VSCROLL - Scrolls vertically.
Catch the message and determine which action was taken
Form Window: frmMain Message actions On WM_SYSCOMMAND Select Case (wParam) Case SC_MINIMIZE // do something here Break Case SC_MAXIMIZE // do something else here Break . . .
These constants can be found in the Windows API archive:
How to detect that CTRL + SPACE was pressed within an graphical Object
The WM_CHAR message is posted to the window with the keyboard focus when a WM_KEYDOWN message is translated by the TranslateMessage function.
The WM_CHAR message contains the character code of the key that was pressed.
For Unicode there is also a WM_UNICHAR Message.
First you will have to declare the constant for this message:
Number: WM_CHAR = 0x0102
The wParam specifies the character code of the key.
The lParam specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table.
0-15 Specifies the repeat count for the current message. The value is the number of times the keystroke is auto repeated as a result of the user holding down the key. If the keystroke is held long enough, multiple messages are sent. However, the repeat count is not cumulative. 16-23 Specifies the scan code. The value depends on the OEM. 24 Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0. 25-28 Reserved; do not use. 29 Specifies the context code. The value is 1 if the ALT key is held down while the key is pressed; otherwise, the value is 0. 30 Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up. 31 Specifies the transition state. The value is 1 if the key is being released, or it is 0 if the key is being pressed.
Catch the message and determine with GetKeyState which Keys has been pressed:
On WM_CHAR If GetKeyState( VK_CONTROL ) < 0 AND GetKeyState( VK_SPACE ) < 0 Return FALSE
To have the GetKeyState Function available you need to declare it in USER32.DLL like the following:
Global Declarations External Functions Library Name: USER32.DLL Function: GetKeyState Export Ordinal: 0 Return: Number: SHORT Parameters: Number: INT
The Constants VK_CONTROLL and VK_SPACE are the following:
Number: VK_CONTROLL = 0x0011 Number: VK_SPACE = 0x0020
The Reason to have a Return FALSE in the On WM_CHAR message is, that otherwise a SPACE-Character would be printed. But in this way nothing will happen.
TODO Translate in correct English and proof if the Links are copied in the right way...
How to detect SysColors have changed
When the user changes the Windows theme or changes any colors for the several GUI elements, Windows will send
message WM_SYSCOLORCHANGE to all top level windows currently present in the system.
When your application is depending or anticipating on special colors, you might want to be informed the System colors have changed. For instance when you do custom painting or display icons/bitmaps in predefined colors and you want to repaint them in the correct wanted color.
First declare this constant:
Number: WM_SYSCOLORCHANGE = 0x0015
Now, trap this message on top level windows. Also send the message to all children to inform them.
Form Window: frmMain Message actions On WM_SYSCOLORCHANGE Call SalSendMsgToChildren( hWndForm, WM_SYSCOLORCHANGE, wParam, lParam )
Depending on your needs, update used icons/bitmaps or repaint the custom drawings.
To get the colors set by the user, you can use the WinAPI function GetSysColor.
This is the declaration
Library name: USER32.dll Function: GetSysColor Returns Number: DWORD Parameters Number: INT
Use the default WinAPI SysColor index values for the input parameter.
You can find the complete list of color index values on GetSysColor.
Or you can find them in SalExtension library and in the sample supplied here.
The next sample shows :
- Detect changes in SysColors
- Show all current SysColors (as picture background colors, RGB values or color values)
- Set SysColors from the sample (using SetSysColors WinAPI). (Beware, it is a system wide setting, not only within the application)
Here you can download the sample:
When the user moves the mouse over the border of a top level window, the cursor is set to a resize icon and the window can be resized.
The locations are left, right, top, bottom and the four corners of the window.
In some situations it could be needed to prevent the user to resize. This can be achieved by the following trick.
When the mouse moves over non-client areas like the border, the message WM_NCHITTEST is send to the window.
By calling the WinAPI function DefWindowProc you can determine which non-client area is hit tested.
When returning HTNOWHERE value in the WM_NCHITTEST message on the several non-client area ID's, the resize is prevented.
There will be no resize icon shown and the window can not be resized on the particular border location.
Here the implementation:
First declare these constants
Number: WM_NCHITTEST = 0x84 ! Number: HTNOWHERE = 0 Number: HTLEFT = 10 Number: HTRIGHT = 11 Number: HTTOP = 12 Number: HTTOPLEFT = 13 Number: HTTOPRIGHT = 14 Number: HTBOTTOM = 15 Number: HTBOTTOMLEFT = 16 Number: HTBOTTOMRIGHT = 17
Also declare DefWindowProc
Library name: USER32.dll Function: DefWindowProcA Export Ordinal: 0 Returns Number: DWORD Parameters Window Handle: HWND Number: UINT Number: WPARAM Number: LPARAM
For TD5.1 and higher, declare DefWindowProcW.
Now, trap WM_NCHITTEST on top level windows.
Form Window: frmMain Message actions On WM_NCHITTEST Set nRet = DefWindowProcA( hWndForm, WM_NCHITTEST, wParam, lParam ) ! Use the next line in TD5.x Set nRet = DefWindowProcW( hWndFrame, WM_NCHITTEST, wParam, lParam ) Select Case nRet Case HTLEFT Case HTRIGHT Case HTBOTTOM Case HTTOP Case HTBOTTOMLEFT Case HTBOTTOMRIGHT Case HTTOPLEFT Case HTTOPRIGHT Return HTNOWHERE
In the code above, all 8 locations are prevented from resize.
To prevent only certain locations, change the code so only for that particular HT area the HTNOWHERE value is returned.
Here you can download a sample:
Here the sample for TD version 5.1 and higher (UNICODE):
These samples contain more HT constants (eg HTCAPTION) to handle other NC areas if needed.