Mouse And Keyboard

Document Sample
Mouse And Keyboard Powered By Docstoc
					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:

                                                                         dedicated thread
                                Device drivers                           owned by
                                                     raw input queue     operating system

                                          thread 1        thread 2     thread 3       thread 4

                   non-client area

Client area

         Getting input from the mouse

•   Client-Area Mouse Messages:
     • Format:    WM_{ L R M } BUTTON { DOWN UP DBLCLK }
     • 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_LBUTTON
        is 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
•   Get double click time
          ::GetDoubleClickTime ()
•   Set double click time
          ::SetDoubleClickTime (250);
•   Sequence for double click:
    Getting input from the mouse (cont)

•   Nonclient-Area Mouse Messages:
     • Format:    WM_NC{ L R M } BUTTON { DOWN UP DBLCLK }
     • 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

•   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 HTCLIENT by HTCAPTION
  (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
    •    You have to restart ::TrackMouseEvent function each time you receive
         WM_MOUSELEAVE and WM_MOUSEHOVER messages
    •    Include
                   #define _WIN32_WINNT 0x0400
         anywhere 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
   •    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) ?
                       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
     –   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
         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.

   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
                  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
                      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 format
    afx_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
    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