//----------------------------------------------------------------------------- // File: Joystick.cpp // // Desc: Demonstrates an application which receives immediate // joystick data in exclusive mode via a dialog timer. // // Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #define STRICT #include #include #include #include "resource.h" //----------------------------------------------------------------------------- // Function-prototypes //----------------------------------------------------------------------------- INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ); BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext ); BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext ); HRESULT InitDirectInput( HWND hDlg ); VOID FreeDirectInput(); HRESULT UpdateInputState( HWND hDlg ); //----------------------------------------------------------------------------- // Defines, constants, and global variables //----------------------------------------------------------------------------- #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } LPDIRECTINPUT8 g_pDI = NULL; LPDIRECTINPUTDEVICE8 g_pJoystick = NULL; //----------------------------------------------------------------------------- // Name: WinMain() // Desc: Entry point for the application. Since we use a simple dialog for // user interaction we don't need to pump messages. //----------------------------------------------------------------------------- int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int ) { // Display the main dialog box. DialogBox( hInst, MAKEINTRESOURCE(IDD_JOYST_IMM), NULL, MainDlgProc ); return TRUE; } //----------------------------------------------------------------------------- // Name: MainDialogProc // Desc: Handles dialog messages //----------------------------------------------------------------------------- INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_INITDIALOG: if( FAILED( InitDirectInput( hDlg ) ) ) { MessageBox( NULL, TEXT("Error Initializing DirectInput"), TEXT("DirectInput Sample"), MB_ICONERROR | MB_OK ); EndDialog( hDlg, 0 ); } // Set a timer to go off 30 times a second. At every timer message // the input device will be read SetTimer( hDlg, 0, 1000 / 30, NULL ); return TRUE; case WM_ACTIVATE: if( WA_INACTIVE != wParam && g_pJoystick ) { // Make sure the device is acquired, if we are gaining focus. g_pJoystick->Acquire(); } return TRUE; case WM_TIMER: // Update the input device every timer message if( FAILED( UpdateInputState( hDlg ) ) ) { KillTimer( hDlg, 0 ); MessageBox( NULL, TEXT("Error Reading Input State. ") \ TEXT("The sample will now exit."), TEXT("DirectInput Sample"), MB_ICONERROR | MB_OK ); EndDialog( hDlg, TRUE ); } return TRUE; case WM_COMMAND: switch( LOWORD(wParam) ) { case IDCANCEL: EndDialog( hDlg, 0 ); return TRUE; } case WM_DESTROY: // Cleanup everything KillTimer( hDlg, 0 ); FreeDirectInput(); return TRUE; } return FALSE; // Message not handled } //----------------------------------------------------------------------------- // Name: InitDirectInput() // Desc: Initialize the DirectInput variables. //----------------------------------------------------------------------------- HRESULT InitDirectInput( HWND hDlg ) { HRESULT hr; // Register with the DirectInput subsystem and get a pointer // to a IDirectInput interface we can use. // Create a DInput object if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) ) return hr; // Look for a simple joystick we can use for this sample program. if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY ) ) ) return hr; // Make sure we got a joystick if( NULL == g_pJoystick ) { MessageBox( NULL, TEXT("Joystick not found. The sample will now exit."), TEXT("DirectInput Sample"), MB_ICONERROR | MB_OK ); EndDialog( hDlg, 0 ); return S_OK; } // Set the data format to "simple joystick" - a predefined data format // // A data format specifies which controls on a device we are interested in, // and how they should be reported. This tells DInput that we will be // passing a DIJOYSTATE2 structure to IDirectInputDevice::GetDeviceState(). if( FAILED( hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick2 ) ) ) return hr; // Set the cooperative level to let DInput know how this device should // interact with the system and with other DInput applications. if( FAILED( hr = g_pJoystick->SetCooperativeLevel( hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND ) ) ) return hr; // Enumerate the joystick objects. The callback function enabled user // interface elements for objects that are found, and sets the min/max // values property for discovered axes. if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, (VOID*)hDlg, DIDFT_ALL ) ) ) return hr; return S_OK; } //----------------------------------------------------------------------------- // Name: EnumJoysticksCallback() // Desc: Called once for each enumerated joystick. If we find one, create a // device interface on it so we can play with it. //----------------------------------------------------------------------------- BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext ) { HRESULT hr; // Obtain an interface to the enumerated joystick. hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL ); // If it failed, then we can't use this joystick. (Maybe the user unplugged // it while we were in the middle of enumerating it.) if( FAILED(hr) ) return DIENUM_CONTINUE; // Stop enumeration. Note: we're just taking the first joystick we get. You // could store all the enumerated joysticks and let the user pick. return DIENUM_STOP; } //----------------------------------------------------------------------------- // Name: EnumObjectsCallback() // Desc: Callback function for enumerating objects (axes, buttons, POVs) on a // joystick. This function enables user interface elements for objects // that are found to exist, and scales axes min/max values. //----------------------------------------------------------------------------- BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext ) { HWND hDlg = (HWND)pContext; static int nSliderCount = 0; // Number of returned slider controls static int nPOVCount = 0; // Number of returned POV controls // For axes that are returned, set the DIPROP_RANGE property for the // enumerated axis in order to scale min/max values. if( pdidoi->dwType & DIDFT_AXIS ) { DIPROPRANGE diprg; diprg.diph.dwSize = sizeof(DIPROPRANGE); diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); diprg.diph.dwHow = DIPH_BYID; diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis diprg.lMin = -1000; diprg.lMax = +1000; // Set the range for the axis if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) return DIENUM_STOP; } // Set the UI to reflect what objects the joystick supports if (pdidoi->guidType == GUID_XAxis) { EnableWindow( GetDlgItem( hDlg, IDC_X_AXIS ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_X_AXIS_TEXT ), TRUE ); } if (pdidoi->guidType == GUID_YAxis) { EnableWindow( GetDlgItem( hDlg, IDC_Y_AXIS ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_Y_AXIS_TEXT ), TRUE ); } if (pdidoi->guidType == GUID_ZAxis) { EnableWindow( GetDlgItem( hDlg, IDC_Z_AXIS ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_Z_AXIS_TEXT ), TRUE ); } if (pdidoi->guidType == GUID_RxAxis) { EnableWindow( GetDlgItem( hDlg, IDC_X_ROT ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_X_ROT_TEXT ), TRUE ); } if (pdidoi->guidType == GUID_RyAxis) { EnableWindow( GetDlgItem( hDlg, IDC_Y_ROT ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_Y_ROT_TEXT ), TRUE ); } if (pdidoi->guidType == GUID_RzAxis) { EnableWindow( GetDlgItem( hDlg, IDC_Z_ROT ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_Z_ROT_TEXT ), TRUE ); } if (pdidoi->guidType == GUID_Slider) { switch( nSliderCount++ ) { case 0 : EnableWindow( GetDlgItem( hDlg, IDC_SLIDER0 ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_SLIDER0_TEXT ), TRUE ); break; case 1 : EnableWindow( GetDlgItem( hDlg, IDC_SLIDER1 ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_SLIDER1_TEXT ), TRUE ); break; } } if (pdidoi->guidType == GUID_POV) { switch( nPOVCount++ ) { case 0 : EnableWindow( GetDlgItem( hDlg, IDC_POV0 ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_POV0_TEXT ), TRUE ); break; case 1 : EnableWindow( GetDlgItem( hDlg, IDC_POV1 ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_POV1_TEXT ), TRUE ); break; case 2 : EnableWindow( GetDlgItem( hDlg, IDC_POV2 ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_POV2_TEXT ), TRUE ); case 3 : EnableWindow( GetDlgItem( hDlg, IDC_POV3 ), TRUE ); EnableWindow( GetDlgItem( hDlg, IDC_POV3_TEXT ), TRUE ); } } return DIENUM_CONTINUE; } //----------------------------------------------------------------------------- // Name: UpdateInputState() // Desc: Get the input device's state and display it. //----------------------------------------------------------------------------- HRESULT UpdateInputState( HWND hDlg ) { HRESULT hr; TCHAR strText[128]; // Device state text DIJOYSTATE2 js; // DInput joystick state TCHAR* str; if( NULL == g_pJoystick ) return S_OK; // Poll the device to read the current state hr = g_pJoystick->Poll(); if( FAILED(hr) ) { // DInput is telling us that the input stream has been // interrupted. We aren't tracking any state between polls, so // we don't have any special reset that needs to be done. We // just re-acquire and try again. hr = g_pJoystick->Acquire(); while( hr == DIERR_INPUTLOST ) hr = g_pJoystick->Acquire(); // hr may be DIERR_OTHERAPPHASPRIO or other errors. This // may occur when the app is minimized or in the process of // switching, so just try again later return S_OK; } // Get the input's device state if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js ) ) ) return hr; // The device should have been acquired during the Poll() // Display joystick state to dialog // Axes wsprintf( strText, TEXT("%ld"), js.lX ); SetWindowText( GetDlgItem( hDlg, IDC_X_AXIS ), strText ); wsprintf( strText, TEXT("%ld"), js.lY ); SetWindowText( GetDlgItem( hDlg, IDC_Y_AXIS ), strText ); wsprintf( strText, TEXT("%ld"), js.lZ ); SetWindowText( GetDlgItem( hDlg, IDC_Z_AXIS ), strText ); wsprintf( strText, TEXT("%ld"), js.lRx ); SetWindowText( GetDlgItem( hDlg, IDC_X_ROT ), strText ); wsprintf( strText, TEXT("%ld"), js.lRy ); SetWindowText( GetDlgItem( hDlg, IDC_Y_ROT ), strText ); wsprintf( strText, TEXT("%ld"), js.lRz ); SetWindowText( GetDlgItem( hDlg, IDC_Z_ROT ), strText ); // Slider controls wsprintf( strText, TEXT("%ld"), js.rglSlider[0] ); SetWindowText( GetDlgItem( hDlg, IDC_SLIDER0 ), strText ); wsprintf( strText, TEXT("%ld"), js.rglSlider[1] ); SetWindowText( GetDlgItem( hDlg, IDC_SLIDER1 ), strText ); // Points of view wsprintf( strText, TEXT("%ld"), js.rgdwPOV[0] ); SetWindowText( GetDlgItem( hDlg, IDC_POV0 ), strText ); wsprintf( strText, TEXT("%ld"), js.rgdwPOV[1] ); SetWindowText( GetDlgItem( hDlg, IDC_POV1 ), strText ); wsprintf( strText, TEXT("%ld"), js.rgdwPOV[2] ); SetWindowText( GetDlgItem( hDlg, IDC_POV2 ), strText ); wsprintf( strText, TEXT("%ld"), js.rgdwPOV[3] ); SetWindowText( GetDlgItem( hDlg, IDC_POV3 ), strText ); // Fill up text with which buttons are pressed str = strText; for( int i = 0; i < 128; i++ ) { if ( js.rgbButtons[i] & 0x80 ) str += wsprintf( str, TEXT("%02d "), i ); } *str = 0; // Terminate the string SetWindowText( GetDlgItem( hDlg, IDC_BUTTONS ), strText ); return S_OK; } //----------------------------------------------------------------------------- // Name: FreeDirectInput() // Desc: Initialize the DirectInput variables. //----------------------------------------------------------------------------- VOID FreeDirectInput() { // Unacquire the device one last time just in case // the app tried to exit while the device is still acquired. if( g_pJoystick ) g_pJoystick->Unacquire(); // Release any DirectInput objects. SAFE_RELEASE( g_pJoystick ); SAFE_RELEASE( g_pDI ); }