SCRAWL.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:31k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /**************************************************************************
  2.     SCRAWL.CPP - A dumb drawing app demo for DirectInput
  3.     Collects mouse data in various modes to demonstrate how it's done.
  4.  **************************************************************************/
  5. /**************************************************************************
  6.     (C) Copyright 1995-1997 Microsoft Corp.  All rights reserved.
  7.     You have a royalty-free right to use, modify, reproduce and
  8.     distribute the Sample Files (and/or any modified version) in
  9.     any way you find useful, provided that you agree that
  10.     Microsoft has no warranty obligations or liability for any
  11.     Sample Application Files which are modified.
  12.  **************************************************************************/
  13. #include <windows.h>
  14. #include <windowsx.h>
  15. #include <stdarg.h>
  16. #define DIRECTINPUT_VERSION 0x0300      /* Remain DX3-compatible */
  17. #include <dinput.h>
  18. #include "scrawl.h"
  19. /****************************************************************************
  20.  *
  21.  *      This is an incredibly dump app.  It just lets you "draw" on
  22.  *      a monochrome bitmap via DirectInput.  The purpose is not to
  23.  *      dazzle you with mind-altering brilliance.  It's just to show
  24.  *      how to use the DirectInput mouse interface.
  25.  *
  26.  ****************************************************************************/
  27. /****************************************************************************
  28.  *
  29.  *      Manifest constants
  30.  *
  31.  ****************************************************************************/
  32. #define DINPUT_BUFFERSIZE           16
  33. #define DINPUT_CXBITMAP             512
  34. #define DINPUT_CYBITMAP             300
  35. /****************************************************************************
  36.  *
  37.  *      Global variables
  38.  *
  39.  ****************************************************************************/
  40. const char c_szAppName[] = "Scrawl";    /* My name */
  41. HINSTANCE  g_hinst;                     /* My instance handle */
  42. BOOL       g_fActive;                   /* Am I the active window? */
  43. int        g_x = DINPUT_CXBITMAP / 2;   /* Virtual x-coordinate */
  44. int        g_y = DINPUT_CYBITMAP / 2;   /* Virtual y-coordinate */
  45. int        g_dxFuzz;                    /* Leftover x-fuzz from scaling */
  46. int        g_dyFuzz;                    /* Leftover y-fuzz from scaling */
  47. int        g_iSensitivity;              /* Mouse sensitivity */
  48. HDC        g_hdc;                       /* Memory DC our picture lives in */
  49. HBITMAP    g_hbm;                       /* Our picture */
  50. HBITMAP    g_hbmDeselect;               /* Stock bitmap for deselecting */
  51. HCURSOR    g_hcurCross;                 /* Crosshairs */
  52. int        g_cxCross;                   /* Width of crosshairs cursor */
  53. int        g_cyCross;                   /* Height of crosshairs cursor */
  54. int        g_dxCrossHot;                /* Hotspot location of crosshairs */
  55. int        g_dyCrossHot;                /* Hotspot location of crosshairs */
  56. int        g_fShowCursor = 1;           /* Should the cursor be shown? */
  57. /****************************************************************************
  58.  *
  59.  *      DirectInput globals
  60.  *
  61.  ****************************************************************************/
  62. LPDIRECTINPUT          g_pdi;
  63. LPDIRECTINPUTDEVICE    g_pMouse;
  64. HANDLE                 g_hevtMouse;
  65. /****************************************************************************
  66.  *
  67.  *      Complain
  68.  *
  69.  *      Whine and moan.
  70.  *
  71.  ****************************************************************************/
  72. void CDECL
  73. Complain(HWND hwndOwner, HRESULT hr, LPCSTR pszFormat, ...)
  74. {
  75.     va_list ap;
  76.     char szBuf[1024];
  77.     char *pszBuf;
  78.     va_start(ap, pszFormat);
  79.     pszBuf = szBuf + wsprintf(szBuf, pszFormat, ap);
  80.     va_end(ap);
  81.     wsprintf(pszBuf, "nnError = %08x", hr);
  82.     MessageBox(hwndOwner, szBuf, c_szAppName, MB_OK);
  83. }
  84. /****************************************************************************
  85.  *
  86.  *      DIInit
  87.  *
  88.  *      Initialize the DirectInput variables.
  89.  *
  90.  ****************************************************************************/
  91. BOOL DIInit(HWND hwnd)
  92. {
  93.     HRESULT hr;
  94.     /*
  95.      *  Register with DirectInput and get an IDirectInput to play with.
  96.      */
  97.     hr = DirectInputCreate(g_hinst, DIRECTINPUT_VERSION, &g_pdi, NULL);
  98.     if (FAILED(hr)) {
  99.         Complain(hwnd, hr, "DirectInputCreate");
  100.         return FALSE;
  101.     }
  102.     /*
  103.      *  Obtain an interface to the system mouse device.
  104.      */
  105.     hr = g_pdi->CreateDevice(GUID_SysMouse, &g_pMouse, NULL);
  106.     if (FAILED(hr)) {
  107.         Complain(hwnd, hr, "CreateDevice(SysMouse)");
  108.         return FALSE;
  109.     }
  110.     /*
  111.      *  Set the data format to "mouse format".
  112.      */
  113.     hr = g_pMouse->SetDataFormat(&c_dfDIMouse);
  114.     if (FAILED(hr)) {
  115.         Complain(hwnd, hr, "SetDataFormat(SysMouse, dfDIMouse)");
  116.         return FALSE;
  117.     }
  118.     /*
  119.      *  Set the cooperativity level.
  120.      */
  121.     hr = g_pMouse->SetCooperativeLevel(hwnd,
  122.                                        DISCL_EXCLUSIVE | DISCL_FOREGROUND);
  123.     if (FAILED(hr)) {
  124.         Complain(hwnd, hr, "SetCooperativeLevel(SysMouse)");
  125.         return FALSE;
  126.     }
  127.     /*
  128.      *  Create the handle that tells us new data is available.
  129.      */
  130.     g_hevtMouse = CreateEvent(0, 0, 0, 0);
  131.     if (g_hevtMouse == NULL) {
  132.         Complain(hwnd, GetLastError(), "CreateEvent");
  133.         return FALSE;
  134.     }
  135.     /*
  136.      *  Associate the event with the device.
  137.      */
  138.     hr = g_pMouse->SetEventNotification(g_hevtMouse);
  139.     if (FAILED(hr)) {
  140.         Complain(hwnd, hr, "SetEventNotification(SysMouse)");
  141.         return FALSE;
  142.     }
  143.     /*
  144.      *  Set the buffer size to DINPUT_BUFFERSIZE elements.
  145.      *  The buffer size is a DWORD property associated with the device.
  146.      */
  147.     DIPROPDWORD dipdw =
  148.         {
  149.             {
  150.                 sizeof(DIPROPDWORD),        // diph.dwSize
  151.                 sizeof(DIPROPHEADER),       // diph.dwHeaderSize
  152.                 0,                          // diph.dwObj
  153.                 DIPH_DEVICE,                // diph.dwHow
  154.             },
  155.             DINPUT_BUFFERSIZE,              // dwData
  156.         };
  157.     hr = g_pMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph);
  158.     if (FAILED(hr)) {
  159.         Complain(hwnd, hr, "Set buffer size(SysMouse)");
  160.         return FALSE;
  161.     }
  162.     return TRUE;
  163. }
  164. /****************************************************************************
  165.  *
  166.  *      DITerm
  167.  *
  168.  *      Terminate our usage of DirectInput.
  169.  *
  170.  ****************************************************************************/
  171. void DITerm(void)
  172. {
  173.     if (g_pdi)      g_pdi   ->Release(), g_pdi    = NULL;
  174.     if (g_pMouse)   g_pMouse->Release(), g_pMouse = NULL;
  175.     if (g_hevtMouse) CloseHandle(g_hevtMouse), g_hevtMouse = NULL;
  176. }
  177. /****************************************************************************
  178.  *
  179.  *      InvalidateCursorRect
  180.  *
  181.  *      Invalidate the rectangle that contains the cursor.
  182.  *
  183.  *      The coordinates are in client coordinates.
  184.  *
  185.  ****************************************************************************/
  186. void InvalidateCursorRect(HWND hwnd)
  187. {
  188.     RECT rc = { g_x - g_dxCrossHot,             g_y - g_dyCrossHot,
  189.                 g_x - g_dxCrossHot + g_cxCross, g_y - g_dyCrossHot + g_cyCross };
  190.     InvalidateRect(hwnd, &rc, 0);
  191. }
  192. /****************************************************************************
  193.  *
  194.  *      UpdateCursorPosition
  195.  *
  196.  *      Move our private cursor in the requested direction, subject
  197.  *      to clipping, scaling, and all that other stuff.
  198.  *
  199.  *      This does not redraw the cursor.  You need to do that yourself.
  200.  *
  201.  ****************************************************************************/
  202. void UpdateCursorPosition(int dx, int dy)
  203. {
  204.     /*
  205.      *  Pick up any leftover fuzz from last time.  This is important
  206.      *  when scaling down mouse motions.  Otherwise, the user can
  207.      *  drag to the right extremely slow for the length of the table
  208.      *  and not get anywhere.
  209.      */
  210.     dx += g_dxFuzz;     g_dxFuzz = 0;
  211.     dy += g_dyFuzz;     g_dyFuzz = 0;
  212.     switch (g_iSensitivity) {
  213.     case 1:                             /* High sensitivity: Magnify! */
  214.         dx *= 2;
  215.         dy *= 2;
  216.         break;
  217.     case -1:                            /* Low sensitivity: Scale down */
  218.         g_dxFuzz = dx % 2;              /* remember the fuzz for next time */
  219.         g_dyFuzz = dy % 2;
  220.         dx /= 2;
  221.         dy /= 2;
  222.         break;
  223.     default:
  224.     case 0:                             /* No sensitivity */
  225.         ;                               /* No adjustments needed */
  226.     }
  227.     g_x += dx;
  228.     g_y += dy;
  229.     /* Clip the cursor to our client area */
  230.     if (g_x < 0)                g_x = 0;
  231.     if (g_x >= DINPUT_CXBITMAP) g_x = DINPUT_CXBITMAP - 1;
  232.     if (g_y < 0)                g_y = 0;
  233.     if (g_y >= DINPUT_CYBITMAP) g_y = DINPUT_CYBITMAP - 1;
  234. }
  235. /****************************************************************************
  236.  *
  237.  *      Scrawl_SyncAcquire
  238.  *
  239.  *      Acquire or unacquire the devices, depending on the the g_fActive
  240.  *      flag.  This synchronizes the devices with our internal view of
  241.  *      the world.
  242.  *
  243.  *      Also repaint the cursor so that it hides/shows in sync with
  244.  *      acquisition.
  245.  *
  246.  ****************************************************************************/
  247. void
  248. Scrawl_SyncAcquire(HWND hwnd)
  249. {
  250.     if (g_fActive) {
  251.         if (g_pMouse) g_pMouse->Acquire();
  252.     } else {
  253.         if (g_pMouse) g_pMouse->Unacquire();
  254.     }
  255.     InvalidateCursorRect(hwnd);
  256. }
  257. /****************************************************************************
  258.  *
  259.  *      Private messages
  260.  *
  261.  *      WM_SYNCACQUIRE forces us to re-synchronize our acquisition
  262.  *      with the world.
  263.  *
  264.  ****************************************************************************/
  265. #define WM_SYNCACQUIRE      (WM_USER + 0)
  266. /****************************************************************************
  267.  *
  268.  *      Scrawl_OnClear
  269.  *
  270.  *      Wipe out the bitmap.
  271.  *
  272.  ****************************************************************************/
  273. void Scrawl_OnClear(HWND hwnd)
  274. {
  275.     /*
  276.      *  Start out all white.
  277.      */
  278.     PatBlt(g_hdc, 0, 0, DINPUT_CXBITMAP, DINPUT_CYBITMAP, WHITENESS);
  279.     if (hwnd) {
  280.         InvalidateRect(hwnd, 0, 0);
  281.     }
  282. }
  283. /****************************************************************************
  284.  *
  285.  *      Scrawl_OnCreate
  286.  *
  287.  *      Set up the window by appending our custom commands to the System
  288.  *      menu.
  289.  *
  290.  *      Also disable the menu items we don't want to see.
  291.  *
  292.  ****************************************************************************/
  293. BOOL Scrawl_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
  294. {
  295.     HMENU hmenu = GetSystemMenu(hwnd, FALSE);
  296.     EnableMenuItem(hmenu, SC_SIZE,     MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  297.     EnableMenuItem(hmenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  298.     AppendMenu(hmenu, MF_ENABLED | MF_STRING, IDC_CLEAR, "C&leartDel");
  299.     AppendMenu(hmenu, MF_ENABLED | MF_STRING, IDC_ABOUT, "&AbouttF1");
  300.     AppendMenu(hmenu, MF_ENABLED | MF_STRING | MF_POPUP,
  301.                       (UINT)LoadMenu(g_hinst,
  302.                                      MAKEINTRESOURCE(IDM_SENSITIVITY)),
  303.                      "Sensitivit&y");
  304.     return 1;
  305. }
  306. /****************************************************************************
  307.  *
  308.  *      Scrawl_OnInitMenuPopup
  309.  *
  310.  *      Initialize the sensitivity item accordingly.
  311.  *
  312.  ****************************************************************************/
  313. void
  314. Scrawl_OnInitMenuPopup(HWND hwnd, HMENU hmenu, UINT item, BOOL fSystemMenu)
  315. {
  316.     int iSensitivity;
  317.     for (iSensitivity = -1; iSensitivity <= 1; iSensitivity++) {
  318.         if (g_iSensitivity == iSensitivity) {
  319.             CheckMenuItem(hmenu, IDC_SENSITIVITY_NORMAL + iSensitivity,
  320.                           MF_BYCOMMAND | MF_CHECKED);
  321.         } else {
  322.             CheckMenuItem(hmenu, IDC_SENSITIVITY_NORMAL + iSensitivity,
  323.                           MF_BYCOMMAND | MF_UNCHECKED);
  324.         }
  325.     }
  326. }
  327. /****************************************************************************
  328.  *
  329.  *      Scrawl_OnKeyDown
  330.  *
  331.  *      See if it's one of our accelerators.
  332.  *
  333.  ****************************************************************************/
  334. void Scrawl_OnKeyDown(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags)
  335. {
  336.     switch (vk) {
  337.     case '1':
  338.     case '2':
  339.     case '3':
  340.         PostMessage(hwnd, WM_SYSCOMMAND, IDC_SENSITIVITY_NORMAL +
  341.                                          vk - '2', 0);
  342.         break;
  343.     case VK_DELETE:
  344.         PostMessage(hwnd, WM_SYSCOMMAND, IDC_CLEAR, 0);
  345.         break;
  346.     case VK_F1:
  347.         PostMessage(hwnd, WM_SYSCOMMAND, IDC_ABOUT, 0);
  348.         break;
  349.     }
  350. }
  351. /****************************************************************************
  352.  *
  353.  *      Scrawl_OnPaint
  354.  *
  355.  *      Blt out our bitmap and draw our cursor on top of it.
  356.  *
  357.  ****************************************************************************/
  358. void
  359. Scrawl_OnPaint(HWND hwnd)
  360. {
  361.     PAINTSTRUCT ps;
  362.     HDC hdc = BeginPaint(hwnd, &ps);
  363.     if (hdc) {
  364.         BitBlt(hdc,
  365.                ps.rcPaint.left,
  366.                ps.rcPaint.top,
  367.                ps.rcPaint.right - ps.rcPaint.left,
  368.                ps.rcPaint.bottom - ps.rcPaint.top,
  369.                g_hdc,
  370.                ps.rcPaint.left,
  371.                ps.rcPaint.top,
  372.                SRCCOPY);
  373.         if (g_fActive && g_fShowCursor) {
  374.             DrawIcon(hdc, g_x - g_dxCrossHot,
  375.                           g_y - g_dyCrossHot, g_hcurCross);
  376.         }
  377.         EndPaint(hwnd, &ps);
  378.     }
  379. }
  380. /****************************************************************************
  381.  *
  382.  *      Scrawl_OnButton0Down_FlushMotion
  383.  *
  384.  *      Flush out any motion that we are holding.
  385.  *
  386.  ****************************************************************************/
  387. typedef struct BUTTON0INFO {
  388.     HDC hdcWindow;
  389.     BOOL fMoved;
  390.     DWORD dwSeqLastSeen;
  391. } BUTTON0INFO, *PBUTTON0INFO;
  392. void Scrawl_OnButton0Down_FlushMotion(PBUTTON0INFO pb0i)
  393. {
  394.     if (pb0i->fMoved) {
  395.         pb0i->fMoved = 0;
  396.         pb0i->dwSeqLastSeen = 0;
  397.         LineTo(pb0i->hdcWindow, g_x, g_y);
  398.         LineTo(g_hdc, g_x, g_y);
  399.     }
  400. }
  401. /****************************************************************************
  402.  *
  403.  *      Scrawl_OnButton0Down
  404.  *
  405.  *      Enter draw mode.
  406.  *
  407.  *      If we are drawing a curve, then read buffered data and draw
  408.  *      lines from point to point.  By reading buffered data, we can
  409.  *      track the motion of the mouse accurately without coalescing.
  410.  *
  411.  *      This function illustrates how a non-message-based program can
  412.  *      process buffered data directly from a device, processing
  413.  *      messages only occasionally (as required by Windows).
  414.  *
  415.  *      This function also illustrates how an application can piece
  416.  *      together buffered data elements based on the sequence number.
  417.  *      A single mouse action (e.g., moving diagonally) is reported
  418.  *      as a series of events, all with the same sequence number.
  419.  *      Zero is never a valid DirectInput sequence number, so it is
  420.  *      safe to use it as a sentinel value.
  421.  *
  422.  ****************************************************************************/
  423. void Scrawl_OnButton0Down(HWND hwnd)
  424. {
  425.     BUTTON0INFO b0i;
  426.     /* Hide the cursor while scrawling */
  427.     g_fShowCursor = FALSE;
  428.     InvalidateCursorRect(hwnd);
  429.     UpdateWindow(hwnd);
  430.     /*
  431.      *  For performance, draw directly onto the window's DC instead of
  432.      *  invalidating and waiting for the WM_PAINT message.  Of course,
  433.      *  we always draw onto our bitmap, too, since that's what really
  434.      *  counts.
  435.      */
  436.     /* BUGBUG -- select a decent pen, too */
  437.     b0i.hdcWindow = GetDC(hwnd);
  438.     MoveToEx(b0i.hdcWindow, g_x, g_y, 0);
  439.     MoveToEx(g_hdc, g_x, g_y, 0);
  440.     /* BUGBUG -- save old pen */
  441.     SelectObject(b0i.hdcWindow, GetStockObject(BLACK_PEN));
  442.     SelectObject(g_hdc, GetStockObject(BLACK_PEN));
  443.     b0i.fMoved = 0;
  444.     b0i.dwSeqLastSeen = 0;
  445.     /*
  446.      *  Keep reading data elements until we see a "mouse button up" event.
  447.      */
  448.     BOOL fDone = 0;
  449.     while (!fDone) {
  450.         DIDEVICEOBJECTDATA od;
  451.         DWORD dwElements = 1;
  452.         HRESULT hr = g_pMouse->GetDeviceData(
  453.                              sizeof(DIDEVICEOBJECTDATA), &od,
  454.                              &dwElements, 0);
  455.         /* Unable to read data */
  456.         if (FAILED(hr)) {
  457.             break;
  458.         }
  459.         /*
  460.          *  If no data available, finish the element we had been
  461.          *  collecting, and then process our message queue so
  462.          * the system don't think we're hung.
  463.          */
  464.         if (dwElements == 0) {
  465.             /* If there is a partial motion, flush it out */
  466.             Scrawl_OnButton0Down_FlushMotion(&b0i);
  467.             MSG msg;
  468.             while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  469.                 /* If it's a quit message, we're outta here */
  470.                 if (msg.message == WM_QUIT) {
  471.                     fDone = TRUE;
  472.                     /*
  473.                      * Re-post the quit message so the
  474.                      * outer loop will see it and exit.
  475.                      */
  476.                     PostQuitMessage(msg.wParam);
  477.                     break;
  478.                 } else {
  479.                     TranslateMessage(&msg);
  480.                     DispatchMessage(&msg);
  481.                 }
  482.             }
  483.             continue;
  484.         }
  485.         /* If this is the start of a new event, flush out the old one */
  486.         if (od.dwSequence != b0i.dwSeqLastSeen) {
  487.             Scrawl_OnButton0Down_FlushMotion(&b0i);
  488.             b0i.dwSeqLastSeen = od.dwSequence;
  489.         }
  490.         /* Look at the element to see what happened */
  491.         switch (od.dwOfs) {
  492.         /* DIMOFS_X: Mouse horizontal motion */
  493.         case DIMOFS_X:
  494.             UpdateCursorPosition(od.dwData, 0);
  495.             b0i.fMoved = 1;
  496.             break;
  497.         /* DIMOFS_Y: Mouse vertical motion */
  498.         case DIMOFS_Y:
  499.             UpdateCursorPosition(0, od.dwData);
  500.             b0i.fMoved = 1;
  501.             break;
  502.         /* DIMOFS_BUTTON0: Button 0 pressed or released */
  503.         case DIMOFS_BUTTON0:
  504.             if (!(od.dwData & 0x80)) { /* Button released */
  505.                 fDone = 1;
  506.                 Scrawl_OnButton0Down_FlushMotion(&b0i); /* Flush out dregs */
  507.             }
  508.             break;
  509.         }
  510.     }
  511.     ReleaseDC(hwnd, b0i.hdcWindow);
  512.     /* Re-show the cursor now that scrawling is finished */
  513.     g_fShowCursor = TRUE;
  514.     InvalidateCursorRect(hwnd);
  515. }
  516. /****************************************************************************
  517.  *
  518.  *      Scrawl_OnButton1Up
  519.  *
  520.  *      Pop up a context menu.
  521.  *
  522.  ****************************************************************************/
  523. void Scrawl_OnButton1Up(HWND hwnd)
  524. {
  525.     POINT pt = { g_x, g_y };
  526.     ClientToScreen(hwnd, &pt);
  527.     /*
  528.      *  Unacquire the devices so the user can interact with the menu.
  529.      *
  530.      *  Put the Windows cursor at the same location as our virtual cursor.
  531.      *
  532.      *  Hide the cursor while moving it so you don't get annoying flicker.
  533.      */
  534.     ShowCursor(FALSE);
  535.     g_fActive = FALSE;
  536.     Scrawl_SyncAcquire(hwnd);
  537.     SetCursorPos(pt.x, pt.y);
  538.     ShowCursor(TRUE);
  539.     HMENU hmenuPopup = GetSystemMenu(hwnd, FALSE);
  540.     UINT idc = TrackPopupMenuEx(hmenuPopup,
  541.                                 TPM_RIGHTBUTTON | TPM_RETURNCMD,
  542.                                 pt.x, pt.y, hwnd, 0);
  543.     PostMessage(hwnd, WM_SYSCOMMAND, idc, 0L);
  544. }
  545. /****************************************************************************
  546.  *
  547.  *      Scrawl_OnMouseInput
  548.  *
  549.  *      The mouse moved while nothing was happening.  Walk the event list
  550.  *      and update the mouse position for each event.  If we see a button
  551.  *      event, then stop pulling events and leave the elements in the
  552.  *      input buffer for the drawing handler to pull.
  553.  *
  554.  *
  555.  ****************************************************************************/
  556. void
  557. Scrawl_OnMouseInput(HWND hwnd)
  558. {
  559.     /* Invalidate the old cursor so it will be erased */
  560.     InvalidateCursorRect(hwnd);
  561.     /*
  562.      *  Attempt to read one data element.  Continue as long as
  563.      *  device data is available.
  564.      */
  565.     BOOL fDone = 0;
  566.     while (!fDone) {
  567.         DIDEVICEOBJECTDATA od;
  568.         DWORD dwElements = 1;
  569.         HRESULT hr = g_pMouse->GetDeviceData(
  570.                              sizeof(DIDEVICEOBJECTDATA), &od,
  571.                              &dwElements, 0);
  572.         if (hr == DIERR_INPUTLOST) {
  573.             /*
  574.              *  We had acquisition, but lost it.  Try to reacquire it.
  575.              *
  576.              *  WARNING!  DO NOT ATTEMPT TO REACQUIRE IF YOU GET
  577.              *  DIERR_NOTACQUIRED!  Otherwise, you're extremely likely
  578.              *  to get caught in an infinite loop:  The acquire will fail,
  579.              *  and you'll get another DIERR_NOTACQUIRED so you'll
  580.              *  try to aquire again, and that'll fail, etc.
  581.              */
  582.             PostMessage(hwnd, WM_SYNCACQUIRE, 0, 0L);
  583.             break;
  584.         }
  585.         /* Unable to read data or no data available */
  586.         if (FAILED(hr) || dwElements == 0) {
  587.             break;
  588.         }
  589.         /* Look at the element to see what happened */
  590.         switch (od.dwOfs) {
  591.         /* DIMOFS_X: Mouse horizontal motion */
  592.         case DIMOFS_X: UpdateCursorPosition(od.dwData, 0); break;
  593.         /* DIMOFS_Y: Mouse vertical motion */
  594.         case DIMOFS_Y: UpdateCursorPosition(0, od.dwData); break;
  595.         /* DIMOFS_BUTTON0: Button 0 pressed or released */
  596.         case DIMOFS_BUTTON0:
  597.             if (od.dwData & 0x80) { /* Button pressed */
  598.                 fDone = 1;
  599.                 Scrawl_OnButton0Down(hwnd); /* Go into button-down mode */
  600.             }
  601.             break;
  602.         /* DIMOFS_BUTTON1: Button 1 pressed or released */
  603.         case DIMOFS_BUTTON1:
  604.             if (!(od.dwData & 0x80)) {  /* Button released */
  605.                 fDone = 1;
  606.                 Scrawl_OnButton1Up(hwnd); /* Context menu time */
  607.             }
  608.         }
  609.     }
  610.     /* Invalidate the new cursor so it will be drawn */
  611.     InvalidateCursorRect(hwnd);
  612. }
  613. /****************************************************************************
  614.  *
  615.  *      ScrawlWndProc
  616.  *
  617.  *      Application window procedure.
  618.  *
  619.  ****************************************************************************/
  620. LONG CALLBACK ScrawlWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
  621. {
  622.     switch (msg) {
  623.     HANDLE_MSG(hwnd, WM_CREATE, Scrawl_OnCreate);
  624.     HANDLE_MSG(hwnd, WM_PAINT, Scrawl_OnPaint);
  625.     HANDLE_MSG(hwnd, WM_INITMENUPOPUP, Scrawl_OnInitMenuPopup);
  626.     HANDLE_MSG(hwnd, WM_KEYDOWN, Scrawl_OnKeyDown);
  627.     /*
  628.      *  Reacquire the mouse and keyboard when we are the active window.
  629.      *  Unacquire them when we stop being the active window.
  630.      */
  631.     case WM_ACTIVATE:
  632.         g_fActive = wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE;
  633.         Scrawl_SyncAcquire(hwnd);
  634.         break;
  635.     /*
  636.      *  Unacquire the devices if a menu appears, so that the user can
  637.      *  interact with the menu in the normal manner.
  638.      *
  639.      *  From Windows' point of view, we are still the active window
  640.      *  when a menu appears, but we want to act like the menu deactivated
  641.      *  us.
  642.      */
  643.     case WM_ENTERMENULOOP:
  644.     case WM_ENTERSIZEMOVE:
  645.         g_fActive = FALSE;
  646.         Scrawl_SyncAcquire(hwnd);
  647.         break;
  648.     /*
  649.      *  Reacquire the devices when the menu goes away.
  650.      *
  651.      *  SUBTLETY 1:  Windows actually sends the WM_EXITMENULOOP message
  652.      *  before all the menu-related stuff is finished, so post ourselves
  653.      *  a private message to reacquire after the menu has been torn
  654.      *  down for real.
  655.      *
  656.      *  SUBTLETY 2:  Don't assume that just because the menu is going
  657.      *  away that you are still the active window.  You might not be.
  658.      *
  659.      *  SUBTLETY 3:  Don't assume that just because you're the active
  660.      *  window that you are restored and ready for action.  You might
  661.      *  just be a taskbar button.
  662.      */
  663.     case WM_EXITMENULOOP:
  664.     case WM_EXITSIZEMOVE:
  665.         g_fActive = GetActiveWindow() == hwnd && !IsIconic(hwnd);
  666.         PostMessage(hwnd, WM_SYNCACQUIRE, 0, 0L);
  667.         break;
  668.     case WM_SYNCACQUIRE:
  669.         Scrawl_SyncAcquire(hwnd);
  670.         break;
  671.     case WM_SYSCOMMAND:
  672.         LRESULT lRc;
  673.         switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  674.         case IDC_CLEAR:
  675.             Scrawl_OnClear(hwnd);
  676.             lRc = 0;
  677.             break;
  678.         case IDC_ABOUT:
  679.             MessageBox(hwnd, "Scrawl DirectInput Sample v1.0",
  680.                     c_szAppName, MB_OK);
  681.             lRc = 0;
  682.             break;
  683.         /*
  684.          *  Eat the screen-saver notification.
  685.          */
  686.         case SC_SCREENSAVE:
  687.             lRc = 0;
  688.             break;
  689.         case IDC_SENSITIVITY_LOW:
  690.         case IDC_SENSITIVITY_NORMAL:
  691.         case IDC_SENSITIVITY_HIGH:
  692.             g_iSensitivity = (signed short)GET_WM_COMMAND_ID(wParam, lParam)
  693.                                 - IDC_SENSITIVITY_NORMAL;
  694.             lRc = 0;
  695.             break;
  696.         default:
  697.             lRc = DefWindowProc(hwnd, msg, wParam, lParam);
  698.             break;
  699.         }
  700.         /*
  701.          * The WM_SYSCOMMAND might've been a WM_CLOSE, in which case
  702.          * our window no longer exists.  So be careful.
  703.          */
  704.         if (IsWindow(hwnd)) {
  705.             Scrawl_SyncAcquire(hwnd);
  706.         }
  707.         return lRc;
  708.     case WM_DESTROY:
  709.         PostQuitMessage(0);
  710.         break;
  711.     }
  712.     return DefWindowProc(hwnd, msg, wParam, lParam);
  713. }
  714. /****************************************************************************
  715.  *
  716.  *      AppInit
  717.  *
  718.  *      Set up everything the application needs to get started.
  719.  *
  720.  ****************************************************************************/
  721. HWND AppInit(HINSTANCE hinst, int nCmdShow)
  722. {
  723.     /* Save instance handle for people who care */
  724.     g_hinst = hinst;
  725.     /*
  726.      *  Get our crosshairs cursor and extract the the width and
  727.      *  hotspot location so we can draw it manually.
  728.      */
  729.     g_hcurCross = LoadCursor(NULL, IDC_CROSS);
  730.     ICONINFO ii;
  731.     GetIconInfo(g_hcurCross, &ii);
  732.     BITMAP bm;
  733.     GetObject(ii.hbmMask, sizeof(BITMAP), &bm);
  734.     if (ii.hbmMask)  DeleteObject(ii.hbmMask);
  735.     if (ii.hbmColor) DeleteObject(ii.hbmColor);
  736.     g_dxCrossHot = ii.xHotspot;
  737.     g_dyCrossHot = ii.yHotspot;
  738.     g_cxCross = bm.bmWidth;
  739.     g_cyCross = bm.bmHeight;
  740.     /*
  741.      *  Create our scrawl bitmap and set it up.
  742.      */
  743.     HDC hdc = GetDC(0);
  744.     g_hdc = CreateCompatibleDC(hdc);
  745.     ReleaseDC(0, hdc);
  746.     if (!g_hdc) return NULL;
  747.     g_hbm = CreateBitmap(DINPUT_CXBITMAP, DINPUT_CYBITMAP, 1, 1, 0);
  748.     if (!g_hbm) return NULL;
  749.     g_hbmDeselect = (HBITMAP) SelectObject(g_hdc, g_hbm);
  750.     Scrawl_OnClear(0);
  751.     /*
  752.      *  Set up the window class.
  753.      */
  754.     WNDCLASS wc;
  755.     wc.hCursor        = LoadCursor(0, IDC_ARROW);
  756.     wc.hIcon          = LoadIcon(hinst, MAKEINTRESOURCE(IDI_MAIN));
  757.     wc.lpszMenuName   = NULL;
  758.     wc.lpszClassName  = c_szAppName;
  759.     wc.hbrBackground  = 0;
  760.     wc.hInstance      = hinst;
  761.     wc.style          = 0;
  762.     wc.lpfnWndProc    = ScrawlWndProc;
  763.     wc.cbClsExtra     = 0;
  764.     wc.cbWndExtra     = 0;
  765.     if (!RegisterClass(&wc)) {
  766.         return NULL;
  767.     }
  768.     DWORD dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
  769.     DWORD dwExStyle = WS_EX_APPWINDOW;
  770.     RECT rc = { 0, 0, DINPUT_CXBITMAP, DINPUT_CYBITMAP };
  771.     AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);
  772.     HWND hwnd = CreateWindowEx(
  773.                     dwExStyle,          // ExStyle
  774.                     c_szAppName,        // Class name
  775.                     c_szAppName,        // Caption
  776.                     dwStyle,            // Style
  777.                     CW_USEDEFAULT, CW_USEDEFAULT,  // Position
  778.                     rc.right - rc.left, // cx
  779.                     rc.bottom - rc.top, // cy
  780.                     0,                  // Parent window (no parent)
  781.                     0,                  // use class menu
  782.                     g_hinst,            // handle to module instance
  783.                     0                   // no params to pass on
  784.                     );
  785.     if (!DIInit(hwnd)) {
  786.         DestroyWindow(hwnd);
  787.         return NULL;
  788.     }
  789.     ShowWindow(hwnd, nCmdShow);
  790.     return hwnd;
  791. }
  792. /****************************************************************************
  793.  *
  794.  *      WinMain
  795.  *
  796.  *      Application entry point.
  797.  *
  798.  *      The main message loop illustrates how a message-driven program
  799.  *      can use event notifications to be signalled when new data is
  800.  *      available from a device.
  801.  *
  802.  ****************************************************************************/
  803. int PASCAL
  804. WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
  805. {
  806.     MSG msg;
  807.     msg.wParam = 0;         /* In case something goes horribly wrong */
  808.     HWND hwnd = AppInit(hinst, nCmdShow);
  809.     if (hwnd) {
  810.         /*
  811.          *  Since we use notification handles, we need to use
  812.          *  MsgWaitForMultipleObjects to wait for the event or
  813.          *  a message, whichever comes first.
  814.          */
  815.         BOOL fDone = FALSE;
  816.         while (!fDone) {
  817.             DWORD dw = MsgWaitForMultipleObjects(1, &g_hevtMouse, 0, INFINITE,
  818.                                                  QS_ALLINPUT);
  819.             switch (dw) {
  820.             /* WAIT_OBJECT_0 + 0 means that g_hevtMouse was signalled */
  821.             case WAIT_OBJECT_0 + 0:
  822.                 Scrawl_OnMouseInput(hwnd);
  823.                 break;
  824.             /* WAIT_OBJECT_0 + 1 means that we have messages to process */
  825.             case WAIT_OBJECT_0 + 1:
  826.                 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  827.                     /* If it's a quit message, we're outta here */
  828.                     if (msg.message == WM_QUIT) {
  829.                         fDone = TRUE;
  830.                     } else {
  831.                         TranslateMessage(&msg);
  832.                         DispatchMessage(&msg);
  833.                     }
  834.                 }
  835.                 break;
  836.             }
  837.         }
  838.     }
  839.     DITerm();
  840.     if (g_hdc) {
  841.         if (g_hbmDeselect) {
  842.             SelectObject(g_hdc, g_hbmDeselect);
  843.         }
  844.         DeleteDC(g_hdc);
  845.     }
  846.     if (g_hbm) {
  847.         DeleteObject(g_hbm);
  848.     }
  849.   return msg.wParam;
  850. }