190 likes | 559 Views
Mouse And Keyboard. Jim Fawcett Derived from a presentation by Dmitri Volper Su ‘2001. Win32 messaging system. Mouse and keyboard input comes in the form of messages:. Window. Getting input from the mouse. Client-Area Mouse Messages:
E N D
Mouse And Keyboard Jim Fawcett Derived from a presentation by Dmitri Volper Su ‘2001
Win32 messaging system • Mouse and keyboard input comes in the form of messages:
Getting input from the mouse • Client-Area Mouse Messages: • Format: WM_{ L R M } BUTTON { DOWN UP DBLCLK } WM_MOUSEMOVE • Handling function: afx_msg void On{ L R M }Button { Down Up DblClk } (UINT nFlags, Cpoint point)afx_msg void OnMouseMove (UINT nFlags, Cpoint point) • nFlags specifies the state of the mouse buttons and the Shift and Ctrl key at the time the message was generated (The expression nFlags & MK_LBUTTONis nonzero if and only if the left mouse button was pressed) • point is a location of the cursor (in client coordinates) at the time the message was generated (point.x and point.y)
Some remarks • Is there a mouse? • ::GetSystemMetrics (SM_MOUSEPRESENT) != 0 • Number of buttons • int nButtonCount = ::GetSystemMetrics (SM_CMOUSEBUTTONS); • Get double click time::GetDoubleClickTime () • Set double click time::SetDoubleClickTime (250); • Sequence for double click: • WM_LBUTTONDOWN • WM_LBUTTONUP • WM_LBUTTONDBLCLK • WM_LBUTTONUP
Getting input from the mouse (cont) • Nonclient-Area Mouse Messages: • Format: WM_NC{ L R M } BUTTON { DOWN UP DBLCLK } WM_NCMOUSEMOVE • Handling function: afx_msg void OnNc{ L R M }Button { Down Up DblClk } (UINT nHitTest, Cpoint point)afx_msg void OnNcMouseMove (UINT nHitTest, Cpoint point) • nHitTest parameter contains a hit-test code that identifies where in the window's nonclient area the event occurred ( nHitTest != HTCAPTION ) • point is a location of the cursor (in screen coordinates) at the time the message was generated (point.x and point.y) • If you want, you can convert screen coordinates to client coordinates with CWnd::ScreenToClient.
Remarks • Propagate nonclient mouse messages to the base window class - it • CFrameWnd::OnNcLButtonDown (nHitTest, point); • Some of the hit-test codes: HTCAPTION The title bar HTCLOSE The close button HTHSCROLL The window's horizontal scroll bar HTMENU The menu bar HTREDUCE The minimize button HTSIZE The restore button (same as HTGROWBOX) HTSYSMENU The system menu box HTVSCROLL The window's vertical scroll bar HTZOOM The maximize button
The WM_NCHITTEST Message • Before a window receives a client-area or nonclient-area mouse message, it receives a WM_NCHITTEST message accompanied by the cursor's screen coordinates. • Most applications do not process WM_NCHITTEST message • But, the next code may be used to substitute HTCLIENTbyHTCAPTION (so that client may drag windows by clicking the client area) • // In CMainWindow's message map ON_WM_NCHITTEST () • UINT CMainWindow::OnNcHitTest (CPoint point) • { UINT nHitTest = CFrameWnd::OnNcHitTest (point); • if (nHitTest == HTCLIENT) nHitTest = HTCAPTION; • return nHitTest; } • Forward WM_NCHITTEST messages that you do not process yourself
The WM_MOUSELEAVE and WM_MOUSEHOVER Messages • It is easy to tell if the mouse is moving over the client-area. How can you differentiate between mouse hovering over some place and mouse outside the client area? • Use ::TrackMouseEvent function to register for WM_MOUSELEAVE and WM_MOUSEHOVER Messages • You have to restart ::TrackMouseEvent function each time you receive WM_MOUSELEAVE and WM_MOUSEHOVER messages • Include #define _WIN32_WINNT 0x0400anywhere before #include <afxwin.h> • MFC doesn't provide type-specific message-mapping macros for WM_MOUSELEAVE and WM_MOUSEHOVER messages, so you must use the ON_MESSAGE macro to link these messages to class member functions// In the message map ON_MESSAGE (WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE (WM_MOUSEHOVER, OnMouseHover)
Capturing the mouse • Sometimes you have to receive mouse messages even if the mouse is outside the window • For example you want to be sure that button down message will be followed by button up • Some graphical applications might use mouse position outside the window • The mouse is captured with CWnd::SetCapture and released with ::ReleaseCapture: • void CMainWindow::OnLButtonDown (UINT nFlags, CPoint point) { SetCapture (); } • void CMainWindow::OnLButtonUp (UINT nFlags, CPoint point) • { if (GetCapture () == this) ::ReleaseCapture (); } • messages use client coordinates • if button is depressed, mouse is released automatically
Mouse Miscellanea • ::GetDoubleClickTime () • ::SetDoubleClickTime (250); • ::GetKeyState (VK_LBUTTON) – logical left button (or “select button”) • ::GetAsyncKeyState (VK_LBUTTON) – physical left button • ::GetAsyncKeyState (::GetSystemMetrics (SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON) • Is the same as • ::GetKeyState (VK_LBUTTON) • ::GetCursorPos and ::SetCursorPos use POINT structure • ::GetMessagePos
Getting input from the keyboard (focus) • Keyboard input comes in the form of messages • Window that owns the focus gets those messages • System notifies the window when it loses or receives the focus: ON_WM_SETFOCUS () ON_WM_KILLFOCUS () void CMainWindow::OnSetFocus (CWnd* pOldWnd) void CMainWindow::OnKillFocus (CWnd* pNewWnd) • An application can shift the input focus pWnd->SetFocus (); • To find out who currently has the input focus CWnd* pFocusWnd = CWnd::GetFocus (); • Window handler is NULL if owned by a different thread
Getting input from the keyboard (messages) • Possible keyboard (keystroke) messages and corresponding member function are • ON_WM_KEYDOWN OnKeyDown • ON_WM_KEYUP OnKeyUp • ON_WM_SYSKEYDOWN OnSysKeyDown • ON_WM_SYSKEYUP OnSysKeyUp • Keystroke message handlers are prototyped as follows: afx_msg void OnMsgName (UINT nChar, UINT nRepCnt, UINT nFlags) • nChar is the virtual key code of the key that was pressed or released (VK_MENU – Alt, VK_PAUSE – Pause, VK_ESCAPE – Esc, VK_SPACE – Spacebar,…) • nRepCnt is the repeat count (always 1 for WM_KEYUP or WM_SYSKEYUP messages)
Getting input from the keyboard (messages) • The nFlags parameter contains the key's scan code and zero or more of the bit flags described here: Bit(s) Meaning Description 0_7 OEM scan code 8-bit OEM scan code 8 Extended key flag 1 if the key is an extended key, 0 if it is not 9_12 Reserved N/A 13 Context code 1 if the Alt key is pressed, 0 if it is not 14 Previous key state 1 if the key was previously pressed, 0 if it was up 15 Transition state 0 if the key is being pressed, 1 if it is being released • the extended key flag is set for the Ctrl and Alt keys on the right side of the keyboard; the Home, End, Insert, Delete, Page Up, Page Down, and arrow keys that are clustered between the main part of the keyboard and the numeric keypad; and the keypad's Enter and forward-slash (/) keys.
Combinations • When you write handlers for keystroke messages, you might need to know whether the Shift, Ctrl, or Alt key is held down. • ::GetKeyState (VK_SHIFT) is negative then Shift is held down( same for VK_Menu (Alt) and VK_CONTROL (Ctrl) ) ( reminder – we already saw this function in the mouse section ) • ::GetKeyState (VK_NUMLOCK) & 0x01 is nonzero if Num Lock is on::GetKeyState (VK_NUMLOCK) & 0x10 is nonzero if Num Lock is pressed ( I couldn’t make the last to work) ( same for VK_CAPITAL (Caps Lock) and VK_SCROLL (Scroll Lock) ) • If calling NOT from keystroke message handler use ::GetAsyncKeyState
The Word of Caution • In general, applications shouldn't process WM_SYSKEYDOWN and WM_SYSKEYUP messages; they should let Windows process them instead. If these messages don't eventually find their way to ::DefWindowProc, system keyboard commands such as Alt-Tab and Alt-Esc will stop working (Alt-Ctrl-Del ?) • Propagate CWnd::OnSysKeyDown (nChar, nRepCnt, nFlags); • One more problem: the case of a character depends on the state of SHIFT and CAPS LOCK (4 combinations) • Even worse: Shift-2 means “ in Russian keyboard and @ in American layout.
Character messages • Solution for the problem stated on the previous page is ::TranslateMessage. This API function converts keystrokes into WM_CHAR messages • WM_KEYDOWN WM_SYSKEYDOWN • WM_CHAR WM_SYSCHAR • WM_ KEYUP WM_ SYSKEYUP • function formatafx_msg void OnChar (UINT nChar, UINT nRepCnt, UINT nFlags) • nRepCnt, and nFlags have the same meaning as before. • nChar holds an ANSI or Unicode character code.
Character messages // In CMainWindow's message mapON_WM_CHAR () void CMainWindow::OnChar (UINT nChar, UINT nRepCnt, UINT nFlags) { if (((nChar >= _T (`A')) && (nChar <= _T (`Z'))) || ((nChar >= _T (`a')) && (nChar <= _T (`z')))) { // Display the character } else if (nChar == VK_RETURN) { // Process the Enter key } else if (nChar == VK_BACK) { // Process the Backspace key } }
Dead-Key Messages • ON_WM_DEADCHAR or ON_WM_SYSDEADCHAR