diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e18689bd..382afcfcf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -423,6 +423,7 @@ FIND_PACKAGE(SDL) FIND_PACKAGE(Poppler-glib) FIND_PACKAGE(RSVG) FIND_PACKAGE(GtkGl) +FIND_PACKAGE(DirectInput) # Include macro utilities here INCLUDE(OsgMacroUtils) diff --git a/CMakeModules/FindDirectInput.cmake b/CMakeModules/FindDirectInput.cmake new file mode 100644 index 000000000..f00b871e8 --- /dev/null +++ b/CMakeModules/FindDirectInput.cmake @@ -0,0 +1,53 @@ +# Locate directinput +# This module defines +# DIRECTINPUT_LIBRARIES +# DIRECTINPUT_FOUND, if false, do not try to link to directinput +# DIRECTINPUT_INCLUDE_DIR, where to find the headers +# +# $DIRECTINPUT_DIR is an environment variable that would +# point to the this path in the plateform devkit (Samples\Multimedia\DirectShow) +# +# Created by Cedric Pinson. +# + +SET( DIRECTINPUT_FOUND FALSE ) + +IF( WIN32 ) + FIND_PATH( DIRECTINPUT_ROOT_DIR Include/D3D10.h + PATHS + $ENV{PATH} + $ENV{PROGRAMFILES} + ) + + FIND_PATH( DIRECTINPUT_INCLUDE_DIR dinput.h + PATHS + ${DIRECTINPUT_ROOT_DIR}/Include + ) + + FIND_LIBRARY( DIRECTINPUT_LIBRARY dinput7.lib dinput8.lib + PATHS + ${DIRECTINPUT_ROOT_DIR}/lib/x86 + ) + + FIND_LIBRARY( DIRECTINPUT_GUID_LIBRARY dxguid.lib + PATHS + ${DIRECTINPUT_ROOT_DIR}/lib/x86 + ) + + FIND_LIBRARY( DIRECTINPUT_ERR_LIBRARY dxerr.lib + PATHS + ${DIRECTINPUT_ROOT_DIR}/lib/x86 + ) + + SET( DIRECTINPUT_LIBRARIES + ${DIRECTINPUT_LIBRARY} + ${DIRECTINPUT_GUID_LIBRARY} + ${DIRECTINPUT_ERR_LIBRARY} + ) + + IF ( DIRECTINPUT_INCLUDE_DIR AND DIRECTINPUT_LIBRARIES ) + SET( DIRECTINPUT_FOUND TRUE ) + ENDIF ( DIRECTINPUT_INCLUDE_DIR AND DIRECTINPUT_LIBRARIES ) +ENDIF( WIN32 ) + +MARK_AS_ADVANCED( DIRECTINPUT_FOUND ) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4ed842c07..89e260fa8 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -225,7 +225,9 @@ IF(DYNAMIC_OPENSCENEGRAPH) ADD_SUBDIRECTORY(osgviewerCocoa) ENDIF(APPLE) - + IF(DIRECTINPUT_FOUND) + ADD_SUBDIRECTORY(osgdirectinput) + ENDIF(DIRECTINPUT_FOUND) IF (LIBVNCSERVER_FOUND) ADD_SUBDIRECTORY(osgvnc) diff --git a/examples/osgdirectinput/CMakeLists.txt b/examples/osgdirectinput/CMakeLists.txt new file mode 100644 index 000000000..945bfa70b --- /dev/null +++ b/examples/osgdirectinput/CMakeLists.txt @@ -0,0 +1,9 @@ +SET(TARGET_H DirectInputRegistry) +SET(TARGET_SRC osgdirectinput.cpp DirectInputRegistry.cpp) + +INCLUDE_DIRECTORIES( ${DIRECTINPUT_INCLUDE_DIR} ) +SET(TARGET_ADDED_LIBRARIES ${DIRECTINPUT_LIBRARIES}) + +#### end var setup ### +SETUP_EXAMPLE(osgdirectinput) + diff --git a/examples/osgdirectinput/DirectInputRegistry b/examples/osgdirectinput/DirectInputRegistry new file mode 100644 index 000000000..f55a4bc5d --- /dev/null +++ b/examples/osgdirectinput/DirectInputRegistry @@ -0,0 +1,74 @@ +/* OpenSceneGraph example, osgdirectinput. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#ifndef OSGDIRECTINPUT_H +#define OSGDIRECTINPUT_H + +#define DIRECTINPUT_VERSION 0x0800 +#include +#include +#include + +class JoystickEvent : public osg::Referenced +{ +public: + JoystickEvent() {} + virtual ~JoystickEvent() {} + DIJOYSTATE2 _js; +}; + +class DirectInputRegistry : public osg::Referenced +{ +public: + static DirectInputRegistry* instance() + { + static osg::ref_ptr s_registry = new DirectInputRegistry; + return s_registry.get(); + } + + LPDIRECTINPUT8& getDevice() { return _inputDevice; } + LPDIRECTINPUTDEVICE8& getKeyboard() { return _keyboard; } + LPDIRECTINPUTDEVICE8& getMouse() { return _mouse; } + LPDIRECTINPUTDEVICE8& getJoyStick() { return _joystick; } + + bool valid() const { return _supportDirectInput; } + + bool initKeyboard( HWND handle ); + bool initMouse( HWND handle ); + bool initJoystick( HWND handle ); + + void updateState( osgGA::EventQueue* eventQueue ); + +protected: + DirectInputRegistry(); + virtual ~DirectInputRegistry(); + + bool initImplementation( HWND handle, LPDIRECTINPUTDEVICE8 device, LPCDIDATAFORMAT format ); + void pollDevice( LPDIRECTINPUTDEVICE8 device ); + void releaseDevice( LPDIRECTINPUTDEVICE8 device ); + + static BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* didInstance, VOID* ); + + LPDIRECTINPUT8 _inputDevice; + LPDIRECTINPUTDEVICE8 _keyboard; + LPDIRECTINPUTDEVICE8 _mouse; + LPDIRECTINPUTDEVICE8 _joystick; + bool _supportDirectInput; +}; + +#endif diff --git a/examples/osgdirectinput/DirectInputRegistry.cpp b/examples/osgdirectinput/DirectInputRegistry.cpp new file mode 100644 index 000000000..2990a06f5 --- /dev/null +++ b/examples/osgdirectinput/DirectInputRegistry.cpp @@ -0,0 +1,210 @@ +/* OpenSceneGraph example, osgdirectinput. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#include +#include +#include "DirectInputRegistry" + +typedef std::pair KeyValue; +typedef std::map KeyMap; +KeyMap g_keyMap; + +void buildKeyMap() +{ + // TODO: finish the key map as you wish + g_keyMap[DIK_ESCAPE] = KeyValue(osgGA::GUIEventAdapter::KEY_Escape, 0); + g_keyMap[DIK_1] = KeyValue('1', 0); + g_keyMap[DIK_2] = KeyValue('2', 0); + g_keyMap[DIK_3] = KeyValue('3', 0); + g_keyMap[DIK_4] = KeyValue('4', 0); + g_keyMap[DIK_5] = KeyValue('5', 0); + g_keyMap[DIK_6] = KeyValue('6', 0); + g_keyMap[DIK_7] = KeyValue('7', 0); + g_keyMap[DIK_8] = KeyValue('8', 0); + g_keyMap[DIK_9] = KeyValue('9', 0); + g_keyMap[DIK_0] = KeyValue('0', 0); + g_keyMap[DIK_MINUS] = KeyValue('-', 0); + g_keyMap[DIK_EQUALS] = KeyValue('=', 0); + g_keyMap[DIK_BACK] = KeyValue(osgGA::GUIEventAdapter::KEY_BackSpace, 0); + g_keyMap[DIK_TAB] = KeyValue(osgGA::GUIEventAdapter::KEY_Tab, 0); + g_keyMap[DIK_SPACE] = KeyValue(osgGA::GUIEventAdapter::KEY_Space, 0); +} + +bool DirectInputRegistry::initKeyboard( HWND handle ) +{ + if ( !_inputDevice ) return false; + + HRESULT hr = _inputDevice->CreateDevice( GUID_SysKeyboard, &_keyboard, NULL ); + if ( FAILED(hr) || _keyboard==NULL ) + { + osg::notify(osg::WARN) << "Unable to create keyboard." << std::endl; + return false; + } + buildKeyMap(); + return initImplementation( handle, _keyboard, &c_dfDIKeyboard ); +} + +bool DirectInputRegistry::initMouse( HWND handle ) +{ + if ( !_inputDevice ) return false; + + HRESULT hr = _inputDevice->CreateDevice( GUID_SysMouse, &_mouse, NULL ); + if ( FAILED(hr) || _mouse==NULL ) + { + osg::notify(osg::WARN) << "Unable to create mouse." << std::endl; + return false; + } + return initImplementation( handle, _mouse, &c_dfDIMouse2 ); +} + +bool DirectInputRegistry::initJoystick( HWND handle ) +{ + if ( !_inputDevice ) return false; + + HRESULT hr = _inputDevice->EnumDevices( DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, + NULL, DIEDFL_ATTACHEDONLY ); + if ( FAILED(hr) || _joystick==NULL ) + { + osg::notify(osg::WARN) << "Unable to enumerate joysticks." << std::endl; + return false; + } + return initImplementation( handle, _joystick, &c_dfDIJoystick2 ); +} + +void DirectInputRegistry::updateState( osgGA::EventQueue* eventQueue ) +{ + HRESULT hr; + if ( !_supportDirectInput || !eventQueue ) return; + + if ( _keyboard ) + { + pollDevice( _keyboard ); + + char buffer[256] = {0}; + hr = _keyboard->GetDeviceState( sizeof(buffer), &buffer ); + if ( SUCCEEDED(hr) ) + { + for ( KeyMap::iterator itr=g_keyMap.begin(); itr!=g_keyMap.end(); ++itr ) + { + KeyValue& key = itr->second; + char value = buffer[itr->first]; + if ( key.second==value ) continue; + + key.second = value; + if ( value&0x80 ) + eventQueue->keyPress( key.first ); + else + eventQueue->keyRelease( key.first ); + } + } + } + + if ( _mouse ) + { + pollDevice( _mouse ); + + DIMOUSESTATE2 mouseState; + hr = _mouse->GetDeviceState( sizeof(DIMOUSESTATE2), &mouseState ); + + // TODO: add mouse handlers + } + + if ( _joystick ) + { + pollDevice( _joystick ); + + osg::ref_ptr event = new JoystickEvent; + hr = _joystick->GetDeviceState( sizeof(DIJOYSTATE2), &(event->_js) ); + if ( SUCCEEDED(hr) ) eventQueue->userEvent( event.get() ); + } +} + +DirectInputRegistry::DirectInputRegistry() +: _keyboard(0), _mouse(0), _joystick(0), + _supportDirectInput(true) +{ + HRESULT hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, + IID_IDirectInput8, (VOID**)&_inputDevice, NULL ); + if ( FAILED(hr) ) + { + osg::notify(osg::WARN) << "Unable to create DirectInput object." << std::endl; + _supportDirectInput = false; + } +} + +DirectInputRegistry::~DirectInputRegistry() +{ + releaseDevice( _keyboard ); + releaseDevice( _mouse ); + releaseDevice( _joystick ); + if ( _inputDevice ) _inputDevice->Release(); +} + +bool DirectInputRegistry::initImplementation( HWND handle, LPDIRECTINPUTDEVICE8 device, LPCDIDATAFORMAT format ) +{ + _supportDirectInput = true; + HRESULT hr = device->SetDataFormat( format ); + if ( FAILED(hr) ) + { + osg::notify(osg::WARN) << "Unable to set device data format." << std::endl; + _supportDirectInput = false; + } + + hr = device->SetCooperativeLevel( handle, DISCL_EXCLUSIVE|DISCL_FOREGROUND ); + if ( FAILED(hr) ) + { + osg::notify(osg::WARN) << "Unable to attach device to window." << std::endl; + _supportDirectInput = false; + } + + device->Acquire(); + return _supportDirectInput; +} + +void DirectInputRegistry::pollDevice( LPDIRECTINPUTDEVICE8 device ) +{ + HRESULT hr = device->Poll(); + if ( FAILED(hr) ) + { + device->Acquire(); + if ( hr==DIERR_INPUTLOST ) + osg::notify(osg::WARN) << "Device lost." << std::endl; + } +} + +void DirectInputRegistry::releaseDevice( LPDIRECTINPUTDEVICE8 device ) +{ + if ( device ) + { + device->Unacquire(); + device->Release(); + } +} + +BOOL CALLBACK DirectInputRegistry::EnumJoysticksCallback( const DIDEVICEINSTANCE* didInstance, VOID* ) +{ + HRESULT hr; + LPDIRECTINPUT8 device = DirectInputRegistry::instance()->getDevice(); + if ( device ) + { + hr = device->CreateDevice( didInstance->guidInstance, + &(DirectInputRegistry::instance()->getJoyStick()), NULL ); + } + if ( FAILED(hr) ) return DIENUM_CONTINUE; + return DIENUM_STOP; +} diff --git a/examples/osgdirectinput/osgdirectinput.cpp b/examples/osgdirectinput/osgdirectinput.cpp new file mode 100644 index 000000000..8546da4c0 --- /dev/null +++ b/examples/osgdirectinput/osgdirectinput.cpp @@ -0,0 +1,115 @@ +/* OpenSceneGraph example, osgdirectinput. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include "DirectInputRegistry" + +class CustomViewer : public osgViewer::Viewer +{ +public: + CustomViewer() : osgViewer::Viewer() {} + virtual ~CustomViewer() {} + + virtual void eventTraversal() + { + DirectInputRegistry::instance()->updateState( _eventQueue.get() ); + osgViewer::Viewer::eventTraversal(); + } + +protected: + virtual void viewerInit() + { + osgViewer::GraphicsWindowWin32* windowWin32 = + dynamic_cast( _camera->getGraphicsContext() ); + if ( windowWin32 ) + { + HWND hwnd = windowWin32->getHWND(); + DirectInputRegistry::instance()->initKeyboard( hwnd ); + //DirectInputRegistry::instance()->initMouse( hwnd ); + DirectInputRegistry::instance()->initJoystick( hwnd ); + } + osgViewer::Viewer::viewerInit(); + } +}; + +class JoystickHandler : public osgGA::GUIEventHandler +{ +public: + JoystickHandler() {} + + bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) + { + switch ( ea.getEventType() ) + { + case osgGA::GUIEventAdapter::KEYDOWN: + std::cout << "*** Key 0x" << std::hex << ea.getKey() << std::dec << " down ***" << std::endl; + break; + case osgGA::GUIEventAdapter::KEYUP: + std::cout << "*** Key 0x" << std::hex << ea.getKey() << std::dec << " up ***" << std::endl; + break; + case osgGA::GUIEventAdapter::USER: + { + const JoystickEvent* event = dynamic_cast( ea.getUserData() ); + if ( !event ) break; + + const DIJOYSTATE2& js = event->_js; + for ( unsigned int i=0; i<128; ++i ) + { + if ( js.rgbButtons[i] ) + std::cout << "*** Joystick Btn" << i << " = " << (int)js.rgbButtons[i] << std::endl; + } + + if ( js.lX==0x0000 ) std::cout << "*** Joystick X-" << std::endl; + else if ( js.lX==0xffff ) std::cout << "*** Joystick X+" << std::endl; + + if ( js.lY==0 ) std::cout << "*** Joystick Y-" << std::endl; + else if ( js.lY==0xffff ) std::cout << "*** Joystick Y+" << std::endl; + } + return true; + default: + break; + } + return false; + } +}; + +int main( int argc, char** argv ) +{ + osg::ArgumentParser arguments( &argc, argv ); + osg::Node* model = osgDB::readNodeFiles( arguments ); + if ( !model ) model = osgDB::readNodeFile( "cow.osg" ); + if ( !model ) + { + std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; + return 1; + } + + CustomViewer viewer; + viewer.addEventHandler( new JoystickHandler ); + viewer.addEventHandler( new osgViewer::StatsHandler ); + viewer.addEventHandler( new osgViewer::WindowSizeHandler ); + viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); + viewer.setSceneData( model ); + viewer.setUpViewInWindow( 250, 50, 800, 600 ); + return viewer.run(); +}