Browse Source

add rudimentary dinput support

cxgeorge 23 years ago
parent
commit
4f6954ae11

+ 13 - 12
panda/src/wdxdisplay8/Sources.pp

@@ -2,26 +2,27 @@
 
 #define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
                    dtoolutil:c dtoolbase:c dtool:m
-#define WIN_SYS_LIBS Imm32.lib
+#define WIN_SYS_LIBS Imm32.lib dinput8.lib
 #define USE_PACKAGES dx
 
 #begin lib_target
   #define TARGET wdxdisplay8
   #define LOCAL_LIBS dxgsg8
-    
-  #define COMBINED_SOURCES $[TARGET]_composite1.cxx 
-  
-  // need to install these due to external projects that link directly with libpandadx (bartop)    
+
+  #define COMBINED_SOURCES $[TARGET]_composite1.cxx
+
+  // need to install these due to external projects that link directly with libpandadx (bartop)
   #define INSTALL_HEADERS \
-    config_wdxdisplay8.h wdxGraphicsPipe8.h wdxGraphicsWindow8.h
-    
+    config_wdxdisplay8.h wdxGraphicsPipe8.h wdxGraphicsWindow8.h dxInput8.h
+
+
   #define INCLUDED_SOURCES \
-    config_wdxdisplay8.cxx wdxGraphicsPipe8.cxx 
-    
-  // note SOURCES shoult NOT include INCLUDED_SOURCES, that would cause a double build
+    config_wdxdisplay8.cxx wdxGraphicsPipe8.cxx dxInput8.cxx
+
+  // note SOURCES should NOT include INCLUDED_SOURCES, that would cause a double build
   // SOURCES should be headers and separately-built cxx files
   // build wdxGraphicsWindow.cxx separately since its big
-  
+
   #define SOURCES wdxGraphicsWindow8.cxx $[INSTALL_HEADERS]
-    
+
 #end lib_target

+ 2 - 0
panda/src/wdxdisplay8/config_wdxdisplay8.cxx

@@ -48,6 +48,8 @@ bool dx_pick_best_screenres = config_wdxdisplay.GetBool("pick-best-screenres", f
 // this config variable with an actual OS detection.
 bool ime_composition_w = config_wdxdisplay.GetBool("ime-composition-w", true);
 
+bool dx_use_joystick = config_wdxdisplay.GetBool("use-joystick", false);
+
 extern void AtExitFn(void);
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 1
panda/src/wdxdisplay8/config_wdxdisplay8.h

@@ -29,12 +29,13 @@ extern bool bResponsive_minimized_fullscreen_window;
 extern bool dx_force_16bpp_zbuffer;
 extern bool dx_preserve_fpu_state;
 extern bool dx_do_vidmemsize_check;
-extern bool dx_pick_best_screenres;
 extern int dx_preferred_deviceID;
+extern bool dx_pick_best_screenres;
 extern Filename get_icon_filename();
 extern Filename get_mono_cursor_filename();
 extern Filename get_color_cursor_filename();
 extern bool ime_composition_w;
+extern bool dx_use_joystick;
 
 extern EXPCL_PANDADX void init_libwdxdisplay8();
 

+ 276 - 0
panda/src/wdxdisplay8/dxInput8.cxx

@@ -0,0 +1,276 @@
+// Filename: dxInput8.cxx
+// Created by:  angelina jolie (07Oct99)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "config_wdxdisplay8.h"
+#include <dxInput8.h>
+
+#define AXIS_RESOLUTION 2000   // use this many levels of resolution by default (could be more if needed and device supported it)
+#define AXIS_RANGE_CENTERED    // if defined, axis range is centered on 0, instead of starting on 0
+
+BOOL CALLBACK EnumGameCtrlsCallback( const DIDEVICEINSTANCE* pdidInstance,
+                                     VOID* pContext ) {
+    DI_DeviceInfos *pDevInfos = (DI_DeviceInfos *)pContext;
+
+    (*pDevInfos).push_back(*pdidInstance);
+
+    if(wdxdisplay_cat.is_debug())
+        wdxdisplay_cat.debug() << "Found DevType 0x" << (void*)pdidInstance->dwDevType << ": " << pdidInstance->tszInstanceName << ": " << pdidInstance->tszProductName <<endl;
+
+    return DIENUM_CONTINUE;
+}
+
+extern BOOL CALLBACK EnumObjectsCallbackJoystick(const DIDEVICEOBJECTINSTANCE* pdidoi,VOID* pContext);
+
+DInput8Info::DInput8Info() {
+    _pDInput8 = NULL;
+    _hDInputDLL = NULL;
+    _JoystickPollTimer = NULL;
+}
+
+DInput8Info::~DInput8Info() {
+  for(UINT i=0;i<_DeviceList.size();i++) {
+      _DeviceList[i]->Unacquire();
+      SAFE_RELEASE(_DeviceList[i]);
+  }
+
+  // bugbug: need to handle this
+  // if(_JoystickPollTimer!=NULL)
+  //   KillTimer(...)
+
+  SAFE_RELEASE(_pDInput8);
+  if(_hDInputDLL) {
+      FreeLibrary(_hDInputDLL);
+      _hDInputDLL=NULL;
+  }
+}
+
+bool DInput8Info::InitDirectInput(void) {
+    HRESULT hr;
+
+    // assumes dx8 exists
+    // use dynamic load so non-dinput programs dont have to load dinput
+    #define DLLNAME "dinput8.dll"
+    #define DINPUTCREATE "DirectInput8Create"
+
+    HINSTANCE _hDInputDLL = LoadLibrary(DLLNAME);
+    if(_hDInputDLL == 0) {
+        wdxdisplay_cat.fatal() << "LoadLibrary(" << DLLNAME <<") failed!, error=" << GetLastError() << endl;
+        exit(1);
+    }
+
+    typedef HRESULT (WINAPI * LPDIRECTINPUT8CREATE)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter);
+    LPDIRECTINPUT8CREATE pDInputCreate8;
+
+    pDInputCreate8 = (LPDIRECTINPUT8CREATE) GetProcAddress(_hDInputDLL,DINPUTCREATE);
+    if(pDInputCreate8 == NULL) {
+        wdxdisplay_cat.fatal() << "GetProcAddr failed for " << DINPUTCREATE << endl;
+        exit(1);
+    }
+
+    // Register with the DirectInput subsystem and get a pointer
+    // to a IDirectInput interface we can use.
+    // Create a DInput object
+    if( FAILED( hr = (*pDInputCreate8)(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
+                                         IID_IDirectInput8, (VOID**)&_pDInput8, NULL ) ) ) {
+        wdxdisplay_cat.error() << DINPUTCREATE << "failed" << D3DERRORSTRING(hr);
+        return false;
+    }
+
+    // enum all the joysticks,etc  (but not keybd/mouse)
+    if( FAILED( hr = _pDInput8->EnumDevices(DI8DEVCLASS_GAMECTRL,
+                                         EnumGameCtrlsCallback,
+                                         (LPVOID)&_DevInfos, DIEDFL_ATTACHEDONLY ) ) ) {
+        wdxdisplay_cat.error() << "EnumDevices failed" << D3DERRORSTRING(hr);
+        return false;
+    }
+
+    return true;
+}
+
+bool DInput8Info::CreateJoystickOrPad(HWND hWnd) {
+    bool bFoundDev = false;
+    UINT devnum=0;
+    char *errstr=NULL;
+
+    // look through the list for the first joystick or gamepad
+    for(;devnum<_DevInfos.size();devnum++) {
+        DWORD devType = GET_DIDEVICE_TYPE(_DevInfos[devnum].dwDevType);
+        if((devType==DI8DEVTYPE_GAMEPAD) ||(devType==DI8DEVTYPE_JOYSTICK)) {
+          bFoundDev=true;
+          break;
+        }
+    }
+
+    if(!bFoundDev) {
+        wdxdisplay_cat.error() << "Cant find an attached Joystick or GamePad!\n";
+        return false;
+    }
+
+    LPDIRECTINPUTDEVICE8 pJoyDevice;
+
+    // Obtain an interface to the enumerated joystick.
+    HRESULT hr = _pDInput8->CreateDevice(_DevInfos[devnum].guidInstance, &pJoyDevice, NULL );
+    if(FAILED(hr)) {
+        errstr="CreateDevice";
+        goto handle_error;
+    }
+
+    assert(pJoyDevice!=NULL);
+    _DeviceList.push_back(pJoyDevice);
+
+    // 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().
+    hr = pJoyDevice->SetDataFormat(&c_dfDIJoystick2);
+    if(FAILED(hr)) {
+        errstr="SetDataFormat";
+        goto handle_error;
+    }
+
+    // must be called AFTER SetDataFormat to get all the proper flags
+    DX_DECLARE_CLEAN(DIDEVCAPS, DIDevCaps);
+    hr = pJoyDevice->GetCapabilities(&DIDevCaps);
+    assert(SUCCEEDED(hr));
+
+    _DevCaps.push_back(DIDevCaps);
+
+    if(wdxdisplay_cat.is_debug())
+        wdxdisplay_cat.debug() << "Joy/Pad has " << DIDevCaps.dwAxes << " Axes, " <<  DIDevCaps.dwButtons << " Buttons, " <<  DIDevCaps.dwPOVs << " POVs" << endl;
+
+    // Set the cooperative level to let DInput know how this device should
+    // interact with the system and with other DInput applications.
+    hr = pJoyDevice->SetCooperativeLevel( hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
+    if(FAILED(hr)) {
+        errstr="SetCooperativeLevel";
+        goto handle_error;
+    }
+
+    // set the min/max values property for discovered axes.
+    hr = pJoyDevice->EnumObjects(EnumObjectsCallbackJoystick, (LPVOID)pJoyDevice, DIDFT_AXIS);
+    if(FAILED(hr)) {
+        errstr="EnumObjects";
+        goto handle_error;
+    }
+
+    return true;
+
+  handle_error:
+    wdxdisplay_cat.error() << errstr << " failed for (" << _DevInfos[devnum].tszInstanceName << ":" << _DevInfos[devnum].tszProductName << ")" << D3DERRORSTRING(hr);
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+// 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 EnumObjectsCallbackJoystick( const DIDEVICEOBJECTINSTANCE* pdidoi,
+                                   VOID* pContext ) {
+
+    LPDIRECTINPUTDEVICE8 pJoyDevice = (LPDIRECTINPUTDEVICE8) pContext;
+    HRESULT hr;
+
+    // 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
+
+     #ifdef AXIS_RANGE_CENTERED
+        diprg.lMin              = -AXIS_RESOLUTION/2;
+        diprg.lMax              = +AXIS_RESOLUTION/2;
+     #else
+        diprg.lMin              = 0;
+        diprg.lMax              = +AXIS_RESOLUTION;
+     #endif
+
+        // Set the range for the axis
+        hr = pJoyDevice->SetProperty( DIPROP_RANGE, &diprg.diph);
+        if(FAILED(hr)) {
+          wdxdisplay_cat.error() << "SetProperty on axis failed" << D3DERRORSTRING(hr);
+          return DIENUM_STOP;
+        }
+    }
+
+    return DIENUM_CONTINUE;
+}
+
+bool DInput8Info::ReadJoystick(int devnum, DIJOYSTATE2 &js) {
+    LPDIRECTINPUTDEVICE8 pJoystick = _DeviceList[devnum];
+    assert(pJoystick!=NULL);
+    HRESULT hr;
+    char *errstr;
+
+    // Poll the device to read the current state
+
+    hr = 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.
+
+        if((hr==DIERR_NOTACQUIRED)||(hr == DIERR_INPUTLOST)) {
+            hr = pJoystick->Acquire();
+
+            if(FAILED(hr)) {
+                if(wdxdisplay_cat.is_spam())
+                   wdxdisplay_cat.spam() << "Acquire failed" << D3DERRORSTRING(hr);
+
+                // 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 false;
+            }
+
+            hr = pJoystick->Poll();
+            if(FAILED(hr)) {
+                // should never happen!
+                errstr = "Poll after successful Acquire failed";
+                goto handle_error;
+            }
+        } else {
+            errstr =  "Unknown Poll failure";
+            goto handle_error;
+        }
+    }
+
+    // should we make a vector of devstate dataformats to generalize this fn for all device types?
+
+    // Get the input's device state
+    hr = pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js);
+    if(FAILED(hr)) {
+        errstr =  "GetDeviceState failed";
+        goto handle_error;
+    }
+
+    return true;
+
+  handle_error:
+     wdxdisplay_cat.fatal() << errstr << D3DERRORSTRING(hr);
+     return false;
+}
+
+

+ 45 - 0
panda/src/wdxdisplay8/dxInput8.h

@@ -0,0 +1,45 @@
+// Filename: dxInput8.h
+// Created by:  blllyjo (07Oct99)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef DXINPUT8_H
+#define DXINPUT8_H
+
+#define DIRECTINPUT_VERSION 0x800
+#include <dinput.h>
+typedef vector<DIDEVICEINSTANCE> DI_DeviceInfos;
+typedef vector<DIDEVICEOBJECTINSTANCE> DI_DeviceObjInfos;
+
+class DInput8Info {
+public:
+ DInput8Info(void);
+ ~DInput8Info(void);
+ bool InitDirectInput(void);
+ bool CreateJoystickOrPad(HWND hWnd);
+ bool ReadJoystick(int devnum, DIJOYSTATE2 &js);
+
+ HINSTANCE _hDInputDLL;
+ UINT_PTR  _JoystickPollTimer;
+ LPDIRECTINPUT8 _pDInput8;
+ DI_DeviceInfos _DevInfos;
+ // arrays for all created devices.  Should probably put these together in a struct,
+ // along with the data fmt info
+ vector<LPDIRECTINPUTDEVICE8> _DeviceList;
+ vector<DIDEVCAPS> _DevCaps;
+};
+
+#endif

+ 1 - 1
panda/src/wdxdisplay8/wdxGraphicsPipe8.h

@@ -31,7 +31,7 @@
 // Defines
 ////////////////////////////////////////////////////////////////////
 
-extern char * ConvD3DErrorToString(const HRESULT &error);
+// extern char * ConvD3DErrorToString(const HRESULT &error);
 
 ////////////////////////////////////////////////////////////////////
 //       Class : wdxGraphicsPipe

+ 66 - 10
panda/src/wdxdisplay8/wdxGraphicsWindow8.cxx

@@ -46,6 +46,9 @@ TypeHandle wdxGraphicsWindow::_type_handle;
 #define WDX_WINDOWCLASSNAME_NOCURSOR WDX_WINDOWCLASSNAME "_NoCursor"
 #define DEFAULT_CURSOR IDC_ARROW
 
+// define this to enable debug testing of dinput joystick
+//#define DINPUT_DEBUG_POLL
+
 typedef map<HWND,wdxGraphicsWindow *> HWND_PANDAWIN_MAP;
 
 // CardIDVec is used in DX7 lowmem card-classification pass so DX8 can
@@ -67,7 +70,8 @@ wdxGraphicsWindow* global_wdxwinptr = NULL;  // need this for temporary windproc
 
 #define MAX_DISPLAYS 20
 
-#define PAUSED_TIMER_ID  7   // completely arbitrary choice
+#define PAUSED_TIMER_ID        7   // completely arbitrary choice
+#define JOYSTICK_POLL_TIMER_ID 8
 #define DX_IS_READY ((_dxgsg!=NULL)&&(_dxgsg->GetDXReady()))
 
 LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam,LPARAM lparam);
@@ -828,6 +832,25 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
                 // do we still need to do this since I return control to app periodically using timer msgs?
                 // does app need to know to avoid major computation?
             }
+
+         #ifdef DINPUT_DEBUG_POLL
+            // probably want to get rid of this in favor of event-based input
+            if(dx_use_joystick && (wparam==_pParentWindowGroup->_pDInputInfo->_JoystickPollTimer)) {
+                DIJOYSTATE2 js;
+                ZeroMemory(&js,sizeof(js));
+                if(_pParentWindowGroup->_pDInputInfo->ReadJoystick(0,js)) {
+                    // for now just print stuff out to make sure it works
+                    wdxdisplay_cat.debug() << "joyPos (X: " << js.lX << ",Y: " << js.lY << ",Z: " << js.lZ << ")\n";
+                    for(int i=0;i<128;i++) {
+                        if(js.rgbButtons[i]!=0)
+                            wdxdisplay_cat.debug() << "joyButton "<< i << " pressed\n";
+                    }
+                } else {
+                    wdxdisplay_cat.error() << "read of Joystick failed!\n";
+                    exit(1);
+                }
+            }
+          #endif
             return 0;
 
         case WM_CLOSE:
@@ -1032,6 +1055,9 @@ void wdxGraphicsWindow::deactivate_window(void) {
            wdxdisplay_cat.error() << "Error in SetTimer!\n";
        }
 //   }
+
+
+     // bugbug: need to handle dinput devices
 }
 
 // currently this should only be called from CheckCoopLvl to return from Alt-tab
@@ -2178,7 +2204,7 @@ bool wdxGraphicsWindow::search_for_device(LPDIRECT3D8 pD3D8,DXDeviceInfo *pDevIn
                 } Memlimres;
 
                 const Memlimres MemRes[] = {
-                                             {       0,  640, 480},                  
+                                             {       0,  640, 480},
                                              { 8000000,  800, 600},
                                              {16000000, 1024, 768},
                                              {32000000, 1280,1024},  // 32MB cards will choose this
@@ -2198,15 +2224,15 @@ bool wdxGraphicsWindow::search_for_device(LPDIRECT3D8 pD3D8,DXDeviceInfo *pDevIn
                                          &_dxgsg->scrn.SupportedScreenDepthsMask,
                                          &bCouldntFindValidZBuf,
                                          &pixFmt);
-    
-            
+
+
                         // note I'm not saving refresh rate, will just use adapter default at given res for now
-            
+
                         if(pixFmt==D3DFMT_UNKNOWN) {
                             wdxdisplay_cat.debug() << "skipping scrnres; "
                                 << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
                                 << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _dxgsg->scrn.CardIDNum << endl;
-                        } else 
+                        } else
                             break;
                     }
                 }
@@ -2218,10 +2244,10 @@ bool wdxGraphicsWindow::search_for_device(LPDIRECT3D8 pD3D8,DXDeviceInfo *pDevIn
                                          &_dxgsg->scrn.SupportedScreenDepthsMask,
                                          &bCouldntFindValidZBuf,
                                          &pixFmt);
-    
-    
+
+
                 // note I'm not saving refresh rate, will just use adapter default at given res for now
-    
+
                 if(pixFmt==D3DFMT_UNKNOWN) {
                     wdxdisplay_cat.fatal()
                         << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
@@ -2408,7 +2434,7 @@ CreateScreenBuffersAndDevice(DXScreenData &Display) {
         if(pPresParams->MultiSampleType != D3DMULTISAMPLE_NONE)
             assert(pPresParams->SwapEffect == D3DSWAPEFFECT_DISCARD);  // only valid effect for multisample
         #endif
-        
+
         ClearToBlack(Display.hWnd,_props);
 
         hr = pD3D8->CreateDevice(Display.CardIDNum, D3DDEVTYPE_HAL, _pParentWindowGroup->_hParentWindow,
@@ -3018,6 +3044,8 @@ void wdxGraphicsWindowGroup::initWindowGroup(void) {
     _hMouseCursor = NULL;
     _bLoadedCustomCursor = false;
 
+    _pDInputInfo = NULL;
+
     // can only get multimon HW acceleration in fullscrn on DX7
 
     UINT numMonitors = GetSystemMetrics(SM_CMONITORS);
@@ -3179,6 +3207,32 @@ void wdxGraphicsWindowGroup::initWindowGroup(void) {
     for(UINT i=0;i<num_windows;i++) {
         _windows[i]->_dxgsg->SetDXReady(true);
     }
+
+  #ifdef DINPUT_DEBUG_POLL
+    if(dx_use_joystick) {
+        _pDInputInfo = new DInput8Info;
+        assert(_pDInputInfo !=NULL);
+       if(!_pDInputInfo->InitDirectInput()) {
+           wdxdisplay_cat.error() << "InitDirectInput failed!\n";
+           exit(1);
+       }
+
+       if(!_pDInputInfo->CreateJoystickOrPad(_hParentWindow)) {  // associate w/parent window of group for now
+           wdxdisplay_cat.error() << "CreateJoystickOrPad failed!\n";
+           exit(1);
+       }
+
+        // for now, just set up a WM_TIMER to poll the joystick.
+        // could configure it to do event-based input, and that is default w/action mapping
+        // which would be better, less processor intensive
+
+        #define POLL_FREQUENCY_HZ  3
+        _pDInputInfo->_JoystickPollTimer = SetTimer(_hParentWindow, JOYSTICK_POLL_TIMER_ID, 1000/POLL_FREQUENCY_HZ, NULL);
+        if(_pDInputInfo->_JoystickPollTimer!=JOYSTICK_POLL_TIMER_ID) {
+           wdxdisplay_cat.error() << "Error in joystick SetTimer!\n";
+       }
+    }
+  #endif
 }
 
 wdxGraphicsWindowGroup::wdxGraphicsWindowGroup(GraphicsPipe *pipe,int num_windows,GraphicsWindow::Properties *WinPropArray) {
@@ -3212,6 +3266,8 @@ wdxGraphicsWindowGroup::~wdxGraphicsWindowGroup() {
     // this fn must be called before windows are actually closed
     _bClosingAllWindows= true;
 
+    SAFE_DELETE(_pDInputInfo);
+
     for(UINT i=0;i<_windows.size();i++) {
         _windows[i]->close_window();
     }

+ 1 - 0
panda/src/wdxdisplay8/wdxGraphicsWindow8.h

@@ -24,6 +24,7 @@
 #include <pandabase.h>
 #include <graphicsWindow.h>
 #include "dxGraphicsStateGuardian8.h"
+#include <dxInput8.h>
 
 ////////////////////////////////////////////////////////////////////
 // Defines

+ 1 - 0
panda/src/wdxdisplay8/wdxdisplay8_composite1.cxx

@@ -1,4 +1,5 @@
 
 #include "config_wdxdisplay8.cxx"
 #include "wdxGraphicsPipe8.cxx"
+#include "dxInput8.cxx"