home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / directx / dxf / samples / multimedia / directinput / keyboard / keyboard.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  23.2 KB  |  620 lines

  1. //-----------------------------------------------------------------------------
  2. // File: keyboard.cpp
  3. //
  4. // Desc: The Keyboard sample show how to use a DirectInput keyboard device 
  5. //       and the differences between cooperative levels and data styles. 
  6. //
  7. // Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <tchar.h>
  11. #include <windows.h>
  12. #include <basetsd.h>
  13. #include <dinput.h>
  14. #include "resource.h"
  15.  
  16.  
  17. //-----------------------------------------------------------------------------
  18. // Function-prototypes
  19. //-----------------------------------------------------------------------------
  20. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  21. HRESULT OnInitDialog( HWND hDlg );
  22. VOID    UpdateUI( HWND hDlg );
  23. HRESULT OnCreateDevice( HWND hDlg );
  24. HRESULT ReadImmediateData( HWND hDlg );
  25. HRESULT ReadBufferedData( HWND hDlg );
  26. VOID    FreeDirectInput();
  27.  
  28.  
  29.  
  30.  
  31. //-----------------------------------------------------------------------------
  32. // Defines, constants, and global variables
  33. //-----------------------------------------------------------------------------
  34. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  35. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  36.  
  37. #define SAMPLE_BUFFER_SIZE 8  // arbitrary number of buffer elements
  38.  
  39. LPDIRECTINPUT8       g_pDI       = NULL;         
  40. LPDIRECTINPUTDEVICE8 g_pKeyboard = NULL;     
  41.  
  42.  
  43.  
  44.  
  45. //-----------------------------------------------------------------------------
  46. // Name: WinMain()
  47. // Desc: Entry point for the application.  Since we use a simple dialog for 
  48. //       user interaction we don't need to pump messages.
  49. //-----------------------------------------------------------------------------
  50. int WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int )
  51. {
  52.     // Display the main dialog box.
  53.     DialogBox( hInst, MAKEINTRESOURCE(IDD_KEYBOARD), NULL, MainDlgProc );
  54.     
  55.     return TRUE;
  56. }
  57.  
  58.  
  59.  
  60.  
  61.  
  62. //-----------------------------------------------------------------------------
  63. // Name: MainDlgProc()
  64. // Desc: Handles dialog messages
  65. //-----------------------------------------------------------------------------
  66. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  67. {
  68.     switch( msg ) 
  69.     {
  70.         case WM_INITDIALOG:
  71.             OnInitDialog( hDlg );
  72.             break;
  73.         
  74.         case WM_COMMAND:
  75.             switch( LOWORD(wParam) )
  76.             {
  77.                 case IDCANCEL:
  78.                     EndDialog( hDlg, 0 ); 
  79.                     break;
  80.  
  81.                 case IDC_EXCLUSIVE:
  82.                 case IDC_NONEXCLUSIVE:
  83.                 case IDC_FOREGROUND:
  84.                 case IDC_BACKGROUND:
  85.                 case IDC_IMMEDIATE:
  86.                 case IDC_BUFFERED:
  87.                 case IDC_WINDOWSKEY:
  88.                     UpdateUI( hDlg );
  89.                     break;
  90.  
  91.                 case IDC_CREATEDEVICE:
  92.                     if( NULL == g_pKeyboard )
  93.                     {
  94.                         if( FAILED( OnCreateDevice( hDlg ) ) )
  95.                         {
  96.                             MessageBox( hDlg, _T("CreateDevice() failed. ")
  97.                                               _T("The sample will now exit."), 
  98.                                               _T("Keyboard"), MB_ICONERROR | MB_OK );
  99.                             FreeDirectInput();
  100.                         }
  101.                     }
  102.                     else
  103.                     {
  104.                         FreeDirectInput();
  105.                     }
  106.  
  107.                     UpdateUI( hDlg );
  108.                     break;
  109.  
  110.                 default:
  111.                     return FALSE; // Message not handled 
  112.             }       
  113.             break;
  114.  
  115.         case WM_ACTIVATE:
  116.             if( WA_INACTIVE != wParam && g_pKeyboard )
  117.             {
  118.                 // Make sure the device is acquired, if we are gaining focus.
  119.                 g_pKeyboard->Acquire();
  120.             }
  121.             break;
  122.         
  123.         case WM_TIMER:
  124.             // Update the input device every timer message
  125.             {
  126.                 BOOL bImmediate = ( IsDlgButtonChecked( hDlg, IDC_IMMEDIATE  ) == BST_CHECKED );
  127.  
  128.                 if( bImmediate )
  129.                 {
  130.                     if( FAILED( ReadImmediateData( hDlg ) ) )
  131.                     {
  132.                         KillTimer( hDlg, 0 );    
  133.                         MessageBox( NULL, _T("Error reading input state. ")
  134.                                           _T("The sample will now exit."), 
  135.                                           _T("Keyboard"), MB_ICONERROR | MB_OK );
  136.                         EndDialog( hDlg, TRUE ); 
  137.                     }
  138.                 }
  139.                 else
  140.                 {
  141.                     if( FAILED( ReadBufferedData( hDlg ) ) )
  142.                     {
  143.                         KillTimer( hDlg, 0 );    
  144.                         MessageBox( NULL, _T("Error reading input state. ")
  145.                                           _T("The sample will now exit."), 
  146.                                           _T("Keyboard"), MB_ICONERROR | MB_OK );
  147.                         EndDialog( hDlg, TRUE ); 
  148.                     }
  149.                 }
  150.             }
  151.             break;
  152.         
  153.         case WM_DESTROY:
  154.             // Cleanup everything
  155.             KillTimer( hDlg, 0 );    
  156.             FreeDirectInput();    
  157.             break;
  158.  
  159.         default:
  160.             return FALSE; // Message not handled 
  161.     }
  162.  
  163.     return TRUE; // Message handled 
  164. }
  165.  
  166.  
  167.  
  168.  
  169. //-----------------------------------------------------------------------------
  170. // Name: OnInitDialog()
  171. // Desc: Initialize the DirectInput variables.
  172. //-----------------------------------------------------------------------------
  173. HRESULT OnInitDialog( HWND hDlg )
  174. {
  175.     // Load the icon
  176.     HICON hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE( IDI_MAIN ) );
  177.  
  178.     // Set the icon for this dialog.
  179.     PostMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  180.     PostMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  181.  
  182.     // Check the 'exclusive', 'foreground', and 'immediate' buttons by default. 
  183.     CheckRadioButton( hDlg, IDC_EXCLUSIVE,  IDC_NONEXCLUSIVE, IDC_EXCLUSIVE );
  184.     CheckRadioButton( hDlg, IDC_FOREGROUND, IDC_BACKGROUND,   IDC_FOREGROUND );
  185.     CheckRadioButton( hDlg, IDC_IMMEDIATE,  IDC_BUFFERED,     IDC_IMMEDIATE );
  186.  
  187.     UpdateUI( hDlg );
  188.  
  189.     return S_OK;
  190. }
  191.  
  192.  
  193.  
  194.  
  195. //-----------------------------------------------------------------------------
  196. // Name: UpdateUI()
  197. // Desc: Enables/disables the UI, and sets the dialog behavior text based on the UI
  198. //-----------------------------------------------------------------------------
  199. VOID UpdateUI( HWND hDlg )
  200. {
  201.     TCHAR   strExcepted[2048];
  202.     BOOL    bExclusive;
  203.     BOOL    bForeground;
  204.     BOOL    bImmediate;
  205.     BOOL    bDisableWindowsKey;
  206.  
  207.     // Detrimine where the buffer would like to be allocated 
  208.     bExclusive         = ( IsDlgButtonChecked( hDlg, IDC_EXCLUSIVE  ) == BST_CHECKED );
  209.     bForeground        = ( IsDlgButtonChecked( hDlg, IDC_FOREGROUND ) == BST_CHECKED );
  210.     bImmediate         = ( IsDlgButtonChecked( hDlg, IDC_IMMEDIATE  ) == BST_CHECKED );
  211.     bDisableWindowsKey = ( IsDlgButtonChecked( hDlg, IDC_WINDOWSKEY ) == BST_CHECKED );
  212.  
  213.     if( g_pKeyboard )
  214.     {
  215.         SetDlgItemText( hDlg, IDC_CREATEDEVICE, TEXT("Release Device") );
  216.         SetDlgItemText( hDlg, IDC_DATA, TEXT("") );
  217.  
  218.         EnableWindow( GetDlgItem( hDlg, IDC_EXCLUSIVE    ), FALSE );
  219.         EnableWindow( GetDlgItem( hDlg, IDC_NONEXCLUSIVE ), FALSE );
  220.         EnableWindow( GetDlgItem( hDlg, IDC_FOREGROUND   ), FALSE );
  221.         EnableWindow( GetDlgItem( hDlg, IDC_BACKGROUND   ), FALSE );
  222.         EnableWindow( GetDlgItem( hDlg, IDC_IMMEDIATE    ), FALSE );
  223.         EnableWindow( GetDlgItem( hDlg, IDC_BUFFERED     ), FALSE );
  224.         EnableWindow( GetDlgItem( hDlg, IDC_WINDOWSKEY   ), FALSE );
  225.     }
  226.     else
  227.     {
  228.         SetDlgItemText( hDlg, IDC_CREATEDEVICE, TEXT("&Create Device") );
  229.         SetDlgItemText( hDlg, IDC_DATA, 
  230.                         TEXT("Device not created. Choose settings and click 'Create Device' then type to see results") );   
  231.  
  232.         EnableWindow( GetDlgItem( hDlg, IDC_EXCLUSIVE    ), TRUE );
  233.         EnableWindow( GetDlgItem( hDlg, IDC_NONEXCLUSIVE ), TRUE );
  234.         EnableWindow( GetDlgItem( hDlg, IDC_FOREGROUND   ), TRUE );
  235.         EnableWindow( GetDlgItem( hDlg, IDC_BACKGROUND   ), TRUE );
  236.         EnableWindow( GetDlgItem( hDlg, IDC_IMMEDIATE    ), TRUE );
  237.         EnableWindow( GetDlgItem( hDlg, IDC_BUFFERED     ), TRUE );
  238.  
  239.         if( !bExclusive && bForeground )
  240.             EnableWindow( GetDlgItem( hDlg, IDC_WINDOWSKEY ), TRUE );
  241.         else
  242.             EnableWindow( GetDlgItem( hDlg, IDC_WINDOWSKEY ), FALSE );
  243.     }
  244.  
  245.     // Figure what the user should expect based on the dialog choice
  246.     if( !bForeground && bExclusive )
  247.     {
  248.         strcpy( strExcepted, "For security reasons, background exclusive "
  249.                              "keyboard access is not allowed.\n\n" );
  250.     }
  251.     else
  252.     {
  253.         if( bForeground )
  254.         {
  255.             strcpy( strExcepted, "Foreground cooperative level means that the "
  256.                                  "application has access to data only when in the "
  257.                                  "foreground or, in other words, has the input focus. "
  258.                                  "If the application moves to the background, "
  259.                                  "the device is automatically unacquired, or made "
  260.                                  "unavailable.\n\n" );
  261.         }
  262.         else
  263.         {
  264.             strcpy( strExcepted, "Background cooperative level really means "
  265.                                  "foreground and background. A device with a "
  266.                                  "background cooperative level can be acquired "
  267.                                  "and used by an application at any time.\n\n" );
  268.         }
  269.  
  270.         if( bExclusive )
  271.         {
  272.             strcat( strExcepted, "Exclusive mode prevents other applications from "
  273.                                  "also acquiring the device exclusively. The fact "
  274.                                  "that your application is using a device at the "
  275.                                  "exclusive level does not mean that other "
  276.                                  "applications cannot get data from the device. "
  277.                                  "When an application has exclusive access to the "
  278.                                  "keyboard, DirectInput suppresses all keyboard "
  279.                                  "messages including the Windows key except "
  280.                                  "CTRL+ALT+DEL and, on Windows 95 and Windows 98, "
  281.                                  "ALT+TAB.\n\n" );
  282.         }
  283.         else
  284.         {
  285.             strcat( strExcepted, "Nonexclusive mode means that other applications "
  286.                                  "can acquire device in exclusive or nonexclusive mode. " );
  287.  
  288.             if( bDisableWindowsKey )
  289.             {
  290.                 strcat( strExcepted, "The Windows key will also be disabled so that "
  291.                                      "users cannot inadvertently break out of the "
  292.                                      "application. " );
  293.             }
  294.  
  295.             strcat( strExcepted, "\n\n" );
  296.         }
  297.  
  298.         if( bImmediate )
  299.         {
  300.             strcat( strExcepted, "Immediate data is a snapshot of the current "
  301.                                  "state of a device. It provides no data about "
  302.                                  "what has happened with the device since the "
  303.                                  "last call, apart from implicit information that "
  304.                                  "you can derive by comparing the current state with "
  305.                                  "the last one. Events in between calls are lost.\n\n" );
  306.         }
  307.         else
  308.         {
  309.             strcat( strExcepted, "Buffered data is a record of events that are stored "
  310.                                  "until an application retrieves them. With buffered "
  311.                                  "data, events are stored until you are ready to deal "
  312.                                  "with them. If the buffer overflows, new data is lost.\n\n" );                             
  313.         }
  314.  
  315.         strcat( strExcepted, "The sample will read the keyboard 12 times a second. "
  316.                              "Typically an application would poll the keyboard "
  317.                              "much faster than this, but this slow rate is simply "
  318.                              "for the purposes of demonstration." );
  319.     }
  320.  
  321.     // Tell the user what to expect
  322.     SetDlgItemText( hDlg, IDC_BEHAVIOR, strExcepted );
  323. }
  324.  
  325.  
  326.  
  327.  
  328. //-----------------------------------------------------------------------------
  329. // Name: OnCreateDevice()
  330. // Desc: Setups a the keyboard device using the flags from the dialog.
  331. //-----------------------------------------------------------------------------
  332. HRESULT OnCreateDevice( HWND hDlg )
  333. {
  334.     HRESULT hr;
  335.     BOOL    bExclusive;
  336.     BOOL    bForeground;
  337.     BOOL    bImmediate;
  338.     BOOL    bDisableWindowsKey;
  339.     DWORD   dwCoopFlags;
  340. #ifdef _WIN64
  341.     HINSTANCE hInst = (HINSTANCE) GetWindowLongPtr( hDlg, GWLP_HINSTANCE );
  342. #else
  343.     HINSTANCE hInst = (HINSTANCE) GetWindowLong( hDlg, GWL_HINSTANCE );
  344. #endif
  345.  
  346.     // Cleanup any previous call first
  347.     KillTimer( hDlg, 0 );    
  348.     FreeDirectInput();
  349.  
  350.     // Detrimine where the buffer would like to be allocated 
  351.     bExclusive         = ( IsDlgButtonChecked( hDlg, IDC_EXCLUSIVE  ) == BST_CHECKED );
  352.     bForeground        = ( IsDlgButtonChecked( hDlg, IDC_FOREGROUND ) == BST_CHECKED );
  353.     bImmediate         = ( IsDlgButtonChecked( hDlg, IDC_IMMEDIATE  ) == BST_CHECKED );
  354.     bDisableWindowsKey = ( IsDlgButtonChecked( hDlg, IDC_WINDOWSKEY ) == BST_CHECKED );
  355.  
  356.     if( bExclusive )
  357.         dwCoopFlags = DISCL_EXCLUSIVE;
  358.     else
  359.         dwCoopFlags = DISCL_NONEXCLUSIVE;
  360.  
  361.     if( bForeground )
  362.         dwCoopFlags |= DISCL_FOREGROUND;
  363.     else
  364.         dwCoopFlags |= DISCL_BACKGROUND;
  365.  
  366.     // Disabling the windows key is only allowed only if we are in foreground nonexclusive
  367.     if( bDisableWindowsKey && !bExclusive && bForeground )
  368.         dwCoopFlags |= DISCL_NOWINKEY;
  369.  
  370.     // Create a DInput object
  371.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  372.                                          IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) )
  373.         return hr;
  374.     
  375.     // Obtain an interface to the system keyboard device.
  376.     if( FAILED( hr = g_pDI->CreateDevice( GUID_SysKeyboard, &g_pKeyboard, NULL ) ) )
  377.         return hr;
  378.     
  379.     // Set the data format to "keyboard format" - a predefined data format 
  380.     //
  381.     // A data format specifies which controls on a device we
  382.     // are interested in, and how they should be reported.
  383.     //
  384.     // This tells DirectInput that we will be passing an array
  385.     // of 256 bytes to IDirectInputDevice::GetDeviceState.
  386.     if( FAILED( hr = g_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
  387.         return hr;
  388.     
  389.     // Set the cooperativity level to let DirectInput know how
  390.     // this device should interact with the system and with other
  391.     // DirectInput applications.
  392.     hr = g_pKeyboard->SetCooperativeLevel( hDlg, dwCoopFlags );
  393.     if( hr == DIERR_UNSUPPORTED && !bForeground && bExclusive )
  394.     {
  395.         FreeDirectInput();
  396.         MessageBox( hDlg, _T("SetCooperativeLevel() returned DIERR_UNSUPPORTED.\n")
  397.                           _T("For security reasons, background exclusive keyboard\n")
  398.                           _T("access is not allowed."), _T("Keyboard"), MB_OK );
  399.         return S_OK;
  400.     }
  401.  
  402.     if( FAILED(hr) )
  403.         return hr;
  404.  
  405.     if( !bImmediate )
  406.     {
  407.         // IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
  408.         //
  409.         // DirectInput uses unbuffered I/O (buffer size = 0) by default.
  410.         // If you want to read buffered data, you need to set a nonzero
  411.         // buffer size.
  412.         //
  413.         // Set the buffer size to DINPUT_BUFFERSIZE (defined above) elements.
  414.         //
  415.         // The buffer size is a DWORD property associated with the device.
  416.         DIPROPDWORD dipdw;
  417.  
  418.         dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  419.         dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  420.         dipdw.diph.dwObj        = 0;
  421.         dipdw.diph.dwHow        = DIPH_DEVICE;
  422.         dipdw.dwData            = SAMPLE_BUFFER_SIZE; // Arbitary buffer size
  423.  
  424.         if( FAILED( hr = g_pKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ) ) )
  425.             return hr;
  426.     }
  427.  
  428.     // Acquire the newly created device
  429.     g_pKeyboard->Acquire();
  430.  
  431.     // Set a timer to go off 12 times a second, to read input
  432.     // Note: Typically an application would poll the keyboard
  433.     //       much faster than this, but this slow rate is simply 
  434.     //       for the purposes of demonstration
  435.     SetTimer( hDlg, 0, 1000 / 12, NULL );
  436.  
  437.     return S_OK;
  438. }
  439.  
  440.  
  441.  
  442.  
  443. //-----------------------------------------------------------------------------
  444. // Name: ReadImmediateData()
  445. // Desc: Read the input device's state when in immediate mode and display it.
  446. //-----------------------------------------------------------------------------
  447. HRESULT ReadImmediateData( HWND hDlg )
  448. {
  449.     HRESULT hr;
  450.     TCHAR   strNewText[256*5 + 1] = TEXT("");
  451.     TCHAR   strElement[10];    
  452.     BYTE    diks[256];   // DirectInput keyboard state buffer 
  453.     int     i;
  454.  
  455.     if( NULL == g_pKeyboard ) 
  456.         return S_OK;
  457.     
  458.     // Get the input's device state, and put the state in dims
  459.     ZeroMemory( &diks, sizeof(diks) );
  460.     hr = g_pKeyboard->GetDeviceState( sizeof(diks), &diks );
  461.     if( FAILED(hr) ) 
  462.     {
  463.         // DirectInput may be telling us that the input stream has been
  464.         // interrupted.  We aren't tracking any state between polls, so
  465.         // we don't have any special reset that needs to be done.
  466.         // We just re-acquire and try again.
  467.         
  468.         // If input is lost then acquire and keep trying 
  469.         hr = g_pKeyboard->Acquire();
  470.         while( hr == DIERR_INPUTLOST ) 
  471.             hr = g_pKeyboard->Acquire();
  472.  
  473.         // Update the dialog text 
  474.         if( hr == DIERR_OTHERAPPHASPRIO || hr == DIERR_NOTACQUIRED ) 
  475.             SetDlgItemText( hDlg, IDC_DATA, "Unacquired" );
  476.  
  477.         // hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
  478.         // may occur when the app is minimized or in the process of 
  479.         // switching, so just try again later 
  480.         return S_OK; 
  481.     }
  482.     
  483.     // Make a string of the index values of the keys that are down
  484.     for( i = 0; i < 256; i++ ) 
  485.     {
  486.         if( diks[i] & 0x80 ) 
  487.         {
  488.             wsprintf( strElement, "0x%02x ", i );
  489.             strcat( strNewText, strElement );
  490.         }
  491.     }
  492.  
  493.     // Get the old text in the text box
  494.     TCHAR strOldText[128];
  495.     GetDlgItemText( hDlg, IDC_DATA, strOldText, 127 );
  496.     
  497.     // If nothing changed then don't repaint - avoid flicker
  498.     if( 0 != lstrcmp( strOldText, strNewText ) ) 
  499.         SetDlgItemText( hDlg, IDC_DATA, strNewText );
  500.     
  501.     return S_OK;
  502. }
  503.  
  504.  
  505.  
  506.  
  507. //-----------------------------------------------------------------------------
  508. // Name: ReadBufferedData()
  509. // Desc: Read the input device's state when in buffered mode and display it.
  510. //-----------------------------------------------------------------------------
  511. HRESULT ReadBufferedData( HWND hDlg )
  512. {
  513.     TCHAR              strNewText[256*5 + 1] = TEXT("");
  514.     TCHAR              strLetter[10];    
  515.     DIDEVICEOBJECTDATA didod[ SAMPLE_BUFFER_SIZE ];  // Receives buffered data 
  516.     DWORD              dwElements;
  517.     DWORD              i;
  518.     HRESULT            hr;
  519.  
  520.     if( NULL == g_pKeyboard ) 
  521.         return S_OK;
  522.     
  523.     dwElements = SAMPLE_BUFFER_SIZE;
  524.     hr = g_pKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  525.                                      didod, &dwElements, 0 );
  526.     if( hr != DI_OK ) 
  527.     {
  528.         // We got an error or we got DI_BUFFEROVERFLOW.
  529.         //
  530.         // Either way, it means that continuous contact with the
  531.         // device has been lost, either due to an external
  532.         // interruption, or because the buffer overflowed
  533.         // and some events were lost.
  534.         //
  535.         // Consequently, if a button was pressed at the time
  536.         // the buffer overflowed or the connection was broken,
  537.         // the corresponding "up" message might have been lost.
  538.         //
  539.         // But since our simple sample doesn't actually have
  540.         // any state associated with button up or down events,
  541.         // there is no state to reset.  (In a real game, ignoring
  542.         // the buffer overflow would result in the game thinking
  543.         // a key was held down when in fact it isn't; it's just
  544.         // that the "up" event got lost because the buffer
  545.         // overflowed.)
  546.         //
  547.         // If we want to be cleverer, we could do a
  548.         // GetDeviceState() and compare the current state
  549.         // against the state we think the device is in,
  550.         // and process all the states that are currently
  551.         // different from our private state.
  552.         hr = g_pKeyboard->Acquire();
  553.         while( hr == DIERR_INPUTLOST ) 
  554.             hr = g_pKeyboard->Acquire();
  555.  
  556.         // Update the dialog text 
  557.         if( hr == DIERR_OTHERAPPHASPRIO || 
  558.             hr == DIERR_NOTACQUIRED ) 
  559.             SetDlgItemText( hDlg, IDC_DATA, "Unacquired" );
  560.  
  561.         // hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
  562.         // may occur when the app is minimized or in the process of 
  563.         // switching, so just try again later 
  564.         return S_OK; 
  565.     }
  566.  
  567.     if( FAILED(hr) )  
  568.         return hr;
  569.  
  570.     // Study each of the buffer elements and process them.
  571.     //
  572.     // Since we really don't do anything, our "processing"
  573.     // consists merely of squirting the name into our
  574.     // local buffer.
  575.     for( i = 0; i < dwElements; i++ ) 
  576.     {
  577.         // this will display then scan code of the key
  578.         // plus a 'D' - meaning the key was pressed 
  579.         //   or a 'U' - meaning the key was released
  580.         wsprintf( strLetter, "0x%02x%s ", didod[ i ].dwOfs,
  581.                                          (didod[ i ].dwData & 0x80) ? "D" : "U");
  582.         strcat( strNewText, strLetter );
  583.     }
  584.  
  585.     // Get the old text in the text box
  586.     TCHAR strOldText[128];
  587.     GetDlgItemText( hDlg, IDC_DATA, strOldText, 127 );
  588.  
  589.     // If nothing changed then don't repaint - avoid flicker
  590.     if( 0 != lstrcmp( strOldText, strNewText ) ) 
  591.         SetDlgItemText( hDlg, IDC_DATA, strNewText );    
  592.  
  593.     return S_OK;
  594. }
  595.  
  596.  
  597.  
  598.  
  599. //-----------------------------------------------------------------------------
  600. // Name: FreeDirectInput()
  601. // Desc: Initialize the DirectInput variables.
  602. //-----------------------------------------------------------------------------
  603. VOID FreeDirectInput()
  604. {
  605.     // Unacquire the device one last time just in case 
  606.     // the app tried to exit while the device is still acquired.
  607.     if( g_pKeyboard ) 
  608.         g_pKeyboard->Unacquire();
  609.     
  610.     // Release any DirectInput objects.
  611.     SAFE_RELEASE( g_pKeyboard );
  612.     SAFE_RELEASE( g_pDI );
  613. }
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620.