Commit 7087bd0f authored by Kyle Rassweiler's avatar Kyle Rassweiler
Browse files

Merge branch 'master' of https://github.com/wgois/OIS

Conflicts:
	demos/OISConsole.cpp

Had pushed this fix to the wrong repo previously - KR
parents abd16784 692546bf
#include "mac/MacMouse.h" #include "mac/MacMouse.h"
#include "mac/MacInputManager.h" #include "mac/MacInputManager.h"
#include "mac/MacHelpers.h" #include "mac/MacHelpers.h"
#include "OISException.h" #include "OISException.h"
#include "OISEvents.h" #include "OISEvents.h"
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
#include <list> #include <list>
#include <iostream> #include <iostream>
using namespace OIS; using namespace OIS;
//Events we subscribe to and remove from queue //Events we subscribe to and remove from queue
const EventTypeSpec mouseEvents[] = { const EventTypeSpec mouseEvents[] = {
{ kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseUp },
{ kEventClassMouse, kEventMouseMoved }, { kEventClassMouse, kEventMouseMoved },
{ kEventClassMouse, kEventMouseDragged }, { kEventClassMouse, kEventMouseDragged },
{ kEventClassMouse, kEventMouseWheelMoved } { kEventClassMouse, kEventMouseWheelMoved }
}; };
const EventTypeSpec WinFocusAcquired [] = {{kEventClassApplication, kEventAppDeactivated}}; const EventTypeSpec WinFocusAcquired [] = {{kEventClassApplication, kEventAppDeactivated}};
//-------------------------------------------------------------------// //-------------------------------------------------------------------//
MacMouse::MacMouse( InputManager* creator, bool buffered ) MacMouse::MacMouse( InputManager* creator, bool buffered )
: Mouse(creator->inputSystemName(), buffered, 0, creator), mNeedsToRegainFocus( false ) : Mouse(creator->inputSystemName(), buffered, 0, creator), mNeedsToRegainFocus( false )
{ {
mouseEventRef = NULL; mouseEventRef = NULL;
mWindowFocusHandler = NULL; mWindowFocusHandler = NULL;
// Get a "Univeral procedure pointer" for our callback // Get a "Univeral procedure pointer" for our callback
mouseUPP = NewEventHandlerUPP(MouseWrapper); mouseUPP = NewEventHandlerUPP(MouseWrapper);
mWindowFocusListener = NewEventHandlerUPP(WindowFocusChanged); mWindowFocusListener = NewEventHandlerUPP(WindowFocusChanged);
static_cast<MacInputManager*>(mCreator)->_setMouseUsed(true); static_cast<MacInputManager*>(mCreator)->_setMouseUsed(true);
} }
MacMouse::~MacMouse() MacMouse::~MacMouse()
{ {
if(mouseEventRef != NULL) if(mouseEventRef != NULL)
RemoveEventHandler(mouseEventRef); RemoveEventHandler(mouseEventRef);
if(mWindowFocusHandler != NULL) if(mWindowFocusHandler != NULL)
RemoveEventHandler(mWindowFocusHandler); RemoveEventHandler(mWindowFocusHandler);
DisposeEventHandlerUPP(mouseUPP); DisposeEventHandlerUPP(mouseUPP);
DisposeEventHandlerUPP(mWindowFocusListener); DisposeEventHandlerUPP(mWindowFocusListener);
// Restore Mouse // Restore Mouse
CGAssociateMouseAndMouseCursorPosition(TRUE); CGAssociateMouseAndMouseCursorPosition(TRUE);
CGDisplayShowCursor(kCGDirectMainDisplay); CGDisplayShowCursor(kCGDirectMainDisplay);
static_cast<MacInputManager*>(mCreator)->_setMouseUsed(false); static_cast<MacInputManager*>(mCreator)->_setMouseUsed(false);
} }
void MacMouse::_initialize() void MacMouse::_initialize()
{ {
mState.clear(); mState.clear();
mTempState.clear(); mTempState.clear();
mMouseWarped = false; mMouseWarped = false;
// Hide OS Mouse // Hide OS Mouse
CGDisplayHideCursor(kCGDirectMainDisplay); CGDisplayHideCursor(kCGDirectMainDisplay);
MacInputManager* im = static_cast<MacInputManager*>(mCreator); MacInputManager* im = static_cast<MacInputManager*>(mCreator);
WindowRef win = im->_getWindow(); WindowRef win = im->_getWindow();
if(win) if(win)
{ {
Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f}; Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f};
GetWindowBounds(win, kWindowContentRgn, &clipRect); GetWindowBounds(win, kWindowContentRgn, &clipRect);
CGPoint warpPoint; CGPoint warpPoint;
warpPoint.x = ((clipRect.right - clipRect.left) / 2) + clipRect.left; warpPoint.x = ((clipRect.right - clipRect.left) / 2) + clipRect.left;
warpPoint.y = ((clipRect.bottom - clipRect.top) / 2) + clipRect.top; warpPoint.y = ((clipRect.bottom - clipRect.top) / 2) + clipRect.top;
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, warpPoint); //Place at display origin CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, warpPoint); //Place at display origin
mMouseWarped = true; mMouseWarped = true;
} }
//Now that mouse is warped, start listening for events //Now that mouse is warped, start listening for events
EventTargetRef event = ((MacInputManager*)mCreator)->_getEventTarget(); EventTargetRef event = ((MacInputManager*)mCreator)->_getEventTarget();
if(mouseEventRef != NULL) if(mouseEventRef != NULL)
RemoveEventHandler(mouseEventRef); RemoveEventHandler(mouseEventRef);
if(mWindowFocusHandler != NULL) if(mWindowFocusHandler != NULL)
RemoveEventHandler(mWindowFocusHandler); RemoveEventHandler(mWindowFocusHandler);
mouseEventRef = mWindowFocusHandler = NULL; mouseEventRef = mWindowFocusHandler = NULL;
if(InstallEventHandler(event, mouseUPP, GetEventTypeCount(mouseEvents), mouseEvents, this, &mouseEventRef) != noErr) if(InstallEventHandler(event, mouseUPP, GetEventTypeCount(mouseEvents), mouseEvents, this, &mouseEventRef) != noErr)
OIS_EXCEPT( E_General, "MacMouse::_initialize >> Error loading Mouse event handler" ); OIS_EXCEPT( E_General, "MacMouse::_initialize >> Error loading Mouse event handler" );
if(InstallEventHandler(event, mWindowFocusListener, GetEventTypeCount(WinFocusAcquired), WinFocusAcquired, this, &mWindowFocusHandler) != noErr) if(InstallEventHandler(event, mWindowFocusListener, GetEventTypeCount(WinFocusAcquired), WinFocusAcquired, this, &mWindowFocusHandler) != noErr)
OIS_EXCEPT( E_General, "MacMouse::_initialize >> Error loading Mouse event handler" ); OIS_EXCEPT( E_General, "MacMouse::_initialize >> Error loading Mouse event handler" );
//Lock OS Mouse movement //Lock OS Mouse movement
mNeedsToRegainFocus = false; mNeedsToRegainFocus = false;
CGAssociateMouseAndMouseCursorPosition(FALSE); CGAssociateMouseAndMouseCursorPosition(FALSE);
} }
OSStatus MacMouse::WindowFocusChanged(EventHandlerCallRef nextHandler, EventRef event, void* macMouse) OSStatus MacMouse::WindowFocusChanged(EventHandlerCallRef nextHandler, EventRef event, void* macMouse)
{ {
//std::cout << "Window Focus Changed\n"; //std::cout << "Window Focus Changed\n";
MacMouse* _this = static_cast<MacMouse*>(macMouse); MacMouse* _this = static_cast<MacMouse*>(macMouse);
if (_this) if (_this)
{ {
_this->mNeedsToRegainFocus = true; _this->mNeedsToRegainFocus = true;
CGAssociateMouseAndMouseCursorPosition(TRUE); CGAssociateMouseAndMouseCursorPosition(TRUE);
// propagate the event down the chain // propagate the event down the chain
return CallNextEventHandler(nextHandler, event); return CallNextEventHandler(nextHandler, event);
} }
else else
OIS_EXCEPT(E_General, "MouseWrapper >> Being called by something other than our event handler!"); OIS_EXCEPT(E_General, "MouseWrapper >> Being called by something other than our event handler!");
} }
void MacMouse::setBuffered( bool buffered ) void MacMouse::setBuffered( bool buffered )
{ {
mBuffered = buffered; mBuffered = buffered;
} }
void MacMouse::capture() void MacMouse::capture()
{ {
mState.X.rel = 0; mState.X.rel = 0;
mState.Y.rel = 0; mState.Y.rel = 0;
mState.Z.rel = 0; mState.Z.rel = 0;
if(mTempState.X.rel || mTempState.Y.rel || mTempState.Z.rel) if(mTempState.X.rel || mTempState.Y.rel || mTempState.Z.rel)
{ {
//printf("%i %i %i\n\n", mTempState.X.rel, mTempState.Y.rel, mTempState.Z.rel); //printf("%i %i %i\n\n", mTempState.X.rel, mTempState.Y.rel, mTempState.Z.rel);
//Set new relative motion values //Set new relative motion values
mState.X.rel = mTempState.X.rel; mState.X.rel = mTempState.X.rel;
mState.Y.rel = mTempState.Y.rel; mState.Y.rel = mTempState.Y.rel;
mState.Z.rel = mTempState.Z.rel; mState.Z.rel = mTempState.Z.rel;
//Update absolute position //Update absolute position
mState.X.abs += mTempState.X.rel; mState.X.abs += mTempState.X.rel;
mState.Y.abs += mTempState.Y.rel; mState.Y.abs += mTempState.Y.rel;
if(mState.X.abs > mState.width) if(mState.X.abs > mState.width)
mState.X.abs = mState.width; mState.X.abs = mState.width;
else if(mState.X.abs < 0) else if(mState.X.abs < 0)
mState.X.abs = 0; mState.X.abs = 0;
if(mState.Y.abs > mState.height) if(mState.Y.abs > mState.height)
mState.Y.abs = mState.height; mState.Y.abs = mState.height;
else if(mState.Y.abs < 0) else if(mState.Y.abs < 0)
mState.Y.abs = 0; mState.Y.abs = 0;
mState.Z.abs += mTempState.Z.rel; mState.Z.abs += mTempState.Z.rel;
//Fire off event //Fire off event
if(mListener && mBuffered) if(mListener && mBuffered)
mListener->mouseMoved(MouseEvent(this, mState)); mListener->mouseMoved(MouseEvent(this, mState));
} }
mTempState.clear(); mTempState.clear();
} }
void MacMouse::_mouseCallback( EventRef theEvent ) void MacMouse::_mouseCallback( EventRef theEvent )
{ {
OSStatus result = eventNotHandledErr; OSStatus result = eventNotHandledErr;
UInt32 kind = GetEventKind (theEvent); UInt32 kind = GetEventKind (theEvent);
switch(kind) switch(kind)
{ {
case kEventMouseDragged: case kEventMouseDragged:
case kEventMouseMoved: case kEventMouseMoved:
{ {
//HIPoint location = {0.0f, 0.0f}; //HIPoint location = {0.0f, 0.0f};
HIPoint delta = {0.0f, 0.0f}; HIPoint delta = {0.0f, 0.0f};
//Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f}; //Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f};
if(mNeedsToRegainFocus) if(mNeedsToRegainFocus)
break; break;
// Capture the parameters // Capture the parameters
// TODO: Look into HIViewNewTrackingArea // TODO: Look into HIViewNewTrackingArea
//GetEventParameter(theEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HIPoint), NULL, &location); //GetEventParameter(theEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HIPoint), NULL, &location);
GetEventParameter(theEvent, kEventParamMouseDelta, typeHIPoint, NULL, sizeof(HIPoint), NULL, &delta); GetEventParameter(theEvent, kEventParamMouseDelta, typeHIPoint, NULL, sizeof(HIPoint), NULL, &delta);
// Mouse X and Y are the position on the screen, // Mouse X and Y are the position on the screen,
// startng from top-left at 0,0 caps at full monitor resolution // startng from top-left at 0,0 caps at full monitor resolution
// If we have a window we need to return adjusted coordinates // If we have a window we need to return adjusted coordinates
// If not, just use raw coordinates - only do this if showing OS mouse // If not, just use raw coordinates - only do this if showing OS mouse
//MacInputManager* im = static_cast<MacInputManager*>(mCreator); //MacInputManager* im = static_cast<MacInputManager*>(mCreator);
//WindowRef win = im->_getWindow(); //WindowRef win = im->_getWindow();
//if(win != NULL) //if(win != NULL)
//{ //{
// GetWindowBounds(win, kWindowContentRgn, &clipRect); // GetWindowBounds(win, kWindowContentRgn, &clipRect);
//} //}
//else //else
//{ //{
// clipRect.right = mState.width; // clipRect.right = mState.width;
// clipRect.bottom = mState.height; // clipRect.bottom = mState.height;
//} //}
// clip the mouse, absolute positioning // clip the mouse, absolute positioning
//if (location.x <= clipRect.left) //if (location.x <= clipRect.left)
// mState.X.abs = 0; // mState.X.abs = 0;
//else if(location.x >= clipRect.right) //else if(location.x >= clipRect.right)
// mState.X.abs = clipRect.right - clipRect.left; // mState.X.abs = clipRect.right - clipRect.left;
//else //else
// mState.X.abs = location.x - clipRect.left; // mState.X.abs = location.x - clipRect.left;
//if (location.y <= clipRect.top) //if (location.y <= clipRect.top)
// mState.Y.abs = 0; // mState.Y.abs = 0;
//else if(location.y >= clipRect.bottom) //else if(location.y >= clipRect.bottom)
// mState.Y.abs = clipRect.bottom - clipRect.top; // mState.Y.abs = clipRect.bottom - clipRect.top;
//else //else
// mState.Y.abs = location.y - clipRect.top; // mState.Y.abs = location.y - clipRect.top;
// relative positioning // relative positioning
if(!mMouseWarped) if(!mMouseWarped)
{ {
mTempState.X.rel += delta.x; mTempState.X.rel += delta.x;
mTempState.Y.rel += delta.y; mTempState.Y.rel += delta.y;
} }
mMouseWarped = false; mMouseWarped = false;
break; break;
} }
case kEventMouseDown: case kEventMouseDown:
{ {
EventMouseButton button = 0; EventMouseButton button = 0;
int mouseButton = 3; int mouseButton = 3;
UInt32 modifiers = 0; UInt32 modifiers = 0;
if(mNeedsToRegainFocus) if(mNeedsToRegainFocus)
break; break;
// Capture parameters // Capture parameters
GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &button); GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &button);
GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
if((button == kEventMouseButtonTertiary) || ((button == kEventMouseButtonPrimary) && (modifiers & optionKey))) if((button == kEventMouseButtonTertiary) || ((button == kEventMouseButtonPrimary) && (modifiers & optionKey)))
{ {
mouseButton = 2; mouseButton = 2;
mState.buttons |= 1 << mouseButton; mState.buttons |= 1 << mouseButton;
} }
else if((button == kEventMouseButtonSecondary) || ((button == kEventMouseButtonPrimary) && (modifiers & controlKey))) else if((button == kEventMouseButtonSecondary) || ((button == kEventMouseButtonPrimary) && (modifiers & controlKey)))
{ {
mouseButton = 1; mouseButton = 1;
mState.buttons |= 1 << mouseButton; mState.buttons |= 1 << mouseButton;
} }
else if(button == kEventMouseButtonPrimary) else if(button == kEventMouseButtonPrimary)
{ {
mouseButton = 0; mouseButton = 0;
mState.buttons |= 1 << mouseButton; mState.buttons |= 1 << mouseButton;
} }
if( mListener && mBuffered ) if( mListener && mBuffered )
mListener->mousePressed( MouseEvent( this, mState ), (MouseButtonID)mouseButton ); mListener->mousePressed( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
break; break;
} }
case kEventMouseUp: case kEventMouseUp:
{ {
EventMouseButton button = 0; EventMouseButton button = 0;
int mouseButton = 3; int mouseButton = 3;
UInt32 modifiers = 0; UInt32 modifiers = 0;
if(mNeedsToRegainFocus) if(mNeedsToRegainFocus)
{ {
mNeedsToRegainFocus = false; mNeedsToRegainFocus = false;
CGAssociateMouseAndMouseCursorPosition(false); CGAssociateMouseAndMouseCursorPosition(false);
MacInputManager* im = static_cast<MacInputManager*>(mCreator); MacInputManager* im = static_cast<MacInputManager*>(mCreator);
WindowRef win = im->_getWindow(); WindowRef win = im->_getWindow();
if(win) if(win)
{ {
Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f}; Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f};
GetWindowBounds(win, kWindowContentRgn, &clipRect); GetWindowBounds(win, kWindowContentRgn, &clipRect);
CGPoint warpPoint; CGPoint warpPoint;
warpPoint.x = ((clipRect.right - clipRect.left) / 2) + clipRect.left; warpPoint.x = ((clipRect.right - clipRect.left) / 2) + clipRect.left;
warpPoint.y = ((clipRect.bottom - clipRect.top) / 2) + clipRect.top; warpPoint.y = ((clipRect.bottom - clipRect.top) / 2) + clipRect.top;
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, warpPoint); //Place at display origin CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, warpPoint); //Place at display origin
CGDisplayHideCursor(kCGDirectMainDisplay); CGDisplayHideCursor(kCGDirectMainDisplay);
mMouseWarped = true; mMouseWarped = true;
} }
//Once we regain focus, we do not really know what state all the buttons are in - for now, set to not pressed. todo, check current status //Once we regain focus, we do not really know what state all the buttons are in - for now, set to not pressed. todo, check current status
//compare against old status, and send off any needed events //compare against old status, and send off any needed events
mState.buttons = 0; mState.buttons = 0;
break; break;
} }
// Capture parameters // Capture parameters
GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &button); GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &button);
GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
if ((button == kEventMouseButtonTertiary) || ((button == kEventMouseButtonPrimary) && (modifiers & optionKey))) if ((button == kEventMouseButtonTertiary) || ((button == kEventMouseButtonPrimary) && (modifiers & optionKey)))
{ {
mouseButton = 2; mouseButton = 2;
mState.buttons &= ~(1 << mouseButton); mState.buttons &= ~(1 << mouseButton);
} }
else if ((button == kEventMouseButtonSecondary) || ((button == kEventMouseButtonPrimary) && (modifiers & controlKey))) else if ((button == kEventMouseButtonSecondary) || ((button == kEventMouseButtonPrimary) && (modifiers & controlKey)))
{ {
mouseButton = 1; mouseButton = 1;
mState.buttons &= ~(1 << mouseButton); mState.buttons &= ~(1 << mouseButton);
} }
else if (button == kEventMouseButtonPrimary) else if (button == kEventMouseButtonPrimary)
{ {
mouseButton = 0; mouseButton = 0;
mState.buttons &= ~(1 << mouseButton); mState.buttons &= ~(1 << mouseButton);
} }
if( mListener && mBuffered ) if( mListener && mBuffered )
mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)mouseButton ); mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
break; break;
} }
case kEventMouseWheelMoved: case kEventMouseWheelMoved:
{ {
SInt32 wheelDelta = 0; SInt32 wheelDelta = 0;
EventMouseWheelAxis wheelAxis = 0; EventMouseWheelAxis wheelAxis = 0;
// Capture parameters // Capture parameters
GetEventParameter(theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(EventMouseWheelAxis), NULL, &wheelAxis); GetEventParameter(theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(EventMouseWheelAxis), NULL, &wheelAxis);
GetEventParameter(theEvent, kEventParamMouseWheelDelta, typeSInt32, NULL, sizeof(SInt32), NULL, &wheelDelta); GetEventParameter(theEvent, kEventParamMouseWheelDelta, typeSInt32, NULL, sizeof(SInt32), NULL, &wheelDelta);
// If the Y axis of the wheel changed, then update the Z // If the Y axis of the wheel changed, then update the Z
// Does OIS care about the X wheel axis? // Does OIS care about the X wheel axis?
if(wheelAxis == kEventMouseWheelAxisY) if(wheelAxis == kEventMouseWheelAxisY)
mTempState.Z.rel += (wheelDelta * 60); mTempState.Z.rel += (wheelDelta * 60);
break; break;
} }
default: default:
break; break;
} }
} }
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "win32/Win32ForceFeedback.h" #include "win32/Win32ForceFeedback.h"
#include "OISException.h" #include "OISException.h"
#include <math.h> #include <math.h>
// 0 = No trace; 1 = Important traces; 2 = Debug traces // 0 = No trace; 1 = Important traces; 2 = Debug traces
#define OIS_WIN32_JOYFF_DEBUG 1 #define OIS_WIN32_JOYFF_DEBUG 1
#if (defined (_DEBUG) || defined(OIS_WIN32_JOYFF_DEBUG)) #if (defined (_DEBUG) || defined(OIS_WIN32_JOYFF_DEBUG))
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
using namespace std; using namespace std;
#endif #endif
using namespace OIS; using namespace OIS;
//--------------------------------------------------------------// //--------------------------------------------------------------//
Win32ForceFeedback::Win32ForceFeedback(IDirectInputDevice8* pDIJoy, const DIDEVCAPS* pDIJoyCaps) : Win32ForceFeedback::Win32ForceFeedback(IDirectInputDevice8* pDIJoy, const DIDEVCAPS* pDIJoyCaps) :
mHandles(0), mJoyStick(pDIJoy), mFFAxes(0), mpDIJoyCaps(pDIJoyCaps) mHandles(0), mJoyStick(pDIJoy), mFFAxes(0), mpDIJoyCaps(pDIJoyCaps)
{ {
#if (OIS_WIN32_JOYFF_DEBUG > 0) #if (OIS_WIN32_JOYFF_DEBUG > 0)
cout << "FFSamplePeriod : " << mpDIJoyCaps->dwFFSamplePeriod << " mu-s, " cout << "FFSamplePeriod : " << mpDIJoyCaps->dwFFSamplePeriod << " mu-s, "
<< "FFMinTimeResolution : " << mpDIJoyCaps->dwFFMinTimeResolution << " mu-s," << "FFMinTimeResolution : " << mpDIJoyCaps->dwFFMinTimeResolution << " mu-s,"
<< "" << endl; << "" << endl;
#endif #endif
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
Win32ForceFeedback::~Win32ForceFeedback() Win32ForceFeedback::~Win32ForceFeedback()
{ {
//Get the effect - if it exists //Get the effect - if it exists
for(EffectList::iterator i = mEffectList.begin(); i != mEffectList.end(); ++i ) for(EffectList::iterator i = mEffectList.begin(); i != mEffectList.end(); ++i )
{ {
LPDIRECTINPUTEFFECT dxEffect = i->second; LPDIRECTINPUTEFFECT dxEffect = i->second;
if( dxEffect ) if( dxEffect )
{ {
dxEffect->Unload(); dxEffect->Unload();
dxEffect->Release(); dxEffect->Release();
} }
} }
mEffectList.clear(); mEffectList.clear();
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
short Win32ForceFeedback::getFFAxesNumber() short Win32ForceFeedback::getFFAxesNumber()
{ {
return mFFAxes; return mFFAxes;
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
unsigned short Win32ForceFeedback::getFFMemoryLoad() unsigned short Win32ForceFeedback::getFFMemoryLoad()
{ {
DIPROPDWORD dipdw; // DIPROPDWORD contains a DIPROPHEADER structure. DIPROPDWORD dipdw; // DIPROPDWORD contains a DIPROPHEADER structure.
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0; // device property dipdw.diph.dwObj = 0; // device property
dipdw.diph.dwHow = DIPH_DEVICE; dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = 0; // In case of any error. dipdw.dwData = 0; // In case of any error.
const HRESULT hr = mJoyStick->GetProperty(DIPROP_FFLOAD, &dipdw.diph); const HRESULT hr = mJoyStick->GetProperty(DIPROP_FFLOAD, &dipdw.diph);
if(FAILED(hr)) if(FAILED(hr))
{ {
if (hr == DIERR_NOTEXCLUSIVEACQUIRED) if (hr == DIERR_NOTEXCLUSIVEACQUIRED)
OIS_EXCEPT(E_General, "Can't query FF memory load as device was not acquired in exclusive mode"); OIS_EXCEPT(E_General, "Can't query FF memory load as device was not acquired in exclusive mode");
else else
OIS_EXCEPT(E_General, "Unknown error querying FF memory load ->.."); OIS_EXCEPT(E_General, "Unknown error querying FF memory load ->..");
} }
return (unsigned short)dipdw.dwData; return (unsigned short)dipdw.dwData;
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::upload( const Effect* effect ) void Win32ForceFeedback::upload( const Effect* effect )
{ {
switch( effect->force ) switch( effect->force )
{ {
case OIS::Effect::ConstantForce: _updateConstantEffect(effect); break; case OIS::Effect::ConstantForce: _updateConstantEffect(effect); break;
case OIS::Effect::RampForce: _updateRampEffect(effect); break; case OIS::Effect::RampForce: _updateRampEffect(effect); break;
case OIS::Effect::PeriodicForce: _updatePeriodicEffect(effect); break; case OIS::Effect::PeriodicForce: _updatePeriodicEffect(effect); break;
case OIS::Effect::ConditionalForce: _updateConditionalEffect(effect); break; case OIS::Effect::ConditionalForce: _updateConditionalEffect(effect); break;
//case OIS::Effect::CustomForce: _updateCustomEffect(effect); break; //case OIS::Effect::CustomForce: _updateCustomEffect(effect); break;
default: OIS_EXCEPT(E_NotImplemented, "Requested Force not Implemented yet, sorry!"); break; default: OIS_EXCEPT(E_NotImplemented, "Requested Force not Implemented yet, sorry!"); break;
} }
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::modify( const Effect* eff ) void Win32ForceFeedback::modify( const Effect* eff )
{ {
//Modifying is essentially the same as an upload, so, just reuse that function //Modifying is essentially the same as an upload, so, just reuse that function
upload(eff); upload(eff);
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::remove( const Effect* eff ) void Win32ForceFeedback::remove( const Effect* eff )
{ {
//Get the effect - if it exists //Get the effect - if it exists
EffectList::iterator i = mEffectList.find(eff->_handle); EffectList::iterator i = mEffectList.find(eff->_handle);
if( i != mEffectList.end() ) if( i != mEffectList.end() )
{ {
LPDIRECTINPUTEFFECT dxEffect = i->second; LPDIRECTINPUTEFFECT dxEffect = i->second;
if( dxEffect ) if( dxEffect )
{ {
dxEffect->Stop(); dxEffect->Stop();
//We care about the return value - as the effect might not //We care about the return value - as the effect might not
//have been unlaoded //have been unlaoded
if( SUCCEEDED(dxEffect->Unload()) ) if( SUCCEEDED(dxEffect->Unload()) )
{ {
dxEffect->Release(); dxEffect->Release();
mEffectList.erase(i); mEffectList.erase(i);
} }
} }
else else
mEffectList.erase(i); mEffectList.erase(i);
} }
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::setMasterGain( float level ) void Win32ForceFeedback::setMasterGain( float level )
{ {
//Between 0 - 10,000 //Between 0 - 10,000
int gain_level = (int)(10000.0f * level); int gain_level = (int)(10000.0f * level);
if( gain_level > 10000 ) if( gain_level > 10000 )
gain_level = 10000; gain_level = 10000;
else if( gain_level < 0 ) else if( gain_level < 0 )
gain_level = 0; gain_level = 0;
DIPROPDWORD DIPropGain; DIPROPDWORD DIPropGain;
DIPropGain.diph.dwSize = sizeof(DIPropGain); DIPropGain.diph.dwSize = sizeof(DIPropGain);
DIPropGain.diph.dwHeaderSize = sizeof(DIPROPHEADER); DIPropGain.diph.dwHeaderSize = sizeof(DIPROPHEADER);
DIPropGain.diph.dwObj = 0; DIPropGain.diph.dwObj = 0;
DIPropGain.diph.dwHow = DIPH_DEVICE; DIPropGain.diph.dwHow = DIPH_DEVICE;
DIPropGain.dwData = gain_level; DIPropGain.dwData = gain_level;
#if (OIS_WIN32_JOYFF_DEBUG > 0) #if (OIS_WIN32_JOYFF_DEBUG > 0)
cout << "Win32ForceFeedback("<< mJoyStick << ") : Setting master gain to " cout << "Win32ForceFeedback("<< mJoyStick << ") : Setting master gain to "
<< level << " => " << DIPropGain.dwData << endl; << level << " => " << DIPropGain.dwData << endl;
#endif #endif
const HRESULT hr = mJoyStick->SetProperty(DIPROP_FFGAIN, &DIPropGain.diph); const HRESULT hr = mJoyStick->SetProperty(DIPROP_FFGAIN, &DIPropGain.diph);
#if defined (_DEBUG) #if defined (_DEBUG)
if(FAILED(hr)) if(FAILED(hr))
cout << "Failed to change master gain" << endl; cout << "Failed to change master gain" << endl;
#endif #endif
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::setAutoCenterMode( bool auto_on ) void Win32ForceFeedback::setAutoCenterMode( bool auto_on )
{ {
DIPROPDWORD DIPropAutoCenter; DIPROPDWORD DIPropAutoCenter;
DIPropAutoCenter.diph.dwSize = sizeof(DIPropAutoCenter); DIPropAutoCenter.diph.dwSize = sizeof(DIPropAutoCenter);
DIPropAutoCenter.diph.dwHeaderSize = sizeof(DIPROPHEADER); DIPropAutoCenter.diph.dwHeaderSize = sizeof(DIPROPHEADER);
DIPropAutoCenter.diph.dwObj = 0; DIPropAutoCenter.diph.dwObj = 0;
DIPropAutoCenter.diph.dwHow = DIPH_DEVICE; DIPropAutoCenter.diph.dwHow = DIPH_DEVICE;
DIPropAutoCenter.dwData = (auto_on ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF); DIPropAutoCenter.dwData = (auto_on ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF);
#if (OIS_WIN32_JOYFF_DEBUG > 0) #if (OIS_WIN32_JOYFF_DEBUG > 0)
cout << "Win32ForceFeedback("<< mJoyStick << ") : Setting auto-center mode to " cout << "Win32ForceFeedback("<< mJoyStick << ") : Setting auto-center mode to "
<< auto_on << " => " << DIPropAutoCenter.dwData << endl; << auto_on << " => " << DIPropAutoCenter.dwData << endl;
#endif #endif
const HRESULT hr = mJoyStick->SetProperty(DIPROP_AUTOCENTER, &DIPropAutoCenter.diph); const HRESULT hr = mJoyStick->SetProperty(DIPROP_AUTOCENTER, &DIPropAutoCenter.diph);
#if defined (_DEBUG) #if defined (_DEBUG)
if(FAILED(hr)) if(FAILED(hr))
cout << "Failed to change auto-center mode" << endl; cout << "Failed to change auto-center mode" << endl;
#endif #endif
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::_updateConstantEffect( const Effect* effect ) void Win32ForceFeedback::_updateConstantEffect( const Effect* effect )
{ {
ConstantEffect *eff = static_cast<ConstantEffect*>(effect->getForceEffect()); ConstantEffect *eff = static_cast<ConstantEffect*>(effect->getForceEffect());
DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
LONG rglDirection[2] = { 0, 0 }; LONG rglDirection[2] = { 0, 0 };
DIENVELOPE diEnvelope; DIENVELOPE diEnvelope;
DICONSTANTFORCE cf; DICONSTANTFORCE cf;
DIEFFECT diEffect; DIEFFECT diEffect;
//Currently only support 1 axis //Currently only support 1 axis
//if( effect->getNumAxes() == 1 ) //if( effect->getNumAxes() == 1 )
cf.lMagnitude = eff->level; cf.lMagnitude = eff->level;
#if (OIS_WIN32_JOYFF_DEBUG > 1) #if (OIS_WIN32_JOYFF_DEBUG > 1)
cout << " Level : " << eff->level cout << " Level : " << eff->level
<< " => " << cf.lMagnitude << endl; << " => " << cf.lMagnitude << endl;
#endif #endif
_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICONSTANTFORCE), &cf, effect, &eff->envelope); _setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICONSTANTFORCE), &cf, effect, &eff->envelope);
_upload(GUID_ConstantForce, &diEffect, effect); _upload(GUID_ConstantForce, &diEffect, effect);
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::_updateRampEffect( const Effect* effect ) void Win32ForceFeedback::_updateRampEffect( const Effect* effect )
{ {
RampEffect *eff = static_cast<RampEffect*>(effect->getForceEffect()); RampEffect *eff = static_cast<RampEffect*>(effect->getForceEffect());
DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
LONG rglDirection[2] = { 0, 0 }; LONG rglDirection[2] = { 0, 0 };
DIENVELOPE diEnvelope; DIENVELOPE diEnvelope;
DIRAMPFORCE rf; DIRAMPFORCE rf;
DIEFFECT diEffect; DIEFFECT diEffect;
//Currently only support 1 axis //Currently only support 1 axis
rf.lStart = eff->startLevel; rf.lStart = eff->startLevel;
rf.lEnd = eff->endLevel; rf.lEnd = eff->endLevel;
_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DIRAMPFORCE), &rf, effect, &eff->envelope ); _setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DIRAMPFORCE), &rf, effect, &eff->envelope );
_upload(GUID_RampForce, &diEffect, effect); _upload(GUID_RampForce, &diEffect, effect);
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::_updatePeriodicEffect( const Effect* effect ) void Win32ForceFeedback::_updatePeriodicEffect( const Effect* effect )
{ {
PeriodicEffect *eff = static_cast<PeriodicEffect*>(effect->getForceEffect()); PeriodicEffect *eff = static_cast<PeriodicEffect*>(effect->getForceEffect());
DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
LONG rglDirection[2] = { 0, 0 }; LONG rglDirection[2] = { 0, 0 };
DIENVELOPE diEnvelope; DIENVELOPE diEnvelope;
DIPERIODIC pf; DIPERIODIC pf;
DIEFFECT diEffect; DIEFFECT diEffect;
//Currently only support 1 axis //Currently only support 1 axis
pf.dwMagnitude = eff->magnitude; pf.dwMagnitude = eff->magnitude;
pf.lOffset = eff->offset; pf.lOffset = eff->offset;
pf.dwPhase = eff->phase; pf.dwPhase = eff->phase;
pf.dwPeriod = eff->period; pf.dwPeriod = eff->period;
_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DIPERIODIC), &pf, effect, &eff->envelope ); _setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DIPERIODIC), &pf, effect, &eff->envelope );
switch( effect->type ) switch( effect->type )
{ {
case OIS::Effect::Square: _upload(GUID_Square, &diEffect, effect); break; case OIS::Effect::Square: _upload(GUID_Square, &diEffect, effect); break;
case OIS::Effect::Triangle: _upload(GUID_Triangle, &diEffect, effect); break; case OIS::Effect::Triangle: _upload(GUID_Triangle, &diEffect, effect); break;
case OIS::Effect::Sine: _upload(GUID_Sine, &diEffect, effect); break; case OIS::Effect::Sine: _upload(GUID_Sine, &diEffect, effect); break;
case OIS::Effect::SawToothUp: _upload(GUID_SawtoothUp, &diEffect, effect); break; case OIS::Effect::SawToothUp: _upload(GUID_SawtoothUp, &diEffect, effect); break;
case OIS::Effect::SawToothDown: _upload(GUID_SawtoothDown, &diEffect, effect); break; case OIS::Effect::SawToothDown: _upload(GUID_SawtoothDown, &diEffect, effect); break;
default: break; default: break;
} }
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::_updateConditionalEffect( const Effect* effect ) void Win32ForceFeedback::_updateConditionalEffect( const Effect* effect )
{ {
ConditionalEffect *eff = static_cast<ConditionalEffect*>(effect->getForceEffect()); ConditionalEffect *eff = static_cast<ConditionalEffect*>(effect->getForceEffect());
DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
LONG rglDirection[2] = { 0, 0 }; LONG rglDirection[2] = { 0, 0 };
DIENVELOPE diEnvelope; DIENVELOPE diEnvelope;
DICONDITION cf; DICONDITION cf;
DIEFFECT diEffect; DIEFFECT diEffect;
cf.lOffset = eff->deadband; cf.lOffset = eff->deadband;
cf.lPositiveCoefficient = eff->rightCoeff; cf.lPositiveCoefficient = eff->rightCoeff;
cf.lNegativeCoefficient = eff->leftCoeff; cf.lNegativeCoefficient = eff->leftCoeff;
cf.dwPositiveSaturation = eff->rightSaturation; cf.dwPositiveSaturation = eff->rightSaturation;
cf.dwNegativeSaturation = eff->leftSaturation; cf.dwNegativeSaturation = eff->leftSaturation;
cf.lDeadBand = eff->deadband; cf.lDeadBand = eff->deadband;
_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICONDITION), &cf, effect, 0 ); _setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICONDITION), &cf, effect, 0 );
switch( effect->type ) switch( effect->type )
{ {
case OIS::Effect::Friction: _upload(GUID_Friction, &diEffect, effect); break; case OIS::Effect::Friction: _upload(GUID_Friction, &diEffect, effect); break;
case OIS::Effect::Damper: _upload(GUID_Damper, &diEffect, effect); break; case OIS::Effect::Damper: _upload(GUID_Damper, &diEffect, effect); break;
case OIS::Effect::Inertia: _upload(GUID_Inertia, &diEffect, effect); break; case OIS::Effect::Inertia: _upload(GUID_Inertia, &diEffect, effect); break;
case OIS::Effect::Spring: _upload(GUID_Spring, &diEffect, effect); break; case OIS::Effect::Spring: _upload(GUID_Spring, &diEffect, effect); break;
default: break; default: break;
} }
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::_updateCustomEffect( const Effect* /*effect*/ ) void Win32ForceFeedback::_updateCustomEffect( const Effect* /*effect*/ )
{ {
//CustomEffect *eff = static_cast<CustomEffect*>(effect->getForceEffect()); //CustomEffect *eff = static_cast<CustomEffect*>(effect->getForceEffect());
// //
//DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; //DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
//LONG rglDirection[2] = { 0, 0 }; //LONG rglDirection[2] = { 0, 0 };
//DIENVELOPE diEnvelope; //DIENVELOPE diEnvelope;
//DICUSTOMFORCE cf; //DICUSTOMFORCE cf;
//DIEFFECT diEffect; //DIEFFECT diEffect;
//cf.cChannels = 0; //cf.cChannels = 0;
//cf.dwSamplePeriod = 0; //cf.dwSamplePeriod = 0;
//cf.cSamples = 0; //cf.cSamples = 0;
//cf.rglForceData = 0; //cf.rglForceData = 0;
//_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICUSTOMFORCE), &cf, effect, &eff->envelope); //_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICUSTOMFORCE), &cf, effect, &eff->envelope);
//_upload(GUID_CustomForce, &diEffect, effect); //_upload(GUID_CustomForce, &diEffect, effect);
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::_setCommonProperties( void Win32ForceFeedback::_setCommonProperties(
DIEFFECT* diEffect, DWORD* rgdwAxes, DIEFFECT* diEffect, DWORD* rgdwAxes,
LONG* rglDirection, DIENVELOPE* diEnvelope, DWORD struct_size, LONG* rglDirection, DIENVELOPE* diEnvelope, DWORD struct_size,
LPVOID struct_type, const Effect* effect, const Envelope* envelope ) LPVOID struct_type, const Effect* effect, const Envelope* envelope )
{ {
ZeroMemory(diEffect, sizeof(DIEFFECT)); ZeroMemory(diEffect, sizeof(DIEFFECT));
diEffect->dwSize = sizeof(DIEFFECT); diEffect->dwSize = sizeof(DIEFFECT);
diEffect->dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; diEffect->dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
diEffect->dwGain = DI_FFNOMINALMAX; diEffect->dwGain = DI_FFNOMINALMAX;
diEffect->dwTriggerButton = DIEB_NOTRIGGER; // effect->trigger_button; // TODO: Conversion diEffect->dwTriggerButton = DIEB_NOTRIGGER; // effect->trigger_button; // TODO: Conversion
diEffect->dwTriggerRepeatInterval = effect->trigger_interval; diEffect->dwTriggerRepeatInterval = effect->trigger_interval;
#if (OIS_WIN32_JOYFF_DEBUG > 1) #if (OIS_WIN32_JOYFF_DEBUG > 1)
cout << " Trigger :" << endl cout << " Trigger :" << endl
<< " Button : " << effect->trigger_button << " Button : " << effect->trigger_button
<< " => " << diEffect->dwTriggerButton << endl << " => " << diEffect->dwTriggerButton << endl
<< " Interval : " << effect->trigger_interval << " Interval : " << effect->trigger_interval
<< " => " << diEffect->dwTriggerRepeatInterval << endl; << " => " << diEffect->dwTriggerRepeatInterval << endl;
#endif #endif
diEffect->cAxes = 1; // effect->getNumAxes(); diEffect->cAxes = 1; // effect->getNumAxes();
diEffect->rgdwAxes = rgdwAxes; diEffect->rgdwAxes = rgdwAxes;
diEffect->rglDirection = rglDirection; // TODO: conversion from effect->direction diEffect->rglDirection = rglDirection; // TODO: conversion from effect->direction
#if (OIS_WIN32_JOYFF_DEBUG > 1) #if (OIS_WIN32_JOYFF_DEBUG > 1)
cout << " Direction : " << Effect::getDirectionName(effect->direction) cout << " Direction : " << Effect::getDirectionName(effect->direction)
<< " => {"; << " => {";
for (int iDir=0; iDir < (int)diEffect->cAxes; iDir++) for (int iDir=0; iDir < (int)diEffect->cAxes; iDir++)
cout << " " << diEffect->rglDirection[iDir]; cout << " " << diEffect->rglDirection[iDir];
cout << "}" << endl; cout << "}" << endl;
#endif #endif
if (diEnvelope && envelope && envelope->isUsed()) if (diEnvelope && envelope && envelope->isUsed())
{ {
diEnvelope->dwSize = sizeof(DIENVELOPE); diEnvelope->dwSize = sizeof(DIENVELOPE);
diEnvelope->dwAttackLevel = envelope->attackLevel; diEnvelope->dwAttackLevel = envelope->attackLevel;
diEnvelope->dwAttackTime = envelope->attackLength; diEnvelope->dwAttackTime = envelope->attackLength;
diEnvelope->dwFadeLevel = envelope->fadeLevel; diEnvelope->dwFadeLevel = envelope->fadeLevel;
diEnvelope->dwFadeTime = envelope->fadeLength; diEnvelope->dwFadeTime = envelope->fadeLength;
diEffect->lpEnvelope = diEnvelope; diEffect->lpEnvelope = diEnvelope;
} }
else else
diEffect->lpEnvelope = 0; diEffect->lpEnvelope = 0;
#if (OIS_WIN32_JOYFF_DEBUG > 1) #if (OIS_WIN32_JOYFF_DEBUG > 1)
if (diEnvelope && envelope && envelope->isUsed()) if (diEnvelope && envelope && envelope->isUsed())
{ {
cout << " Enveloppe :" << endl cout << " Enveloppe :" << endl
<< " AttackLen : " << envelope->attackLength << " AttackLen : " << envelope->attackLength
<< " => " << diEnvelope->dwAttackTime << endl << " => " << diEnvelope->dwAttackTime << endl
<< " AttackLvl : " << envelope->attackLevel << " AttackLvl : " << envelope->attackLevel
<< " => " << diEnvelope->dwAttackLevel << endl << " => " << diEnvelope->dwAttackLevel << endl
<< " FadeLen : " << envelope->fadeLength << " FadeLen : " << envelope->fadeLength
<< " => " << diEnvelope->dwFadeTime << endl << " => " << diEnvelope->dwFadeTime << endl
<< " FadeLvl : " << envelope->fadeLevel << " FadeLvl : " << envelope->fadeLevel
<< " => " << diEnvelope->dwFadeLevel << endl; << " => " << diEnvelope->dwFadeLevel << endl;
} }
#endif #endif
diEffect->dwSamplePeriod = 0; diEffect->dwSamplePeriod = 0;
diEffect->dwDuration = effect->replay_length; diEffect->dwDuration = effect->replay_length;
diEffect->dwStartDelay = effect->replay_delay; diEffect->dwStartDelay = effect->replay_delay;
#if (OIS_WIN32_JOYFF_DEBUG > 1) #if (OIS_WIN32_JOYFF_DEBUG > 1)
cout << " Replay :" << endl cout << " Replay :" << endl
<< " Length : " << effect->replay_length << " Length : " << effect->replay_length
<< " => " << diEffect->dwDuration << endl << " => " << diEffect->dwDuration << endl
<< " Delay : " << effect->replay_delay << " Delay : " << effect->replay_delay
<< " => " << diEffect->dwStartDelay << endl; << " => " << diEffect->dwStartDelay << endl;
#endif #endif
diEffect->cbTypeSpecificParams = struct_size; diEffect->cbTypeSpecificParams = struct_size;
diEffect->lpvTypeSpecificParams = struct_type; diEffect->lpvTypeSpecificParams = struct_type;
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::_upload( GUID guid, DIEFFECT* diEffect, const Effect* effect) void Win32ForceFeedback::_upload( GUID guid, DIEFFECT* diEffect, const Effect* effect)
{ {
LPDIRECTINPUTEFFECT dxEffect = 0; LPDIRECTINPUTEFFECT dxEffect = 0;
//Get the effect - if it exists //Get the effect - if it exists
EffectList::iterator i = mEffectList.find(effect->_handle); EffectList::iterator i = mEffectList.find(effect->_handle);
//It has been created already //It has been created already
if( i != mEffectList.end() ) if( i != mEffectList.end() )
dxEffect = i->second; dxEffect = i->second;
else //This effect has not yet been created - generate a handle else //This effect has not yet been created - generate a handle
effect->_handle = mHandles++; effect->_handle = mHandles++;
if( dxEffect == 0 ) if( dxEffect == 0 )
{ {
//This effect has not yet been created, so create it //This effect has not yet been created, so create it
HRESULT hr = mJoyStick->CreateEffect(guid, diEffect, &dxEffect, NULL); HRESULT hr = mJoyStick->CreateEffect(guid, diEffect, &dxEffect, NULL);
if(SUCCEEDED(hr)) if(SUCCEEDED(hr))
{ {
mEffectList[effect->_handle] = dxEffect; mEffectList[effect->_handle] = dxEffect;
dxEffect->Start(INFINITE,0); dxEffect->Start(INFINITE,0);
} }
else if( hr == DIERR_DEVICEFULL ) else if( hr == DIERR_DEVICEFULL )
OIS_EXCEPT(E_DeviceFull, "Remove an effect before adding more!"); OIS_EXCEPT(E_DeviceFull, "Remove an effect before adding more!");
else else
OIS_EXCEPT(E_General, "Unknown error creating effect->.."); OIS_EXCEPT(E_General, "Unknown error creating effect->..");
} }
else else
{ {
//ToDo -- Update the Effect //ToDo -- Update the Effect
HRESULT hr = dxEffect->SetParameters( diEffect, DIEP_DIRECTION | HRESULT hr = dxEffect->SetParameters( diEffect, DIEP_DIRECTION |
DIEP_DURATION | DIEP_ENVELOPE | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON | DIEP_DURATION | DIEP_ENVELOPE | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON |
DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_START ); DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_START );
if(FAILED(hr)) OIS_EXCEPT(E_InvalidParam, "Error updating device!"); if(FAILED(hr)) OIS_EXCEPT(E_InvalidParam, "Error updating device!");
} }
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::_addEffectSupport( LPCDIEFFECTINFO pdei ) void Win32ForceFeedback::_addEffectSupport( LPCDIEFFECTINFO pdei )
{ {
#if (OIS_WIN32_JOYFF_DEBUG > 0) #if (OIS_WIN32_JOYFF_DEBUG > 0)
// Dump some usefull information about the effect type. // Dump some usefull information about the effect type.
cout << "Adding support for '" << pdei->tszName << "' effect type" << endl; cout << "Adding support for '" << pdei->tszName << "' effect type" << endl;
cout << " Supported static params: "; cout << " Supported static params: ";
if (pdei->dwStaticParams & DIEP_AXES) cout << " Axes"; if (pdei->dwStaticParams & DIEP_AXES) cout << " Axes";
if (pdei->dwStaticParams & DIEP_DIRECTION) cout << " Direction"; if (pdei->dwStaticParams & DIEP_DIRECTION) cout << " Direction";
if (pdei->dwStaticParams & DIEP_DURATION) cout << " Duration"; if (pdei->dwStaticParams & DIEP_DURATION) cout << " Duration";
if (pdei->dwStaticParams & DIEP_ENVELOPE) cout << " Envelope"; if (pdei->dwStaticParams & DIEP_ENVELOPE) cout << " Envelope";
if (pdei->dwStaticParams & DIEP_GAIN) cout << " Gain"; if (pdei->dwStaticParams & DIEP_GAIN) cout << " Gain";
if (pdei->dwStaticParams & DIEP_SAMPLEPERIOD) cout << " SamplePeriod"; if (pdei->dwStaticParams & DIEP_SAMPLEPERIOD) cout << " SamplePeriod";
if (pdei->dwStaticParams & DIEP_STARTDELAY) cout << " StartDelay"; if (pdei->dwStaticParams & DIEP_STARTDELAY) cout << " StartDelay";
if (pdei->dwStaticParams & DIEP_TRIGGERBUTTON) cout << " TriggerButton"; if (pdei->dwStaticParams & DIEP_TRIGGERBUTTON) cout << " TriggerButton";
if (pdei->dwStaticParams & DIEP_TRIGGERREPEATINTERVAL) cout << " TriggerRepeatInterval"; if (pdei->dwStaticParams & DIEP_TRIGGERREPEATINTERVAL) cout << " TriggerRepeatInterval";
if (pdei->dwStaticParams & DIEP_TYPESPECIFICPARAMS) cout << " TypeSpecificParams"; if (pdei->dwStaticParams & DIEP_TYPESPECIFICPARAMS) cout << " TypeSpecificParams";
cout << endl; cout << endl;
cout << " Supported dynamic params: "; cout << " Supported dynamic params: ";
if (pdei->dwDynamicParams & DIEP_AXES) cout << " Axes"; if (pdei->dwDynamicParams & DIEP_AXES) cout << " Axes";
if (pdei->dwDynamicParams & DIEP_DIRECTION) cout << " Direction"; if (pdei->dwDynamicParams & DIEP_DIRECTION) cout << " Direction";
if (pdei->dwDynamicParams & DIEP_DURATION) cout << " Duration"; if (pdei->dwDynamicParams & DIEP_DURATION) cout << " Duration";
if (pdei->dwDynamicParams & DIEP_ENVELOPE) cout << " Envelope"; if (pdei->dwDynamicParams & DIEP_ENVELOPE) cout << " Envelope";
if (pdei->dwDynamicParams & DIEP_GAIN) cout << " Gain"; if (pdei->dwDynamicParams & DIEP_GAIN) cout << " Gain";
if (pdei->dwDynamicParams & DIEP_SAMPLEPERIOD) cout << " SamplePeriod"; if (pdei->dwDynamicParams & DIEP_SAMPLEPERIOD) cout << " SamplePeriod";
if (pdei->dwDynamicParams & DIEP_STARTDELAY) cout << " StartDelay"; if (pdei->dwDynamicParams & DIEP_STARTDELAY) cout << " StartDelay";
if (pdei->dwDynamicParams & DIEP_TRIGGERBUTTON) cout << " TriggerButton"; if (pdei->dwDynamicParams & DIEP_TRIGGERBUTTON) cout << " TriggerButton";
if (pdei->dwDynamicParams & DIEP_TRIGGERREPEATINTERVAL) cout << " TriggerRepeatInterval"; if (pdei->dwDynamicParams & DIEP_TRIGGERREPEATINTERVAL) cout << " TriggerRepeatInterval";
if (pdei->dwDynamicParams & DIEP_TYPESPECIFICPARAMS) cout << " TypeSpecificParams"; if (pdei->dwDynamicParams & DIEP_TYPESPECIFICPARAMS) cout << " TypeSpecificParams";
cout << endl; cout << endl;
cout << " More details about supported parameters support: "; cout << " More details about supported parameters support: ";
if (pdei->dwEffType & DIEFT_STARTDELAY) cout << " StartDelay"; if (pdei->dwEffType & DIEFT_STARTDELAY) cout << " StartDelay";
if (pdei->dwEffType & DIEFT_FFATTACK) cout << " Attack"; if (pdei->dwEffType & DIEFT_FFATTACK) cout << " Attack";
if (pdei->dwEffType & DIEFT_FFFADE) cout << " Fade"; if (pdei->dwEffType & DIEFT_FFFADE) cout << " Fade";
if (pdei->dwEffType & DIEFT_DEADBAND) cout << " DeadBand"; if (pdei->dwEffType & DIEFT_DEADBAND) cout << " DeadBand";
if (pdei->dwEffType & DIEFT_SATURATION) cout << " Saturation"; if (pdei->dwEffType & DIEFT_SATURATION) cout << " Saturation";
if (pdei->dwEffType & DIEFT_POSNEGSATURATION) cout << " PosNegaturation"; if (pdei->dwEffType & DIEFT_POSNEGSATURATION) cout << " PosNegaturation";
if (pdei->dwEffType & DIEFT_POSNEGCOEFFICIENTS) cout << " PosNegCoefficients"; if (pdei->dwEffType & DIEFT_POSNEGCOEFFICIENTS) cout << " PosNegCoefficients";
if (pdei->dwEffType & DIEFT_HARDWARE) cout << " HardwareSpecific"; if (pdei->dwEffType & DIEFT_HARDWARE) cout << " HardwareSpecific";
cout << endl; cout << endl;
#endif #endif
Effect::EForce eForce; Effect::EForce eForce;
switch (DIEFT_GETTYPE(pdei->dwEffType)) switch (DIEFT_GETTYPE(pdei->dwEffType))
{ {
case DIEFT_CONSTANTFORCE: case DIEFT_CONSTANTFORCE:
eForce = Effect::ConstantForce; eForce = Effect::ConstantForce;
break; break;
case DIEFT_RAMPFORCE: case DIEFT_RAMPFORCE:
eForce = Effect::RampForce; eForce = Effect::RampForce;
break; break;
case DIEFT_PERIODIC: case DIEFT_PERIODIC:
eForce = Effect::PeriodicForce; eForce = Effect::PeriodicForce;
break; break;
case DIEFT_CONDITION: case DIEFT_CONDITION:
eForce = Effect::ConditionalForce; eForce = Effect::ConditionalForce;
break; break;
case DIEFT_CUSTOMFORCE: case DIEFT_CUSTOMFORCE:
eForce = Effect::CustomForce; eForce = Effect::CustomForce;
break; break;
default: default:
eForce = Effect::UnknownForce; eForce = Effect::UnknownForce;
#if defined (_DEBUG) #if defined (_DEBUG)
cout << "Win32ForceFeedback: DirectInput8 Effect type support not implemented: " cout << "Win32ForceFeedback: DirectInput8 Effect type support not implemented: "
<< "DIEFT_GETTYPE="<< (int)DIEFT_GETTYPE(pdei->dwEffType) << endl; << "DIEFT_GETTYPE="<< (int)DIEFT_GETTYPE(pdei->dwEffType) << endl;
#endif #endif
return; return;
} }
//Determine what the effect type is and how it corresponds to our OIS's Enums //Determine what the effect type is and how it corresponds to our OIS's Enums
//We could save the GUIDs too, however, we will just use the predefined ones later //We could save the GUIDs too, however, we will just use the predefined ones later
if( pdei->guid == GUID_ConstantForce ) if( pdei->guid == GUID_ConstantForce )
_addEffectTypes(eForce, Effect::Constant ); _addEffectTypes(eForce, Effect::Constant );
else if( pdei->guid == GUID_Triangle ) else if( pdei->guid == GUID_Triangle )
_addEffectTypes(eForce, Effect::Triangle ); _addEffectTypes(eForce, Effect::Triangle );
else if( pdei->guid == GUID_Spring ) else if( pdei->guid == GUID_Spring )
_addEffectTypes(eForce, Effect::Spring ); _addEffectTypes(eForce, Effect::Spring );
else if( pdei->guid == GUID_Friction ) else if( pdei->guid == GUID_Friction )
_addEffectTypes(eForce, Effect::Friction ); _addEffectTypes(eForce, Effect::Friction );
else if( pdei->guid == GUID_Square ) else if( pdei->guid == GUID_Square )
_addEffectTypes(eForce, Effect::Square ); _addEffectTypes(eForce, Effect::Square );
else if( pdei->guid == GUID_Sine ) else if( pdei->guid == GUID_Sine )
_addEffectTypes(eForce, Effect::Sine ); _addEffectTypes(eForce, Effect::Sine );
else if( pdei->guid == GUID_SawtoothUp ) else if( pdei->guid == GUID_SawtoothUp )
_addEffectTypes(eForce, Effect::SawToothUp ); _addEffectTypes(eForce, Effect::SawToothUp );
else if( pdei->guid == GUID_SawtoothDown ) else if( pdei->guid == GUID_SawtoothDown )
_addEffectTypes(eForce, Effect::SawToothDown ); _addEffectTypes(eForce, Effect::SawToothDown );
else if( pdei->guid == GUID_Damper ) else if( pdei->guid == GUID_Damper )
_addEffectTypes(eForce, Effect::Damper ); _addEffectTypes(eForce, Effect::Damper );
else if( pdei->guid == GUID_Inertia ) else if( pdei->guid == GUID_Inertia )
_addEffectTypes(eForce, Effect::Inertia ); _addEffectTypes(eForce, Effect::Inertia );
else if( pdei->guid == GUID_CustomForce ) else if( pdei->guid == GUID_CustomForce )
_addEffectTypes(eForce, Effect::Custom ); _addEffectTypes(eForce, Effect::Custom );
else if( pdei->guid == GUID_RampForce ) else if( pdei->guid == GUID_RampForce )
_addEffectTypes(eForce, Effect::Ramp ); _addEffectTypes(eForce, Effect::Ramp );
#if defined (_DEBUG) #if defined (_DEBUG)
//Only care about this for Debugging Purposes //Only care about this for Debugging Purposes
//else //else
//{ //{
// std::ostringstream ss; // std::ostringstream ss;
// ss << "Win32ForceFeedback, DirectInput8 Effect not found. Reported as: " // ss << "Win32ForceFeedback, DirectInput8 Effect not found. Reported as: "
// << pdei->tszName; // << pdei->tszName;
// OIS_EXCEPT( E_General, ss.str().c_str()); // OIS_EXCEPT( E_General, ss.str().c_str());
//} //}
#endif #endif
} }
//--------------------------------------------------------------// //--------------------------------------------------------------//
void Win32ForceFeedback::_addFFAxis() void Win32ForceFeedback::_addFFAxis()
{ {
mFFAxes++; mFFAxes++;
} }
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "win32/Win32InputManager.h" #include "win32/Win32InputManager.h"
#include "win32/Win32KeyBoard.h" #include "win32/Win32KeyBoard.h"
#include "win32/Win32Mouse.h" #include "win32/Win32Mouse.h"
#include "win32/Win32JoyStick.h" #include "win32/Win32JoyStick.h"
#include "OISException.h" #include "OISException.h"
using namespace OIS; using namespace OIS;
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
Win32InputManager::Win32InputManager() : InputManager("Win32InputManager") Win32InputManager::Win32InputManager() : InputManager("Win32InputManager")
{ {
hWnd = 0; hWnd = 0;
mDirectInput = 0; mDirectInput = 0;
kbSettings = 0; kbSettings = 0;
mouseSettings = 0; mouseSettings = 0;
joySettings = 0; joySettings = 0;
joySticks = 0; joySticks = 0;
keyboardUsed = mouseUsed = false; keyboardUsed = mouseUsed = false;
//Setup our internal factories //Setup our internal factories
mFactories.push_back(this); mFactories.push_back(this);
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
Win32InputManager::~Win32InputManager() Win32InputManager::~Win32InputManager()
{ {
if( mDirectInput ) if( mDirectInput )
{ {
mDirectInput->Release(); mDirectInput->Release();
mDirectInput = 0; mDirectInput = 0;
} }
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
void Win32InputManager::_initialize( ParamList &paramList ) void Win32InputManager::_initialize( ParamList &paramList )
{ {
HINSTANCE hInst = 0; HINSTANCE hInst = 0;
HRESULT hr; HRESULT hr;
//First of all, get the Windows Handle and Instance //First of all, get the Windows Handle and Instance
ParamList::iterator i = paramList.find("WINDOW"); ParamList::iterator i = paramList.find("WINDOW");
if( i == paramList.end() ) if( i == paramList.end() )
OIS_EXCEPT( E_InvalidParam, "Win32InputManager::Win32InputManager >> No HWND found!" ); OIS_EXCEPT( E_InvalidParam, "Win32InputManager::Win32InputManager >> No HWND found!" );
// Get number as 64 bit and then convert. Handles the case of 32 or 64 bit HWND // Get number as 64 bit and then convert. Handles the case of 32 or 64 bit HWND
unsigned __int64 handle = _strtoui64(i->second.c_str(), 0, 10); unsigned __int64 handle = _strtoui64(i->second.c_str(), 0, 10);
hWnd = (HWND)handle; hWnd = (HWND)handle;
if( IsWindow(hWnd) == 0 ) if( IsWindow(hWnd) == 0 )
OIS_EXCEPT( E_General, "Win32InputManager::Win32InputManager >> The sent HWND is not valid!"); OIS_EXCEPT( E_General, "Win32InputManager::Win32InputManager >> The sent HWND is not valid!");
hInst = GetModuleHandle(0); hInst = GetModuleHandle(0);
//Create the device //Create the device
hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&mDirectInput, NULL ); hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&mDirectInput, NULL );
if (FAILED(hr)) if (FAILED(hr))
OIS_EXCEPT( E_General, "Win32InputManager::Win32InputManager >> Not able to init DirectX8 Input!"); OIS_EXCEPT( E_General, "Win32InputManager::Win32InputManager >> Not able to init DirectX8 Input!");
//Ok, now we have DirectInput, parse whatever extra settings were sent to us //Ok, now we have DirectInput, parse whatever extra settings were sent to us
_parseConfigSettings( paramList ); _parseConfigSettings( paramList );
// Enumerate devices ... // Enumerate devices ...
_enumerateDevices(); _enumerateDevices();
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
void Win32InputManager::_parseConfigSettings( ParamList &paramList ) void Win32InputManager::_parseConfigSettings( ParamList &paramList )
{ {
//Here we pick up settings such as a device's cooperation mode //Here we pick up settings such as a device's cooperation mode
std::map<std::string, DWORD> temp; std::map<std::string, DWORD> temp;
temp["DISCL_BACKGROUND"] = DISCL_BACKGROUND; temp["DISCL_BACKGROUND"] = DISCL_BACKGROUND;
temp["DISCL_EXCLUSIVE"] = DISCL_EXCLUSIVE; temp["DISCL_EXCLUSIVE"] = DISCL_EXCLUSIVE;
temp["DISCL_FOREGROUND"] = DISCL_FOREGROUND; temp["DISCL_FOREGROUND"] = DISCL_FOREGROUND;
temp["DISCL_NONEXCLUSIVE"] = DISCL_NONEXCLUSIVE; temp["DISCL_NONEXCLUSIVE"] = DISCL_NONEXCLUSIVE;
temp["DISCL_NOWINKEY"] = DISCL_NOWINKEY; temp["DISCL_NOWINKEY"] = DISCL_NOWINKEY;
//Check for pairs: ie. ("w32_keyboard","DISCL_NOWINKEY")("w32_keyboard","DISCL_FOREGROUND") //Check for pairs: ie. ("w32_keyboard","DISCL_NOWINKEY")("w32_keyboard","DISCL_FOREGROUND")
ParamList::iterator i = paramList.begin(), e = paramList.end(); ParamList::iterator i = paramList.begin(), e = paramList.end();
for( ; i != e; ++i ) for( ; i != e; ++i )
{ {
if( i->first == "w32_keyboard" ) if( i->first == "w32_keyboard" )
kbSettings |= temp[i->second]; kbSettings |= temp[i->second];
else if( i->first == "w32_mouse" ) else if( i->first == "w32_mouse" )
mouseSettings |= temp[i->second]; mouseSettings |= temp[i->second];
else if( i->first == "w32_joystick" ) else if( i->first == "w32_joystick" )
joySettings |= temp[i->second]; joySettings |= temp[i->second];
} }
if( kbSettings == 0 ) kbSettings = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY; if( kbSettings == 0 ) kbSettings = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY;
if( mouseSettings == 0 ) mouseSettings = DISCL_FOREGROUND | DISCL_EXCLUSIVE; if( mouseSettings == 0 ) mouseSettings = DISCL_FOREGROUND | DISCL_EXCLUSIVE;
if( joySettings == 0 ) joySettings = DISCL_FOREGROUND | DISCL_EXCLUSIVE; if( joySettings == 0 ) joySettings = DISCL_FOREGROUND | DISCL_EXCLUSIVE;
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
void Win32InputManager::_enumerateDevices() void Win32InputManager::_enumerateDevices()
{ {
//Enumerate all attached devices //Enumerate all attached devices
mDirectInput->EnumDevices(NULL, _DIEnumDevCallback, this, DIEDFL_ATTACHEDONLY); mDirectInput->EnumDevices(NULL, _DIEnumDevCallback, this, DIEDFL_ATTACHEDONLY);
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
//let's check how many possible XInput devices we may have (max 4)... //let's check how many possible XInput devices we may have (max 4)...
for(int i = 0; i < 3; ++i) for(int i = 0; i < 3; ++i)
{ {
XINPUT_STATE state; XINPUT_STATE state;
if(XInputGetState(i, &state) != ERROR_DEVICE_NOT_CONNECTED) if(XInputGetState(i, &state) != ERROR_DEVICE_NOT_CONNECTED)
{ //Once we found 1, just check our whole list against devices { //Once we found 1, just check our whole list against devices
Win32JoyStick::CheckXInputDevices(unusedJoyStickList); Win32JoyStick::CheckXInputDevices(unusedJoyStickList);
break; break;
} }
} }
#endif #endif
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
BOOL CALLBACK Win32InputManager::_DIEnumDevCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) BOOL CALLBACK Win32InputManager::_DIEnumDevCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
{ {
Win32InputManager *_this_ = static_cast<Win32InputManager*>(pvRef); Win32InputManager *_this_ = static_cast<Win32InputManager*>(pvRef);
// Register only game devices (keyboard and mouse are managed differently). // Register only game devices (keyboard and mouse are managed differently).
if( GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_JOYSTICK || if( GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_JOYSTICK ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_GAMEPAD || GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_GAMEPAD ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_1STPERSON || GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_1STPERSON ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_DRIVING || GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_DRIVING ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_FLIGHT || GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_FLIGHT ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_SUPPLEMENTAL) GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_SUPPLEMENTAL)
{ {
JoyStickInfo jsInfo; JoyStickInfo jsInfo;
jsInfo.isXInput = false; jsInfo.isXInput = false;
jsInfo.productGuid = lpddi->guidProduct; jsInfo.productGuid = lpddi->guidProduct;
jsInfo.deviceID = lpddi->guidInstance; jsInfo.deviceID = lpddi->guidInstance;
jsInfo.vendor = lpddi->tszInstanceName; jsInfo.vendor = lpddi->tszInstanceName;
jsInfo.devId = _this_->joySticks; jsInfo.devId = _this_->joySticks;
_this_->joySticks++; _this_->joySticks++;
_this_->unusedJoyStickList.push_back( jsInfo ); _this_->unusedJoyStickList.push_back( jsInfo );
} }
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
void Win32InputManager::_returnJoyStick(const JoyStickInfo& joystick) void Win32InputManager::_returnJoyStick(const JoyStickInfo& joystick)
{ {
unusedJoyStickList.push_back(joystick); unusedJoyStickList.push_back(joystick);
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
DeviceList Win32InputManager::freeDeviceList() DeviceList Win32InputManager::freeDeviceList()
{ {
DeviceList ret; DeviceList ret;
if( keyboardUsed == false ) if( keyboardUsed == false )
ret.insert(std::make_pair(OISKeyboard, mInputSystemName)); ret.insert(std::make_pair(OISKeyboard, mInputSystemName));
if( mouseUsed == false ) if( mouseUsed == false )
ret.insert(std::make_pair(OISMouse, mInputSystemName)); ret.insert(std::make_pair(OISMouse, mInputSystemName));
for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i) for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i)
ret.insert(std::make_pair(OISJoyStick, i->vendor)); ret.insert(std::make_pair(OISJoyStick, i->vendor));
return ret; return ret;
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
int Win32InputManager::totalDevices(Type iType) int Win32InputManager::totalDevices(Type iType)
{ {
switch(iType) switch(iType)
{ {
case OISKeyboard: return 1; case OISKeyboard: return 1;
case OISMouse: return 1; case OISMouse: return 1;
case OISJoyStick: return joySticks; case OISJoyStick: return joySticks;
default: return 0; default: return 0;
} }
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
int Win32InputManager::freeDevices(Type iType) int Win32InputManager::freeDevices(Type iType)
{ {
switch(iType) switch(iType)
{ {
case OISKeyboard: return keyboardUsed ? 0 : 1; case OISKeyboard: return keyboardUsed ? 0 : 1;
case OISMouse: return mouseUsed ? 0 : 1; case OISMouse: return mouseUsed ? 0 : 1;
case OISJoyStick: return (int)unusedJoyStickList.size(); case OISJoyStick: return (int)unusedJoyStickList.size();
default: return 0; default: return 0;
} }
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
bool Win32InputManager::vendorExist(Type iType, const std::string & vendor) bool Win32InputManager::vendorExist(Type iType, const std::string & vendor)
{ {
if( (iType == OISKeyboard || iType == OISMouse) && vendor == mInputSystemName ) if( (iType == OISKeyboard || iType == OISMouse) && vendor == mInputSystemName )
{ {
return true; return true;
} }
else if( iType == OISJoyStick ) else if( iType == OISJoyStick )
{ {
for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i) for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i)
if(i->vendor == vendor) if(i->vendor == vendor)
return true; return true;
} }
return false; return false;
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
Object* Win32InputManager::createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor) Object* Win32InputManager::createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor)
{ {
Object *obj = 0; OIS_UNUSED(creator);
switch(iType) Object *obj = 0;
{
case OISKeyboard: switch(iType)
{ {
if( keyboardUsed == false ) case OISKeyboard:
obj = new Win32Keyboard(this, mDirectInput, bufferMode, kbSettings); {
break; if( keyboardUsed == false )
} obj = new Win32Keyboard(this, mDirectInput, bufferMode, kbSettings);
case OISMouse: break;
{ }
if( mouseUsed == false ) case OISMouse:
obj = new Win32Mouse(this, mDirectInput, bufferMode, mouseSettings); {
break; if( mouseUsed == false )
} obj = new Win32Mouse(this, mDirectInput, bufferMode, mouseSettings);
case OISJoyStick: break;
{ }
for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i) case OISJoyStick:
{ {
if(vendor == "" || i->vendor == vendor) for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i)
{ {
obj = new Win32JoyStick(this, mDirectInput, bufferMode, joySettings, *i); if(vendor == "" || i->vendor == vendor)
unusedJoyStickList.erase(i); {
break; obj = new Win32JoyStick(this, mDirectInput, bufferMode, joySettings, *i);
} unusedJoyStickList.erase(i);
} break;
break; }
} }
default: break;
break; }
} default:
break;
if( obj == 0 ) }
OIS_EXCEPT(E_InputDeviceNonExistant, "No devices match requested type.");
if( obj == 0 )
return obj; OIS_EXCEPT(E_InputDeviceNonExistant, "No devices match requested type.");
}
return obj;
//----------------------------------------------------------------------------// }
void Win32InputManager::destroyObject(Object* obj)
{ //----------------------------------------------------------------------------//
delete obj; void Win32InputManager::destroyObject(Object* obj)
} {
delete obj;
}
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "win32/Win32JoyStick.h" #include "win32/Win32JoyStick.h"
#include "win32/Win32InputManager.h" #include "win32/Win32InputManager.h"
#include "win32/Win32ForceFeedback.h" #include "win32/Win32ForceFeedback.h"
#include "OISEvents.h" #include "OISEvents.h"
#include "OISException.h" #include "OISException.h"
#include <cassert> #include <cassert>
// Only if xinput support is enabled // Only if xinput support is enabled
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
#include <wbemidl.h> #include <wbemidl.h>
#include <oleauto.h> #include <oleauto.h>
//#include <wmsstd.h> //#include <wmsstd.h>
#ifndef SAFE_RELEASE #ifndef SAFE_RELEASE
#define SAFE_RELEASE(x) \ #define SAFE_RELEASE(x) \
if(x != NULL) \ if(x != NULL) \
{ \ { \
x->Release(); \ x->Release(); \
x = NULL; \ x = NULL; \
} }
#endif #endif
#pragma comment(lib, "xinput.lib") #pragma comment(lib, "xinput.lib")
#endif #endif
//DX Only defines macros for the JOYSTICK not JOYSTICK2, so fix it //DX Only defines macros for the JOYSTICK not JOYSTICK2, so fix it
#undef DIJOFS_BUTTON #undef DIJOFS_BUTTON
#undef DIJOFS_POV #undef DIJOFS_POV
#define DIJOFS_BUTTON(n) (FIELD_OFFSET(DIJOYSTATE2, rgbButtons) + (n)) #define DIJOFS_BUTTON(n) (FIELD_OFFSET(DIJOYSTATE2, rgbButtons) + (n))
#define DIJOFS_POV(n) (FIELD_OFFSET(DIJOYSTATE2, rgdwPOV)+(n)*sizeof(DWORD)) #define DIJOFS_POV(n) (FIELD_OFFSET(DIJOYSTATE2, rgdwPOV)+(n)*sizeof(DWORD))
#define DIJOFS_SLIDER0(n) (FIELD_OFFSET(DIJOYSTATE2, rglSlider)+(n) * sizeof(LONG)) #define DIJOFS_SLIDER0(n) (FIELD_OFFSET(DIJOYSTATE2, rglSlider)+(n) * sizeof(LONG))
#define DIJOFS_SLIDER1(n) (FIELD_OFFSET(DIJOYSTATE2, rglVSlider)+(n) * sizeof(LONG)) #define DIJOFS_SLIDER1(n) (FIELD_OFFSET(DIJOYSTATE2, rglVSlider)+(n) * sizeof(LONG))
#define DIJOFS_SLIDER2(n) (FIELD_OFFSET(DIJOYSTATE2, rglASlider)+(n) * sizeof(LONG)) #define DIJOFS_SLIDER2(n) (FIELD_OFFSET(DIJOYSTATE2, rglASlider)+(n) * sizeof(LONG))
#define DIJOFS_SLIDER3(n) (FIELD_OFFSET(DIJOYSTATE2, rglFSlider)+(n) * sizeof(LONG)) #define DIJOFS_SLIDER3(n) (FIELD_OFFSET(DIJOYSTATE2, rglFSlider)+(n) * sizeof(LONG))
#define XINPUT_TRANSLATED_BUTTON_COUNT 12 #define XINPUT_TRANSLATED_BUTTON_COUNT 12
#define XINPUT_TRANSLATED_AXIS_COUNT 6 #define XINPUT_TRANSLATED_AXIS_COUNT 6
using namespace OIS; using namespace OIS;
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32JoyStick::Win32JoyStick( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings, const JoyStickInfo &info ) : Win32JoyStick::Win32JoyStick( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings, const JoyStickInfo &info ) :
JoyStick(info.vendor, buffered, info.devId, creator), JoyStick(info.vendor, buffered, info.devId, creator),
mDirectInput(pDI), mDirectInput(pDI),
coopSetting(coopSettings), coopSetting(coopSettings),
mJoyStick(0), mJoyStick(0),
mJoyInfo(info), mJoyInfo(info),
mFfDevice(0) mFfDevice(0)
{ {
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32JoyStick::~Win32JoyStick() Win32JoyStick::~Win32JoyStick()
{ {
delete mFfDevice; delete mFfDevice;
if(mJoyStick) if(mJoyStick)
{ {
mJoyStick->Unacquire(); mJoyStick->Unacquire();
mJoyStick->Release(); mJoyStick->Release();
mJoyStick = 0; mJoyStick = 0;
} }
//Return joystick to pool //Return joystick to pool
static_cast<Win32InputManager*>(mCreator)->_returnJoyStick(mJoyInfo); static_cast<Win32InputManager*>(mCreator)->_returnJoyStick(mJoyInfo);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::_initialize() void Win32JoyStick::_initialize()
{ {
if (mJoyInfo.isXInput) if (mJoyInfo.isXInput)
{ {
_enumerate(); _enumerate();
} }
else else
{ {
//Clear old state //Clear old state
mState.mAxes.clear(); mState.mAxes.clear();
delete mFfDevice; delete mFfDevice;
mFfDevice = 0; mFfDevice = 0;
DIPROPDWORD dipdw; DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0; dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE; dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = JOYSTICK_DX_BUFFERSIZE; dipdw.dwData = JOYSTICK_DX_BUFFERSIZE;
if(FAILED(mDirectInput->CreateDevice(mJoyInfo.deviceID, &mJoyStick, NULL))) if(FAILED(mDirectInput->CreateDevice(mJoyInfo.deviceID, &mJoyStick, NULL)))
OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> Could not initialize joy device!"); OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> Could not initialize joy device!");
if(FAILED(mJoyStick->SetDataFormat(&c_dfDIJoystick2))) if(FAILED(mJoyStick->SetDataFormat(&c_dfDIJoystick2)))
OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> data format error!"); OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> data format error!");
HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle(); HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
if(FAILED(mJoyStick->SetCooperativeLevel( hwin, coopSetting))) if(FAILED(mJoyStick->SetCooperativeLevel( hwin, coopSetting)))
OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> failed to set cooperation level!"); OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> failed to set cooperation level!");
if( FAILED(mJoyStick->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)) ) if( FAILED(mJoyStick->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set buffer size property" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set buffer size property" );
//Enumerate all axes/buttons/sliders/etc before aquiring //Enumerate all axes/buttons/sliders/etc before aquiring
_enumerate(); _enumerate();
mState.clear(); mState.clear();
capture(); capture();
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::_enumerate() void Win32JoyStick::_enumerate()
{ {
if (mJoyInfo.isXInput) if (mJoyInfo.isXInput)
{ {
mPOVs = 1; mPOVs = 1;
mState.mButtons.resize(XINPUT_TRANSLATED_BUTTON_COUNT); mState.mButtons.resize(XINPUT_TRANSLATED_BUTTON_COUNT);
mState.mAxes.resize(XINPUT_TRANSLATED_AXIS_COUNT); mState.mAxes.resize(XINPUT_TRANSLATED_AXIS_COUNT);
} }
else else
{ {
// Get joystick capabilities. // Get joystick capabilities.
mDIJoyCaps.dwSize = sizeof(DIDEVCAPS); mDIJoyCaps.dwSize = sizeof(DIDEVCAPS);
if( FAILED(mJoyStick->GetCapabilities(&mDIJoyCaps)) ) if( FAILED(mJoyStick->GetCapabilities(&mDIJoyCaps)) )
OIS_EXCEPT( E_General, "Win32JoyStick::_enumerate >> Failed to get capabilities" ); OIS_EXCEPT( E_General, "Win32JoyStick::_enumerate >> Failed to get capabilities" );
mPOVs = (short)mDIJoyCaps.dwPOVs; mPOVs = (short)mDIJoyCaps.dwPOVs;
mState.mButtons.resize(mDIJoyCaps.dwButtons); mState.mButtons.resize(mDIJoyCaps.dwButtons);
mState.mAxes.resize(mDIJoyCaps.dwAxes); mState.mAxes.resize(mDIJoyCaps.dwAxes);
//Reset the axis mapping enumeration value //Reset the axis mapping enumeration value
_AxisNumber = 0; _AxisNumber = 0;
//Enumerate Force Feedback (if any) //Enumerate Force Feedback (if any)
mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL); mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL);
//Enumerate and set axis constraints (and check FF Axes) //Enumerate and set axis constraints (and check FF Axes)
mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS); mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS);
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
BOOL CALLBACK Win32JoyStick::DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) BOOL CALLBACK Win32JoyStick::DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
{ {
Win32JoyStick* _this = (Win32JoyStick*)pvRef; Win32JoyStick* _this = (Win32JoyStick*)pvRef;
//Setup mappings //Setup mappings
DIPROPPOINTER diptr; DIPROPPOINTER diptr;
diptr.diph.dwSize = sizeof(DIPROPPOINTER); diptr.diph.dwSize = sizeof(DIPROPPOINTER);
diptr.diph.dwHeaderSize = sizeof(DIPROPHEADER); diptr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diptr.diph.dwHow = DIPH_BYID; diptr.diph.dwHow = DIPH_BYID;
diptr.diph.dwObj = lpddoi->dwType; diptr.diph.dwObj = lpddoi->dwType;
//Add a magic number to recognise we set seomthing //Add a magic number to recognise we set seomthing
diptr.uData = 0x13130000 | _this->_AxisNumber; diptr.uData = 0x13130000 | _this->_AxisNumber;
//Check if axis is slider, if so, do not treat as regular axis //Check if axis is slider, if so, do not treat as regular axis
if(GUID_Slider == lpddoi->guidType) if(GUID_Slider == lpddoi->guidType)
{ {
++_this->mSliders; ++_this->mSliders;
//Decrease Axes, since this slider shows up in a different place //Decrease Axes, since this slider shows up in a different place
_this->mState.mAxes.pop_back(); _this->mState.mAxes.pop_back();
} }
else if (FAILED(_this->mJoyStick->SetProperty(DIPROP_APPDATA, &diptr.diph))) else if (FAILED(_this->mJoyStick->SetProperty(DIPROP_APPDATA, &diptr.diph)))
{ //If for some reason we could not set needed user data, just ignore this axis { //If for some reason we could not set needed user data, just ignore this axis
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
//Increase for next time through //Increase for next time through
if(GUID_Slider != lpddoi->guidType) if(GUID_Slider != lpddoi->guidType)
_this->_AxisNumber += 1; _this->_AxisNumber += 1;
//Set range //Set range
DIPROPRANGE diprg; DIPROPRANGE diprg;
diprg.diph.dwSize = sizeof(DIPROPRANGE); diprg.diph.dwSize = sizeof(DIPROPRANGE);
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diprg.diph.dwHow = DIPH_BYID; diprg.diph.dwHow = DIPH_BYID;
diprg.diph.dwObj = lpddoi->dwType; diprg.diph.dwObj = lpddoi->dwType;
diprg.lMin = MIN_AXIS; diprg.lMin = MIN_AXIS;
diprg.lMax = MAX_AXIS; diprg.lMax = MAX_AXIS;
if (FAILED(_this->mJoyStick->SetProperty(DIPROP_RANGE, &diprg.diph))) if (FAILED(_this->mJoyStick->SetProperty(DIPROP_RANGE, &diprg.diph)))
OIS_EXCEPT( E_General, "Win32JoyStick::_DIEnumDeviceObjectsCallback >> Failed to set min/max range property" ); OIS_EXCEPT( E_General, "Win32JoyStick::_DIEnumDeviceObjectsCallback >> Failed to set min/max range property" );
//Check if FF Axes, and if so, increment counter //Check if FF Axes, and if so, increment counter
if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 ) if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 )
{ {
if( _this->mFfDevice ) if( _this->mFfDevice )
{ {
_this->mFfDevice->_addFFAxis(); _this->mFfDevice->_addFFAxis();
} }
} }
//Force the flags for gain and auto-center support to true, //Force the flags for gain and auto-center support to true,
//as DInput has no API to query the device for these capabilities //as DInput has no API to query the device for these capabilities
//(the only way to know is to try them ...) //(the only way to know is to try them ...)
if( _this->mFfDevice ) if( _this->mFfDevice )
{ {
_this->mFfDevice->_setGainSupport(true); _this->mFfDevice->_setGainSupport(true);
_this->mFfDevice->_setAutoCenterSupport(true); _this->mFfDevice->_setAutoCenterSupport(true);
} }
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
BOOL CALLBACK Win32JoyStick::DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef) BOOL CALLBACK Win32JoyStick::DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef)
{ {
Win32JoyStick* _this = (Win32JoyStick*)pvRef; Win32JoyStick* _this = (Win32JoyStick*)pvRef;
//Create the FF instance only after we know there is at least one effect type //Create the FF instance only after we know there is at least one effect type
if( _this->mFfDevice == 0 ) if( _this->mFfDevice == 0 )
_this->mFfDevice = new Win32ForceFeedback(_this->mJoyStick, &_this->mDIJoyCaps); _this->mFfDevice = new Win32ForceFeedback(_this->mJoyStick, &_this->mDIJoyCaps);
_this->mFfDevice->_addEffectSupport(pdei); _this->mFfDevice->_addEffectSupport(pdei);
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::capture() void Win32JoyStick::capture()
{ {
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
//handle xbox controller differently //handle xbox controller differently
if (mJoyInfo.isXInput) if (mJoyInfo.isXInput)
{ {
captureXInput(); captureXInput();
return; return;
} }
#endif #endif
//handle directinput based devices //handle directinput based devices
DIDEVICEOBJECTDATA diBuff[JOYSTICK_DX_BUFFERSIZE]; DIDEVICEOBJECTDATA diBuff[JOYSTICK_DX_BUFFERSIZE];
DWORD entries = JOYSTICK_DX_BUFFERSIZE; DWORD entries = JOYSTICK_DX_BUFFERSIZE;
// Poll the device to read the current state // Poll the device to read the current state
HRESULT hr = mJoyStick->Poll(); HRESULT hr = mJoyStick->Poll();
if( hr == DI_OK ) if( hr == DI_OK )
hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
if( hr != DI_OK ) if( hr != DI_OK )
{ {
hr = mJoyStick->Acquire(); hr = mJoyStick->Acquire();
while( hr == DIERR_INPUTLOST ) while( hr == DIERR_INPUTLOST )
hr = mJoyStick->Acquire(); hr = mJoyStick->Acquire();
// Poll the device to read the current state // Poll the device to read the current state
mJoyStick->Poll(); mJoyStick->Poll();
hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
//Perhaps the user just tabbed away //Perhaps the user just tabbed away
if( FAILED(hr) ) if( FAILED(hr) )
return; return;
} }
bool axisMoved[24] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false, bool axisMoved[24] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false}; false,false,false,false,false,false,false,false};
bool sliderMoved[4] = {false,false,false,false}; bool sliderMoved[4] = {false,false,false,false};
//Loop through all the events //Loop through all the events
for(unsigned int i = 0; i < entries; ++i) for(unsigned int i = 0; i < entries; ++i)
{ {
//This may seem outof order, but is in order of the way these variables //This may seem outof order, but is in order of the way these variables
//are declared in the JoyStick State 2 structure. //are declared in the JoyStick State 2 structure.
switch(diBuff[i].dwOfs) switch(diBuff[i].dwOfs)
{ {
//------ slider -// //------ slider -//
case DIJOFS_SLIDER0(0): case DIJOFS_SLIDER0(0):
sliderMoved[0] = true; sliderMoved[0] = true;
mState.mSliders[0].abX = diBuff[i].dwData; mState.mSliders[0].abX = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER0(1): case DIJOFS_SLIDER0(1):
sliderMoved[0] = true; sliderMoved[0] = true;
mState.mSliders[0].abY = diBuff[i].dwData; mState.mSliders[0].abY = diBuff[i].dwData;
break; break;
//----- Max 4 POVs Next ---------------// //----- Max 4 POVs Next ---------------//
case DIJOFS_POV(0): case DIJOFS_POV(0):
if(!_changePOV(0,diBuff[i])) if(!_changePOV(0,diBuff[i]))
return; return;
break; break;
case DIJOFS_POV(1): case DIJOFS_POV(1):
if(!_changePOV(1,diBuff[i])) if(!_changePOV(1,diBuff[i]))
return; return;
break; break;
case DIJOFS_POV(2): case DIJOFS_POV(2):
if(!_changePOV(2,diBuff[i])) if(!_changePOV(2,diBuff[i]))
return; return;
break; break;
case DIJOFS_POV(3): case DIJOFS_POV(3):
if(!_changePOV(3,diBuff[i])) if(!_changePOV(3,diBuff[i]))
return; return;
break; break;
case DIJOFS_SLIDER1(0): case DIJOFS_SLIDER1(0):
sliderMoved[1] = true; sliderMoved[1] = true;
mState.mSliders[1].abX = diBuff[i].dwData; mState.mSliders[1].abX = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER1(1): case DIJOFS_SLIDER1(1):
sliderMoved[1] = true; sliderMoved[1] = true;
mState.mSliders[1].abY = diBuff[i].dwData; mState.mSliders[1].abY = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER2(0): case DIJOFS_SLIDER2(0):
sliderMoved[2] = true; sliderMoved[2] = true;
mState.mSliders[2].abX = diBuff[i].dwData; mState.mSliders[2].abX = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER2(1): case DIJOFS_SLIDER2(1):
sliderMoved[2] = true; sliderMoved[2] = true;
mState.mSliders[2].abY = diBuff[i].dwData; mState.mSliders[2].abY = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER3(0): case DIJOFS_SLIDER3(0):
sliderMoved[3] = true; sliderMoved[3] = true;
mState.mSliders[3].abX = diBuff[i].dwData; mState.mSliders[3].abX = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER3(1): case DIJOFS_SLIDER3(1):
sliderMoved[3] = true; sliderMoved[3] = true;
mState.mSliders[3].abY = diBuff[i].dwData; mState.mSliders[3].abY = diBuff[i].dwData;
break; break;
//-----------------------------------------// //-----------------------------------------//
default: default:
//Handle Button Events Easily using the DX Offset Macros //Handle Button Events Easily using the DX Offset Macros
if( diBuff[i].dwOfs >= DIJOFS_BUTTON(0) && diBuff[i].dwOfs < DIJOFS_BUTTON(128) ) if( diBuff[i].dwOfs >= DIJOFS_BUTTON(0) && diBuff[i].dwOfs < DIJOFS_BUTTON(128) )
{ {
if(!_doButtonClick((diBuff[i].dwOfs - DIJOFS_BUTTON(0)), diBuff[i])) if(!_doButtonClick((diBuff[i].dwOfs - DIJOFS_BUTTON(0)), diBuff[i]))
return; return;
} }
else if((short)(diBuff[i].uAppData >> 16) == 0x1313) else if((short)(diBuff[i].uAppData >> 16) == 0x1313)
{ //If it was nothing else, might be axis enumerated earlier (determined by magic number) { //If it was nothing else, might be axis enumerated earlier (determined by magic number)
int axis = (int)(0x0000FFFF & diBuff[i].uAppData); //Mask out the high bit int axis = (int)(0x0000FFFF & diBuff[i].uAppData); //Mask out the high bit
assert( axis >= 0 && axis < (int)mState.mAxes.size() && "Axis out of range!"); assert( axis >= 0 && axis < (int)mState.mAxes.size() && "Axis out of range!");
if(axis >= 0 && axis < (int)mState.mAxes.size()) if(axis >= 0 && axis < (int)mState.mAxes.size())
{ {
mState.mAxes[axis].abs = diBuff[i].dwData; mState.mAxes[axis].abs = diBuff[i].dwData;
axisMoved[axis] = true; axisMoved[axis] = true;
} }
} }
break; break;
} //end case } //end case
} //end for } //end for
//Check to see if any of the axes values have changed.. if so send events //Check to see if any of the axes values have changed.. if so send events
if( mBuffered && mListener && entries > 0 ) if( mBuffered && mListener && entries > 0 )
{ {
JoyStickEvent temp(this, mState); JoyStickEvent temp(this, mState);
//Update axes //Update axes
for( int i = 0; i < 24; ++i ) for( int i = 0; i < 24; ++i )
if( axisMoved[i] ) if( axisMoved[i] )
if( mListener->axisMoved( temp, i ) == false ) if( mListener->axisMoved( temp, i ) == false )
return; return;
//Now update sliders //Now update sliders
for( int i = 0; i < 4; ++i ) for( int i = 0; i < 4; ++i )
if( sliderMoved[i] ) if( sliderMoved[i] )
if( mListener->sliderMoved( temp, i ) == false ) if( mListener->sliderMoved( temp, i ) == false )
return; return;
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::captureXInput() void Win32JoyStick::captureXInput()
{ {
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
XINPUT_STATE inputState; XINPUT_STATE inputState;
if (XInputGetState((DWORD)mJoyInfo.xInputDev, &inputState) != ERROR_SUCCESS) if (XInputGetState((DWORD)mJoyInfo.xInputDev, &inputState) != ERROR_SUCCESS)
memset(&inputState, 0, sizeof(inputState)); memset(&inputState, 0, sizeof(inputState));
//Sticks and triggers //Sticks and triggers
int value; int value;
bool axisMoved[XINPUT_TRANSLATED_AXIS_COUNT] = {false,false,false,false,false,false}; bool axisMoved[XINPUT_TRANSLATED_AXIS_COUNT] = {false,false,false,false,false,false};
//LeftY //LeftY
value = -(int)inputState.Gamepad.sThumbLY; value = -(int)inputState.Gamepad.sThumbLY;
mState.mAxes[0].rel = value - mState.mAxes[0].abs; mState.mAxes[0].rel = value - mState.mAxes[0].abs;
mState.mAxes[0].abs = value; mState.mAxes[0].abs = value;
if(mState.mAxes[0].rel != 0) if(mState.mAxes[0].rel != 0)
axisMoved[0] = true; axisMoved[0] = true;
//LeftX //LeftX
mState.mAxes[1].rel = inputState.Gamepad.sThumbLX - mState.mAxes[1].abs; mState.mAxes[1].rel = inputState.Gamepad.sThumbLX - mState.mAxes[1].abs;
mState.mAxes[1].abs = inputState.Gamepad.sThumbLX; mState.mAxes[1].abs = inputState.Gamepad.sThumbLX;
if(mState.mAxes[1].rel != 0) if(mState.mAxes[1].rel != 0)
axisMoved[1] = true; axisMoved[1] = true;
//RightY //RightY
value = -(int)inputState.Gamepad.sThumbRY; value = -(int)inputState.Gamepad.sThumbRY;
mState.mAxes[2].rel = value - mState.mAxes[2].abs; mState.mAxes[2].rel = value - mState.mAxes[2].abs;
mState.mAxes[2].abs = value; mState.mAxes[2].abs = value;
if(mState.mAxes[2].rel != 0) if(mState.mAxes[2].rel != 0)
axisMoved[2] = true; axisMoved[2] = true;
//RightX //RightX
mState.mAxes[3].rel = inputState.Gamepad.sThumbRX - mState.mAxes[3].abs; mState.mAxes[3].rel = inputState.Gamepad.sThumbRX - mState.mAxes[3].abs;
mState.mAxes[3].abs = inputState.Gamepad.sThumbRX; mState.mAxes[3].abs = inputState.Gamepad.sThumbRX;
if(mState.mAxes[3].rel != 0) if(mState.mAxes[3].rel != 0)
axisMoved[3] = true; axisMoved[3] = true;
//Left trigger //Left trigger
value = inputState.Gamepad.bLeftTrigger * 129; value = inputState.Gamepad.bLeftTrigger * 129;
if(value > JoyStick::MAX_AXIS) if(value > JoyStick::MAX_AXIS)
value = JoyStick::MAX_AXIS; value = JoyStick::MAX_AXIS;
mState.mAxes[4].rel = value - mState.mAxes[4].abs; mState.mAxes[4].rel = value - mState.mAxes[4].abs;
mState.mAxes[4].abs = value; mState.mAxes[4].abs = value;
if(mState.mAxes[4].rel != 0) if(mState.mAxes[4].rel != 0)
axisMoved[4] = true; axisMoved[4] = true;
//Right trigger //Right trigger
value = (int)inputState.Gamepad.bRightTrigger * 129; value = (int)inputState.Gamepad.bRightTrigger * 129;
if(value > JoyStick::MAX_AXIS) if(value > JoyStick::MAX_AXIS)
value = JoyStick::MAX_AXIS; value = JoyStick::MAX_AXIS;
mState.mAxes[5].rel = value - mState.mAxes[5].abs; mState.mAxes[5].rel = value - mState.mAxes[5].abs;
mState.mAxes[5].abs = value; mState.mAxes[5].abs = value;
if(mState.mAxes[5].rel != 0) if(mState.mAxes[5].rel != 0)
axisMoved[5] = true; axisMoved[5] = true;
//POV //POV
int previousPov = mState.mPOV[0].direction; int previousPov = mState.mPOV[0].direction;
int& pov = mState.mPOV[0].direction; int& pov = mState.mPOV[0].direction;
pov = Pov::Centered; pov = Pov::Centered;
if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
pov |= Pov::North; pov |= Pov::North;
else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
pov |= Pov::South; pov |= Pov::South;
if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
pov |= Pov::West; pov |= Pov::West;
else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
pov |= Pov::East; pov |= Pov::East;
//Buttons - The first 4 buttons don't need to be checked since they represent the dpad //Buttons - The first 4 buttons don't need to be checked since they represent the dpad
bool previousButtons[XINPUT_TRANSLATED_BUTTON_COUNT]; bool previousButtons[XINPUT_TRANSLATED_BUTTON_COUNT];
std::copy(mState.mButtons.begin(), mState.mButtons.end(), previousButtons); std::copy(mState.mButtons.begin(), mState.mButtons.end(), previousButtons);
for (size_t i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++) for (size_t i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++)
mState.mButtons[i] = (inputState.Gamepad.wButtons & (1 << (i + 4))) != 0; mState.mButtons[i] = (inputState.Gamepad.wButtons & (1 << (i + 4))) != 0;
//Send events //Send events
if (mBuffered && mListener) if (mBuffered && mListener)
{ {
JoyStickEvent joystickEvent(this, mState); JoyStickEvent joystickEvent(this, mState);
//Axes //Axes
for (int i = 0; i < XINPUT_TRANSLATED_AXIS_COUNT; i++) for (int i = 0; i < XINPUT_TRANSLATED_AXIS_COUNT; i++)
{ {
if (axisMoved[i] && !mListener->axisMoved(joystickEvent, i)) if (axisMoved[i] && !mListener->axisMoved(joystickEvent, i))
return; return;
} }
//POV //POV
if (previousPov != pov && !mListener->povMoved(joystickEvent, 0)) if (previousPov != pov && !mListener->povMoved(joystickEvent, 0))
return; return;
//Buttons //Buttons
for (int i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++) for (int i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++)
{ {
if (!previousButtons[i] && mState.mButtons[i]) if (!previousButtons[i] && mState.mButtons[i])
{ {
if (!mListener->buttonPressed(joystickEvent, i)) if (!mListener->buttonPressed(joystickEvent, i))
return; return;
} }
else if (previousButtons[i] && !mState.mButtons[i]) else if (previousButtons[i] && !mState.mButtons[i])
{ {
if (!mListener->buttonReleased(joystickEvent, i)) if (!mListener->buttonReleased(joystickEvent, i))
return; return;
} }
} }
} }
#endif #endif
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
bool Win32JoyStick::_doButtonClick( int button, DIDEVICEOBJECTDATA& di ) bool Win32JoyStick::_doButtonClick( int button, DIDEVICEOBJECTDATA& di )
{ {
if( di.dwData & 0x80 ) if( di.dwData & 0x80 )
{ {
mState.mButtons[button] = true; mState.mButtons[button] = true;
if( mBuffered && mListener ) if( mBuffered && mListener )
return mListener->buttonPressed( JoyStickEvent( this, mState ), button ); return mListener->buttonPressed( JoyStickEvent( this, mState ), button );
} }
else else
{ {
mState.mButtons[button] = false; mState.mButtons[button] = false;
if( mBuffered && mListener ) if( mBuffered && mListener )
return mListener->buttonReleased( JoyStickEvent( this, mState ), button ); return mListener->buttonReleased( JoyStickEvent( this, mState ), button );
} }
return true; return true;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
bool Win32JoyStick::_changePOV( int pov, DIDEVICEOBJECTDATA& di ) bool Win32JoyStick::_changePOV( int pov, DIDEVICEOBJECTDATA& di )
{ {
//Some drivers report a value of 65,535, instead of 1, //Some drivers report a value of 65,535, instead of 1,
//for the center position //for the center position
if(LOWORD(di.dwData) == 0xFFFF) if(LOWORD(di.dwData) == 0xFFFF)
{ {
mState.mPOV[pov].direction = Pov::Centered; mState.mPOV[pov].direction = Pov::Centered;
} }
else else
{ {
switch(di.dwData) switch(di.dwData)
{ {
case 0: mState.mPOV[pov].direction = Pov::North; break; case 0: mState.mPOV[pov].direction = Pov::North; break;
case 4500: mState.mPOV[pov].direction = Pov::NorthEast; break; case 4500: mState.mPOV[pov].direction = Pov::NorthEast; break;
case 9000: mState.mPOV[pov].direction = Pov::East; break; case 9000: mState.mPOV[pov].direction = Pov::East; break;
case 13500: mState.mPOV[pov].direction = Pov::SouthEast; break; case 13500: mState.mPOV[pov].direction = Pov::SouthEast; break;
case 18000: mState.mPOV[pov].direction = Pov::South; break; case 18000: mState.mPOV[pov].direction = Pov::South; break;
case 22500: mState.mPOV[pov].direction = Pov::SouthWest; break; case 22500: mState.mPOV[pov].direction = Pov::SouthWest; break;
case 27000: mState.mPOV[pov].direction = Pov::West; break; case 27000: mState.mPOV[pov].direction = Pov::West; break;
case 31500: mState.mPOV[pov].direction = Pov::NorthWest; break; case 31500: mState.mPOV[pov].direction = Pov::NorthWest; break;
} }
} }
if( mBuffered && mListener ) if( mBuffered && mListener )
return mListener->povMoved( JoyStickEvent( this, mState ), pov ); return mListener->povMoved( JoyStickEvent( this, mState ), pov );
return true; return true;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::setBuffered(bool buffered) void Win32JoyStick::setBuffered(bool buffered)
{ {
mBuffered = buffered; mBuffered = buffered;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Interface* Win32JoyStick::queryInterface(Interface::IType type) Interface* Win32JoyStick::queryInterface(Interface::IType type)
{ {
if( mFfDevice && type == Interface::ForceFeedback ) if( mFfDevice && type == Interface::ForceFeedback )
return mFfDevice; return mFfDevice;
else else
return 0; return 0;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
void Win32JoyStick::CheckXInputDevices(JoyStickInfoList &joys) void Win32JoyStick::CheckXInputDevices(JoyStickInfoList &joys)
{ {
IWbemLocator* pIWbemLocator = NULL; IWbemLocator* pIWbemLocator = NULL;
IEnumWbemClassObject* pEnumDevices = NULL; IEnumWbemClassObject* pEnumDevices = NULL;
IWbemClassObject* pDevices[20] = {0}; IWbemClassObject* pDevices[20] = {0};
IWbemServices* pIWbemServices = NULL; IWbemServices* pIWbemServices = NULL;
BSTR bstrNamespace = NULL; BSTR bstrNamespace = NULL;
BSTR bstrDeviceID = NULL; BSTR bstrDeviceID = NULL;
BSTR bstrClassName = NULL; BSTR bstrClassName = NULL;
DWORD uReturned = 0; DWORD uReturned = 0;
bool bIsXinputDevice= false; bool bIsXinputDevice= false;
DWORD iDevice = 0; DWORD iDevice = 0;
int xDevice = 0; int xDevice = 0;
VARIANT var; VARIANT var;
HRESULT hr; HRESULT hr;
if(joys.size() == 0) if(joys.size() == 0)
return; return;
// CoInit if needed // CoInit if needed
hr = CoInitialize(NULL); hr = CoInitialize(NULL);
bool bCleanupCOM = SUCCEEDED(hr); bool bCleanupCOM = SUCCEEDED(hr);
// Create WMI // Create WMI
hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator); hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator);
if( FAILED(hr) || pIWbemLocator == NULL ) if( FAILED(hr) || pIWbemLocator == NULL )
goto LCleanup; goto LCleanup;
bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" ); bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );
if( bstrNamespace == NULL ) if( bstrNamespace == NULL )
goto LCleanup; goto LCleanup;
bstrClassName = SysAllocString( L"Win32_PNPEntity" ); bstrClassName = SysAllocString( L"Win32_PNPEntity" );
if( bstrClassName == NULL ) if( bstrClassName == NULL )
goto LCleanup; goto LCleanup;
bstrDeviceID = SysAllocString( L"DeviceID" ); bstrDeviceID = SysAllocString( L"DeviceID" );
if( bstrDeviceID == NULL ) if( bstrDeviceID == NULL )
goto LCleanup; goto LCleanup;
// Connect to WMI // Connect to WMI
hr = pIWbemLocator->ConnectServer( bstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices ); hr = pIWbemLocator->ConnectServer( bstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices );
if( FAILED(hr) || pIWbemServices == NULL ) if( FAILED(hr) || pIWbemServices == NULL )
goto LCleanup; goto LCleanup;
// Switch security level to IMPERSONATE. // Switch security level to IMPERSONATE.
CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ); CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
hr = pIWbemServices->CreateInstanceEnum( bstrClassName, 0, NULL, &pEnumDevices ); hr = pIWbemServices->CreateInstanceEnum( bstrClassName, 0, NULL, &pEnumDevices );
if( FAILED(hr) || pEnumDevices == NULL ) if( FAILED(hr) || pEnumDevices == NULL )
goto LCleanup; goto LCleanup;
// Loop over all devices // Loop over all devices
for( ;; ) for( ;; )
{ {
// Get 20 at a time // Get 20 at a time
hr = pEnumDevices->Next(5000, 20, pDevices, &uReturned); hr = pEnumDevices->Next(5000, 20, pDevices, &uReturned);
if( FAILED(hr) ) if( FAILED(hr) )
goto LCleanup; goto LCleanup;
if( uReturned == 0 ) if( uReturned == 0 )
break; break;
for(iDevice = 0; iDevice < uReturned; iDevice++) for(iDevice = 0; iDevice < uReturned; iDevice++)
{ {
// For each device, get its device ID // For each device, get its device ID
hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, NULL, NULL); hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, NULL, NULL);
if(SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) if(SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL)
{ {
// Check if the device ID contains "IG_". If it does, then it's an XInput device - This information can not be found from DirectInput // Check if the device ID contains "IG_". If it does, then it's an XInput device - This information can not be found from DirectInput
if(wcsstr(var.bstrVal, L"IG_")) if(wcsstr(var.bstrVal, L"IG_"))
{ {
// If it does, then get the VID/PID from var.bstrVal // If it does, then get the VID/PID from var.bstrVal
DWORD dwPid = 0, dwVid = 0; DWORD dwPid = 0, dwVid = 0;
WCHAR* strVid = wcsstr( var.bstrVal, L"VID_" ); WCHAR* strVid = wcsstr( var.bstrVal, L"VID_" );
if(strVid && swscanf_s( strVid, L"VID_%4X", &dwVid ) != 1) if(strVid && swscanf_s( strVid, L"VID_%4X", &dwVid ) != 1)
dwVid = 0; dwVid = 0;
WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" ); WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" );
if(strPid && swscanf_s( strPid, L"PID_%4X", &dwPid ) != 1) if(strPid && swscanf_s( strPid, L"PID_%4X", &dwPid ) != 1)
dwPid = 0; dwPid = 0;
// Compare the VID/PID to the DInput device // Compare the VID/PID to the DInput device
DWORD dwVidPid = MAKELONG(dwVid, dwPid); DWORD dwVidPid = MAKELONG(dwVid, dwPid);
for(JoyStickInfoList::iterator i = joys.begin(); i != joys.end(); ++i) for(JoyStickInfoList::iterator i = joys.begin(); i != joys.end(); ++i)
{ {
if(!i->isXInput && dwVidPid == i->productGuid.Data1) if(!i->isXInput && dwVidPid == i->productGuid.Data1)
{ {
i->isXInput = true; i->isXInput = true;
i->xInputDev = xDevice; i->xInputDev = xDevice;
++xDevice; ++xDevice;
} }
} }
if(joys.size() == 0) if(joys.size() == 0)
goto LCleanup; goto LCleanup;
} }
} }
SAFE_RELEASE(pDevices[iDevice]); SAFE_RELEASE(pDevices[iDevice]);
} }
} }
LCleanup: LCleanup:
if(bstrNamespace) if(bstrNamespace)
SysFreeString(bstrNamespace); SysFreeString(bstrNamespace);
if(bstrDeviceID) if(bstrDeviceID)
SysFreeString(bstrDeviceID); SysFreeString(bstrDeviceID);
if(bstrClassName) if(bstrClassName)
SysFreeString(bstrClassName); SysFreeString(bstrClassName);
for(iDevice=0; iDevice < 20; iDevice++) for(iDevice=0; iDevice < 20; iDevice++)
SAFE_RELEASE(pDevices[iDevice]); SAFE_RELEASE(pDevices[iDevice]);
SAFE_RELEASE(pEnumDevices); SAFE_RELEASE(pEnumDevices);
SAFE_RELEASE(pIWbemLocator); SAFE_RELEASE(pIWbemLocator);
SAFE_RELEASE(pIWbemServices); SAFE_RELEASE(pIWbemServices);
if(bCleanupCOM) if(bCleanupCOM)
CoUninitialize(); CoUninitialize();
} }
#endif #endif
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "win32/Win32InputManager.h" #include "win32/Win32InputManager.h"
#include "win32/Win32KeyBoard.h" #include "win32/Win32KeyBoard.h"
#include "OISException.h" #include "OISException.h"
#include "OISEvents.h" #include "OISEvents.h"
#include <sstream> #include <sstream>
using namespace OIS; using namespace OIS;
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32Keyboard::Win32Keyboard( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings ) Win32Keyboard::Win32Keyboard( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings )
: Keyboard(creator->inputSystemName(), buffered, 0, creator) : Keyboard(creator->inputSystemName(), buffered, 0, creator)
{ {
mKeyboard = 0; mKeyboard = 0;
mDirectInput = pDI; mDirectInput = pDI;
coopSetting = coopSettings; coopSetting = coopSettings;
//Clear our keyboard state buffer //Clear our keyboard state buffer
memset( &KeyBuffer, 0, 256 ); memset( &KeyBuffer, 0, 256 );
deadKey = '\0'; deadKey = '\0';
static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(true); static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(true);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::_initialize() void Win32Keyboard::_initialize()
{ {
mModifiers = 0; mModifiers = 0;
deadKey = '\0'; deadKey = '\0';
if(FAILED(mDirectInput->CreateDevice(GUID_SysKeyboard, &mKeyboard, NULL))) if(FAILED(mDirectInput->CreateDevice(GUID_SysKeyboard, &mKeyboard, NULL)))
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> Could not init device!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> Could not init device!");
if(FAILED(mKeyboard->SetDataFormat(&c_dfDIKeyboard))) if(FAILED(mKeyboard->SetDataFormat(&c_dfDIKeyboard)))
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> format error!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> format error!");
HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle(); HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
if(FAILED(mKeyboard->SetCooperativeLevel( hwin, coopSetting))) if(FAILED(mKeyboard->SetCooperativeLevel( hwin, coopSetting)))
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> coop error!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> coop error!");
if( mBuffered ) if( mBuffered )
{ {
DIPROPDWORD dipdw; DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0; dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE; dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = KEYBOARD_DX_BUFFERSIZE; dipdw.dwData = KEYBOARD_DX_BUFFERSIZE;
if (FAILED(mKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ))) if (FAILED(mKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph )))
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> buffer error!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> buffer error!");
} }
HRESULT hr = mKeyboard->Acquire(); HRESULT hr = mKeyboard->Acquire();
if(FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO) if(FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO)
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> aquire error!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> aquire error!");
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32Keyboard::~Win32Keyboard() Win32Keyboard::~Win32Keyboard()
{ {
if(mKeyboard) if(mKeyboard)
{ {
mKeyboard->Unacquire(); mKeyboard->Unacquire();
mKeyboard->Release(); mKeyboard->Release();
mKeyboard = 0; mKeyboard = 0;
} }
static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(false); static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(false);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::capture() void Win32Keyboard::capture()
{ {
if( mBuffered ) if( mBuffered )
_readBuffered(); _readBuffered();
else else
_read(); _read();
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::_readBuffered() void Win32Keyboard::_readBuffered()
{ {
DIDEVICEOBJECTDATA diBuff[KEYBOARD_DX_BUFFERSIZE]; DIDEVICEOBJECTDATA diBuff[KEYBOARD_DX_BUFFERSIZE];
DWORD entries = KEYBOARD_DX_BUFFERSIZE; DWORD entries = KEYBOARD_DX_BUFFERSIZE;
HRESULT hr; HRESULT hr;
//Only one keyboard allowed per app, so static is ok //Only one keyboard allowed per app, so static is ok
static bool verifyAfterAltTab = false; static bool verifyAfterAltTab = false;
hr = mKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); hr = mKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
if( hr != DI_OK ) if( hr != DI_OK )
{ {
hr = mKeyboard->Acquire(); hr = mKeyboard->Acquire();
if (hr == E_ACCESSDENIED) if (hr == E_ACCESSDENIED)
verifyAfterAltTab = true; verifyAfterAltTab = true;
while( hr == DIERR_INPUTLOST ) while( hr == DIERR_INPUTLOST )
hr = mKeyboard->Acquire(); hr = mKeyboard->Acquire();
return; return;
} }
if( FAILED(hr) ) if( FAILED(hr) )
OIS_EXCEPT( E_General, "Win32Keyboard::_readBuffered() >> Problem with Device!" ); OIS_EXCEPT( E_General, "Win32Keyboard::_readBuffered() >> Problem with Device!" );
//Update keyboard and modifier states.. And, if mListener, fire events //Update keyboard and modifier states.. And, if mListener, fire events
for(unsigned int i = 0; i < entries; ++i ) for(unsigned int i = 0; i < entries; ++i )
{ {
//If the listener returns false, that means that we are probably deleted... //If the listener returns false, that means that we are probably deleted...
//send no more events and just leave as the this pointer is invalid now... //send no more events and just leave as the this pointer is invalid now...
bool ret = true; bool ret = true;
KeyCode kc = (KeyCode)diBuff[ i ].dwOfs; KeyCode kc = (KeyCode)diBuff[ i ].dwOfs;
//Store result in our keyBuffer too //Store result in our keyBuffer too
KeyBuffer[kc] = static_cast<unsigned char>(diBuff[ i ].dwData); KeyBuffer[kc] = static_cast<unsigned char>(diBuff[ i ].dwData);
if( diBuff[ i ].dwData & 0x80 ) if( diBuff[ i ].dwData & 0x80 )
{ {
//Turn on modifier //Turn on modifier
if( kc == KC_LCONTROL || kc == KC_RCONTROL ) if( kc == KC_LCONTROL || kc == KC_RCONTROL )
mModifiers |= Ctrl; mModifiers |= Ctrl;
else if( kc == KC_LSHIFT || kc == KC_RSHIFT ) else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
mModifiers |= Shift; mModifiers |= Shift;
else if( kc == KC_LMENU || kc == KC_RMENU ) else if( kc == KC_LMENU || kc == KC_RMENU )
mModifiers |= Alt; mModifiers |= Alt;
if( mListener ) if( mListener )
ret = mListener->keyPressed( KeyEvent( this, kc, _translateText(kc) ) ); ret = mListener->keyPressed( KeyEvent( this, kc, _translateText(kc) ) );
} }
else else
{ {
//Turn off modifier //Turn off modifier
if( kc == KC_LCONTROL || kc == KC_RCONTROL ) if( kc == KC_LCONTROL || kc == KC_RCONTROL )
mModifiers &= ~Ctrl; mModifiers &= ~Ctrl;
else if( kc == KC_LSHIFT || kc == KC_RSHIFT ) else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
mModifiers &= ~Shift; mModifiers &= ~Shift;
else if( kc == KC_LMENU || kc == KC_RMENU ) else if( kc == KC_LMENU || kc == KC_RMENU )
mModifiers &= ~Alt; mModifiers &= ~Alt;
//Fire off event //Fire off event
if( mListener ) if( mListener )
ret = mListener->keyReleased( KeyEvent( this, kc, 0 ) ); ret = mListener->keyReleased( KeyEvent( this, kc, 0 ) );
} }
if(ret == false) if(ret == false)
break; break;
} }
// If a lost device/access denied was detected, recover gracefully with new events // If a lost device/access denied was detected, recover gracefully with new events
if(verifyAfterAltTab) if(verifyAfterAltTab)
{ {
bool ret = true; bool ret = true;
//Copy old buffer to temp location to compare against //Copy old buffer to temp location to compare against
unsigned char keyBufferCopy[256]; unsigned char keyBufferCopy[256];
memcpy(keyBufferCopy, KeyBuffer, 256); memcpy(keyBufferCopy, KeyBuffer, 256);
//Update new state //Update new state
_read(); _read();
for (unsigned i = 0; i < 256; i++) for (unsigned i = 0; i < 256; i++)
{ {
if (keyBufferCopy[i] != KeyBuffer[i]) if (keyBufferCopy[i] != KeyBuffer[i])
{ {
if (mListener) if (mListener)
{ {
if (KeyBuffer[i]) if (KeyBuffer[i])
ret = mListener->keyPressed( KeyEvent( this, (KeyCode)i, _translateText((KeyCode)i) ) ); ret = mListener->keyPressed( KeyEvent( this, (KeyCode)i, _translateText((KeyCode)i) ) );
else else
ret = mListener->keyReleased( KeyEvent( this, (KeyCode)i, 0 ) ); ret = mListener->keyReleased( KeyEvent( this, (KeyCode)i, 0 ) );
} }
} }
//If user returned false from callback, return immediately //If user returned false from callback, return immediately
if(ret == false) if(ret == false)
return; return;
} }
verifyAfterAltTab = false; verifyAfterAltTab = false;
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::_read() void Win32Keyboard::_read()
{ {
HRESULT hr = mKeyboard->GetDeviceState( sizeof(KeyBuffer), &KeyBuffer ); HRESULT hr = mKeyboard->GetDeviceState( sizeof(KeyBuffer), &KeyBuffer );
if( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) if( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED )
{ {
hr = mKeyboard->Acquire(); hr = mKeyboard->Acquire();
if (hr != DIERR_OTHERAPPHASPRIO) if (hr != DIERR_OTHERAPPHASPRIO)
mKeyboard->GetDeviceState(sizeof(KeyBuffer), &KeyBuffer); mKeyboard->GetDeviceState(sizeof(KeyBuffer), &KeyBuffer);
} }
//Set Shift, Ctrl, Alt //Set Shift, Ctrl, Alt
mModifiers = 0; mModifiers = 0;
if( isKeyDown(KC_LCONTROL) || isKeyDown(KC_RCONTROL) ) if( isKeyDown(KC_LCONTROL) || isKeyDown(KC_RCONTROL) )
mModifiers |= Ctrl; mModifiers |= Ctrl;
if( isKeyDown(KC_LSHIFT) || isKeyDown(KC_RSHIFT) ) if( isKeyDown(KC_LSHIFT) || isKeyDown(KC_RSHIFT) )
mModifiers |= Shift; mModifiers |= Shift;
if( isKeyDown(KC_LMENU) || isKeyDown(KC_RMENU) ) if( isKeyDown(KC_LMENU) || isKeyDown(KC_RMENU) )
mModifiers |= Alt; mModifiers |= Alt;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
int Win32Keyboard::_translateText( KeyCode kc ) int Win32Keyboard::_translateText( KeyCode kc )
{ {
if( mTextMode == Off ) if( mTextMode == Off )
return 0; return 0;
BYTE keyState[256]; BYTE keyState[256];
HKL layout = GetKeyboardLayout(0); HKL layout = GetKeyboardLayout(0);
if( GetKeyboardState(keyState) == 0 ) if( GetKeyboardState(keyState) == 0 )
return 0; return 0;
unsigned int vk = MapVirtualKeyEx(kc, 3, layout); unsigned int vk = MapVirtualKeyEx(kc, 3, layout);
if( vk == 0 ) if( vk == 0 )
return 0; return 0;
WCHAR buff[3] = {0}; WCHAR buff[3] = {0};
int ascii = ToUnicodeEx(vk, kc, keyState, buff, 3, 0, layout); int ascii = ToUnicodeEx(vk, kc, keyState, buff, 3, 0, layout);
if(ascii == 1 && deadKey != '\0' ) if(ascii == 1 && deadKey != '\0' )
{ {
// A dead key is stored and we have just converted a character key // A dead key is stored and we have just converted a character key
// Combine the two into a single character // Combine the two into a single character
WCHAR wcBuff[3] = {buff[0], deadKey, '\0'}; WCHAR wcBuff[3] = {buff[0], deadKey, '\0'};
WCHAR out[3]; WCHAR out[3];
deadKey = '\0'; deadKey = '\0';
if(FoldStringW(MAP_PRECOMPOSED, (LPWSTR)wcBuff, 3, (LPWSTR)out, 3)) if(FoldStringW(MAP_PRECOMPOSED, (LPWSTR)wcBuff, 3, (LPWSTR)out, 3))
return out[0]; return out[0];
} }
else if (ascii == 1) else if (ascii == 1)
{ // We have a single character { // We have a single character
deadKey = '\0'; deadKey = '\0';
return buff[0]; return buff[0];
} }
else if(ascii == 2) else if(ascii == 2)
{ // Convert a non-combining diacritical mark into a combining diacritical mark { // Convert a non-combining diacritical mark into a combining diacritical mark
// Combining versions range from 0x300 to 0x36F; only 5 (for French) have been mapped below // Combining versions range from 0x300 to 0x36F; only 5 (for French) have been mapped below
// http://www.fileformat.info/info/unicode/block/combining_diacritical_marks/images.htm // http://www.fileformat.info/info/unicode/block/combining_diacritical_marks/images.htm
switch(buff[0]) { switch(buff[0]) {
case 0x5E: // Circumflex accent: case 0x5E: // Circumflex accent:
deadKey = 0x302; break; deadKey = 0x302; break;
case 0x60: // Grave accent: case 0x60: // Grave accent:
deadKey = 0x300; break; deadKey = 0x300; break;
case 0xA8: // Diaeresis: case 0xA8: // Diaeresis:
deadKey = 0x308; break; deadKey = 0x308; break;
case 0xB4: // Acute accent: case 0xB4: // Acute accent:
deadKey = 0x301; break; deadKey = 0x301; break;
case 0xB8: // Cedilla: case 0xB8: // Cedilla:
deadKey = 0x327; break; deadKey = 0x327; break;
default: default:
deadKey = buff[0]; break; deadKey = buff[0]; break;
} }
} }
return 0; return 0;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
bool Win32Keyboard::isKeyDown( KeyCode key ) const bool Win32Keyboard::isKeyDown( KeyCode key ) const
{ {
return (KeyBuffer[key] & 0x80) != 0; return (KeyBuffer[key] & 0x80) != 0;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
const std::string& Win32Keyboard::getAsString(KeyCode kc) const std::string& Win32Keyboard::getAsString(KeyCode kc)
{ {
char temp[256]; char temp[256];
DIPROPSTRING prop; DIPROPSTRING prop;
prop.diph.dwSize = sizeof(DIPROPSTRING); prop.diph.dwSize = sizeof(DIPROPSTRING);
prop.diph.dwHeaderSize = sizeof(DIPROPHEADER); prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
prop.diph.dwObj = static_cast<DWORD>(kc); prop.diph.dwObj = static_cast<DWORD>(kc);
prop.diph.dwHow = DIPH_BYOFFSET; prop.diph.dwHow = DIPH_BYOFFSET;
if (SUCCEEDED(mKeyboard->GetProperty(DIPROP_KEYNAME, &prop.diph))) if (SUCCEEDED(mKeyboard->GetProperty(DIPROP_KEYNAME, &prop.diph)))
{ {
// convert the WCHAR in "wsz" to multibyte // convert the WCHAR in "wsz" to multibyte
if (WideCharToMultiByte(CP_ACP, 0, prop.wsz, -1, temp, sizeof(temp), NULL, NULL)) if (WideCharToMultiByte(CP_ACP, 0, prop.wsz, -1, temp, sizeof(temp), NULL, NULL))
return mGetString.assign(temp); return mGetString.assign(temp);
} }
std::stringstream ss; std::stringstream ss;
ss << "Key_" << (int)kc; ss << "Key_" << (int)kc;
return mGetString.assign(ss.str()); return mGetString.assign(ss.str());
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::copyKeyStates( char keys[256] ) const void Win32Keyboard::copyKeyStates( char keys[256] ) const
{ {
for(int i = 0; i < 256; ++i) for(int i = 0; i < 256; ++i)
keys[i] = KeyBuffer[i] > 0; //Normalise the DX values (0x80) keys[i] = KeyBuffer[i] > 0; //Normalise the DX values (0x80)
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::setBuffered(bool buffered) void Win32Keyboard::setBuffered(bool buffered)
{ {
if( buffered != mBuffered ) if( buffered != mBuffered )
{ {
if(mKeyboard) if(mKeyboard)
{ {
mKeyboard->Unacquire(); mKeyboard->Unacquire();
mKeyboard->Release(); mKeyboard->Release();
mKeyboard = 0; mKeyboard = 0;
} }
mBuffered = buffered; mBuffered = buffered;
_initialize(); _initialize();
} }
} }
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "win32/Win32Mouse.h" #include "win32/Win32Mouse.h"
#include "win32/Win32InputManager.h" #include "win32/Win32InputManager.h"
#include "OISException.h" #include "OISException.h"
#include "OISEvents.h" #include "OISEvents.h"
using namespace OIS; using namespace OIS;
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32Mouse::Win32Mouse( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings ) Win32Mouse::Win32Mouse( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings )
: Mouse(creator->inputSystemName(), buffered, 0, creator) : Mouse(creator->inputSystemName(), buffered, 0, creator)
{ {
mMouse = 0; mMouse = 0;
mDirectInput = pDI; mDirectInput = pDI;
coopSetting = coopSettings; coopSetting = coopSettings;
mHwnd = 0; mHwnd = 0;
static_cast<Win32InputManager*>(mCreator)->_setMouseUsed(true); static_cast<Win32InputManager*>(mCreator)->_setMouseUsed(true);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Mouse::_initialize() void Win32Mouse::_initialize()
{ {
DIPROPDWORD dipdw; DIPROPDWORD dipdw;
//Clear old state //Clear old state
mState.clear(); mState.clear();
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0; dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE; dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = MOUSE_DX_BUFFERSIZE; dipdw.dwData = MOUSE_DX_BUFFERSIZE;
if( FAILED(mDirectInput->CreateDevice(GUID_SysMouse, &mMouse, NULL)) ) if( FAILED(mDirectInput->CreateDevice(GUID_SysMouse, &mMouse, NULL)) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to create device" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to create device" );
if( FAILED(mMouse->SetDataFormat(&c_dfDIMouse2)) ) if( FAILED(mMouse->SetDataFormat(&c_dfDIMouse2)) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set format" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set format" );
mHwnd = ((Win32InputManager*)mCreator)->getWindowHandle(); mHwnd = ((Win32InputManager*)mCreator)->getWindowHandle();
if( FAILED(mMouse->SetCooperativeLevel(mHwnd, coopSetting)) ) if( FAILED(mMouse->SetCooperativeLevel(mHwnd, coopSetting)) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set coop level" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set coop level" );
if( FAILED(mMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph )) ) if( FAILED(mMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph )) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set property" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set property" );
HRESULT hr = mMouse->Acquire(); HRESULT hr = mMouse->Acquire();
if (FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO) if (FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO)
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to aquire mouse!" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to aquire mouse!" );
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32Mouse::~Win32Mouse() Win32Mouse::~Win32Mouse()
{ {
if (mMouse) if (mMouse)
{ {
mMouse->Unacquire(); mMouse->Unacquire();
mMouse->Release(); mMouse->Release();
mMouse = 0; mMouse = 0;
} }
static_cast<Win32InputManager*>(mCreator)->_setMouseUsed(false); static_cast<Win32InputManager*>(mCreator)->_setMouseUsed(false);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Mouse::capture() void Win32Mouse::capture()
{ {
//Clear old relative values //Clear old relative values
mState.X.rel = mState.Y.rel = mState.Z.rel = 0; mState.X.rel = mState.Y.rel = mState.Z.rel = 0;
DIDEVICEOBJECTDATA diBuff[MOUSE_DX_BUFFERSIZE]; DIDEVICEOBJECTDATA diBuff[MOUSE_DX_BUFFERSIZE];
DWORD entries = MOUSE_DX_BUFFERSIZE; DWORD entries = MOUSE_DX_BUFFERSIZE;
HRESULT hr = mMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); HRESULT hr = mMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
if( hr != DI_OK ) if( hr != DI_OK )
{ {
hr = mMouse->Acquire(); hr = mMouse->Acquire();
while( hr == DIERR_INPUTLOST ) while( hr == DIERR_INPUTLOST )
hr = mMouse->Acquire(); hr = mMouse->Acquire();
hr = mMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); hr = mMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
//Perhaps the user just tabbed away, and coop settings //Perhaps the user just tabbed away, and coop settings
//are nonexclusive..so just ignore //are nonexclusive..so just ignore
if( FAILED(hr) ) if( FAILED(hr) )
return; return;
} }
bool axesMoved = false; bool axesMoved = false;
//Accumulate all axis movements for one axesMove message.. //Accumulate all axis movements for one axesMove message..
//Buttons are fired off as they are found //Buttons are fired off as they are found
for(unsigned int i = 0; i < entries; ++i ) for(unsigned int i = 0; i < entries; ++i )
{ {
switch( diBuff[i].dwOfs ) switch( diBuff[i].dwOfs )
{ {
case DIMOFS_BUTTON0: case DIMOFS_BUTTON0:
if(!_doMouseClick(0, diBuff[i])) return; if(!_doMouseClick(0, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON1: case DIMOFS_BUTTON1:
if(!_doMouseClick(1, diBuff[i])) return; if(!_doMouseClick(1, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON2: case DIMOFS_BUTTON2:
if(!_doMouseClick(2, diBuff[i])) return; if(!_doMouseClick(2, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON3: case DIMOFS_BUTTON3:
if(!_doMouseClick(3, diBuff[i])) return; if(!_doMouseClick(3, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON4: case DIMOFS_BUTTON4:
if(!_doMouseClick(4, diBuff[i])) return; if(!_doMouseClick(4, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON5: case DIMOFS_BUTTON5:
if(!_doMouseClick(5, diBuff[i])) return; if(!_doMouseClick(5, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON6: case DIMOFS_BUTTON6:
if(!_doMouseClick(6, diBuff[i])) return; if(!_doMouseClick(6, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON7: case DIMOFS_BUTTON7:
if(!_doMouseClick(7, diBuff[i])) return; if(!_doMouseClick(7, diBuff[i])) return;
break; break;
case DIMOFS_X: case DIMOFS_X:
mState.X.rel += diBuff[i].dwData; mState.X.rel += diBuff[i].dwData;
axesMoved = true; axesMoved = true;
break; break;
case DIMOFS_Y: case DIMOFS_Y:
mState.Y.rel += diBuff[i].dwData; mState.Y.rel += diBuff[i].dwData;
axesMoved = true; axesMoved = true;
break; break;
case DIMOFS_Z: case DIMOFS_Z:
mState.Z.rel += diBuff[i].dwData; mState.Z.rel += diBuff[i].dwData;
axesMoved = true; axesMoved = true;
break; break;
default: break; default: break;
} //end switch } //end switch
}//end for }//end for
if( axesMoved ) if( axesMoved )
{ {
if( coopSetting & DISCL_NONEXCLUSIVE ) if( coopSetting & DISCL_NONEXCLUSIVE )
{ {
//DirectInput provides us with meaningless values, so correct that //DirectInput provides us with meaningless values, so correct that
POINT point; POINT point;
GetCursorPos(&point); GetCursorPos(&point);
ScreenToClient(mHwnd, &point); ScreenToClient(mHwnd, &point);
mState.X.abs = point.x; mState.X.abs = point.x;
mState.Y.abs = point.y; mState.Y.abs = point.y;
} }
else else
{ {
mState.X.abs += mState.X.rel; mState.X.abs += mState.X.rel;
mState.Y.abs += mState.Y.rel; mState.Y.abs += mState.Y.rel;
} }
mState.Z.abs += mState.Z.rel; mState.Z.abs += mState.Z.rel;
//Clip values to window //Clip values to window
if( mState.X.abs < 0 ) if( mState.X.abs < 0 )
mState.X.abs = 0; mState.X.abs = 0;
else if( mState.X.abs > mState.width ) else if( mState.X.abs > mState.width )
mState.X.abs = mState.width; mState.X.abs = mState.width;
if( mState.Y.abs < 0 ) if( mState.Y.abs < 0 )
mState.Y.abs = 0; mState.Y.abs = 0;
else if( mState.Y.abs > mState.height ) else if( mState.Y.abs > mState.height )
mState.Y.abs = mState.height; mState.Y.abs = mState.height;
//Do the move //Do the move
if( mListener && mBuffered ) if( mListener && mBuffered )
mListener->mouseMoved( MouseEvent( this, mState ) ); mListener->mouseMoved( MouseEvent( this, mState ) );
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
bool Win32Mouse::_doMouseClick( int mouseButton, DIDEVICEOBJECTDATA& di ) bool Win32Mouse::_doMouseClick( int mouseButton, DIDEVICEOBJECTDATA& di )
{ {
if( di.dwData & 0x80 ) if( di.dwData & 0x80 )
{ {
mState.buttons |= 1 << mouseButton; //turn the bit flag on mState.buttons |= 1 << mouseButton; //turn the bit flag on
if( mListener && mBuffered ) if( mListener && mBuffered )
return mListener->mousePressed( MouseEvent( this, mState ), (MouseButtonID)mouseButton ); return mListener->mousePressed( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
} }
else else
{ {
mState.buttons &= ~(1 << mouseButton); //turn the bit flag off mState.buttons &= ~(1 << mouseButton); //turn the bit flag off
if( mListener && mBuffered ) if( mListener && mBuffered )
return mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)mouseButton ); return mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
} }
return true; return true;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Mouse::setBuffered(bool buffered) void Win32Mouse::setBuffered(bool buffered)
{ {
mBuffered = buffered; mBuffered = buffered;
} }
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "OISWiiMote.h" #include "OISWiiMote.h"
#include "OISWiiMoteFactoryCreator.h" #include "OISWiiMoteFactoryCreator.h"
#include "OISException.h" #include "OISException.h"
#include "OISWiiMoteForceFeedback.h" #include "OISWiiMoteForceFeedback.h"
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include <math.h> #include <math.h>
#include <limits.h> #include <limits.h>
using namespace OIS; using namespace OIS;
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
WiiMote::WiiMote(InputManager* creator, int id, bool buffered, WiiMoteFactoryCreator* local_creator) : WiiMote::WiiMote(InputManager* creator, int id, bool buffered, WiiMoteFactoryCreator* local_creator) :
JoyStick("cWiiMote", buffered, id, creator), JoyStick("cWiiMote", buffered, id, creator),
mWiiCreator(local_creator), mWiiCreator(local_creator),
mtInitialized(false), mtInitialized(false),
mRingBuffer(OIS_WII_EVENT_BUFFER), mRingBuffer(OIS_WII_EVENT_BUFFER),
mtLastButtonStates(0), mtLastButtonStates(0),
mtLastPOVState(0), mtLastPOVState(0),
mtLastX(0.0f), mtLastX(0.0f),
mtLastY(1.0f), mtLastY(1.0f),
mtLastZ(0.0f), mtLastZ(0.0f),
mtLastNunChuckX(0.0f), mtLastNunChuckX(0.0f),
mtLastNunChuckY(1.0f), mtLastNunChuckY(1.0f),
mtLastNunChuckZ(0.0f), mtLastNunChuckZ(0.0f),
mLastNunChuckXAxis(0), mLastNunChuckXAxis(0),
mLastNunChuckYAxis(0), mLastNunChuckYAxis(0),
_mWiiMoteMotionDelay(5), _mWiiMoteMotionDelay(5),
mRumble(0) mRumble(0)
{ {
mRumble = new WiiMoteForceFeedback(mWiiMote); mRumble = new WiiMoteForceFeedback(mWiiMote);
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
WiiMote::~WiiMote() WiiMote::~WiiMote()
{ {
delete mRumble; delete mRumble;
if( mWiiMote.IsConnected() ) if( mWiiMote.IsConnected() )
{ {
mWiiMote.StopDataStream(); mWiiMote.StopDataStream();
mWiiMote.Disconnect(); mWiiMote.Disconnect();
} }
mWiiCreator->_returnWiiMote(mDevID); mWiiCreator->_returnWiiMote(mDevID);
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::_initialize() void WiiMote::_initialize()
{ {
if( mWiiMote.ConnectToDevice(mDevID) == false ) if( mWiiMote.ConnectToDevice(mDevID) == false )
OIS_EXCEPT(E_InputDisconnected, "Error connecting to WiiMote!"); OIS_EXCEPT(E_InputDisconnected, "Error connecting to WiiMote!");
if( mWiiMote.StartDataStream() == false ) if( mWiiMote.StartDataStream() == false )
OIS_EXCEPT(E_InputDisconnected, "Error starting WiiMote data stream!"); OIS_EXCEPT(E_InputDisconnected, "Error starting WiiMote data stream!");
//Fill in joystick information //Fill in joystick information
mState.mVectors.clear(); mState.mVectors.clear();
mState.mButtons.clear(); mState.mButtons.clear();
mState.mAxes.clear(); mState.mAxes.clear();
if( mWiiMote.IsNunChuckAttached() ) if( mWiiMote.IsNunChuckAttached() )
{ //Setup for WiiMote + nunChuck { //Setup for WiiMote + nunChuck
mState.mVectors.resize(2); mState.mVectors.resize(2);
mState.mButtons.resize(9); mState.mButtons.resize(9);
mState.mAxes.resize(2); mState.mAxes.resize(2);
mState.mAxes[0].absOnly = true; mState.mAxes[0].absOnly = true;
mState.mAxes[1].absOnly = true; mState.mAxes[1].absOnly = true;
} }
else else
{ //Setup for WiiMote { //Setup for WiiMote
mState.mVectors.resize(1); mState.mVectors.resize(1);
mState.mButtons.resize(7); mState.mButtons.resize(7);
} }
mPOVs = 1; mPOVs = 1;
mState.clear(); mState.clear();
mtInitialized = true; mtInitialized = true;
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::_threadUpdate() void WiiMote::_threadUpdate()
{ {
//Leave early if nothing is setup yet //Leave early if nothing is setup yet
if( mtInitialized == false ) if( mtInitialized == false )
return; return;
//Oops, no room left in ring buffer.. have to wait for client app to call Capture() //Oops, no room left in ring buffer.. have to wait for client app to call Capture()
if( mRingBuffer.GetWriteAvailable() == 0 ) if( mRingBuffer.GetWriteAvailable() == 0 )
return; return;
WiiMoteEvent newEvent; WiiMoteEvent newEvent;
newEvent.clear(); newEvent.clear();
//Update read //Update read
mWiiMote.HeartBeat(); mWiiMote.HeartBeat();
//Get & check current button states //Get & check current button states
const cWiiMote::tButtonStatus &bState = mWiiMote.GetLastButtonStatus(); const cWiiMote::tButtonStatus &bState = mWiiMote.GetLastButtonStatus();
_doButtonCheck(bState.m1, 0, newEvent.pushedButtons, newEvent.releasedButtons); //1 _doButtonCheck(bState.m1, 0, newEvent.pushedButtons, newEvent.releasedButtons); //1
_doButtonCheck(bState.m2, 1, newEvent.pushedButtons, newEvent.releasedButtons); //2 _doButtonCheck(bState.m2, 1, newEvent.pushedButtons, newEvent.releasedButtons); //2
_doButtonCheck(bState.mA, 2, newEvent.pushedButtons, newEvent.releasedButtons); //A _doButtonCheck(bState.mA, 2, newEvent.pushedButtons, newEvent.releasedButtons); //A
_doButtonCheck(bState.mB, 3, newEvent.pushedButtons, newEvent.releasedButtons); //B _doButtonCheck(bState.mB, 3, newEvent.pushedButtons, newEvent.releasedButtons); //B
_doButtonCheck(bState.mPlus, 4, newEvent.pushedButtons, newEvent.releasedButtons);//+ _doButtonCheck(bState.mPlus, 4, newEvent.pushedButtons, newEvent.releasedButtons);//+
_doButtonCheck(bState.mMinus, 5, newEvent.pushedButtons, newEvent.releasedButtons);//- _doButtonCheck(bState.mMinus, 5, newEvent.pushedButtons, newEvent.releasedButtons);//-
_doButtonCheck(bState.mHome, 6, newEvent.pushedButtons, newEvent.releasedButtons);//Home _doButtonCheck(bState.mHome, 6, newEvent.pushedButtons, newEvent.releasedButtons);//Home
//Check POV //Check POV
newEvent.povChanged = _doPOVCheck(bState, newEvent.povDirection); newEvent.povChanged = _doPOVCheck(bState, newEvent.povDirection);
//Do motion check on main orientation - accounting for sensitivity factor //Do motion check on main orientation - accounting for sensitivity factor
mWiiMote.GetCalibratedAcceleration(newEvent.x, newEvent.y, newEvent.z); mWiiMote.GetCalibratedAcceleration(newEvent.x, newEvent.y, newEvent.z);
//Normalize new vector (old vector is already normalized) //Normalize new vector (old vector is already normalized)
float len = sqrt((newEvent.x*newEvent.x) + (newEvent.y*newEvent.y) + (newEvent.z*newEvent.z)); float len = sqrt((newEvent.x*newEvent.x) + (newEvent.y*newEvent.y) + (newEvent.z*newEvent.z));
newEvent.x /= len; newEvent.x /= len;
newEvent.y /= len; newEvent.y /= len;
newEvent.z /= len; newEvent.z /= len;
//Get new angle //Get new angle
float angle = acos((newEvent.x * mtLastX) + (newEvent.y * mtLastY) + (newEvent.z * mtLastZ)); float angle = acos((newEvent.x * mtLastX) + (newEvent.y * mtLastY) + (newEvent.z * mtLastZ));
if( angle > (mVector3Sensitivity * (M_PI / 180.0)) ) if( angle > (mVector3Sensitivity * (M_PI / 180.0)) )
{ //Store for next check { //Store for next check
mtLastX = newEvent.x; mtLastX = newEvent.x;
mtLastY = newEvent.y; mtLastY = newEvent.y;
mtLastZ = newEvent.z; mtLastZ = newEvent.z;
if( _mWiiMoteMotionDelay <= 0 ) if( _mWiiMoteMotionDelay <= 0 )
newEvent.movement = true; //Set flag as moved newEvent.movement = true; //Set flag as moved
else else
--_mWiiMoteMotionDelay; --_mWiiMoteMotionDelay;
} }
//Act on NunChuck Data //Act on NunChuck Data
if( mWiiMote.IsNunChuckAttached() ) if( mWiiMote.IsNunChuckAttached() )
{ {
const cWiiMote::tChuckReport &bState = mWiiMote.GetLastChuckReport(); const cWiiMote::tChuckReport &bState = mWiiMote.GetLastChuckReport();
_doButtonCheck(bState.mButtonC, 7, newEvent.pushedButtons, newEvent.releasedButtons); //C _doButtonCheck(bState.mButtonC, 7, newEvent.pushedButtons, newEvent.releasedButtons); //C
_doButtonCheck(bState.mButtonZ, 8, newEvent.pushedButtons, newEvent.releasedButtons); //Z _doButtonCheck(bState.mButtonZ, 8, newEvent.pushedButtons, newEvent.releasedButtons); //Z
mWiiMote.GetCalibratedChuckAcceleration(newEvent.nunChuckx, newEvent.nunChucky, newEvent.nunChuckz); mWiiMote.GetCalibratedChuckAcceleration(newEvent.nunChuckx, newEvent.nunChucky, newEvent.nunChuckz);
//Normalize new vector (old vector is already normalized) //Normalize new vector (old vector is already normalized)
float len = sqrt((newEvent.nunChuckx*newEvent.nunChuckx) + float len = sqrt((newEvent.nunChuckx*newEvent.nunChuckx) +
(newEvent.nunChucky*newEvent.nunChucky) + (newEvent.nunChucky*newEvent.nunChucky) +
(newEvent.nunChuckz*newEvent.nunChuckz)); (newEvent.nunChuckz*newEvent.nunChuckz));
newEvent.nunChuckx /= len; newEvent.nunChuckx /= len;
newEvent.nunChucky /= len; newEvent.nunChucky /= len;
newEvent.nunChuckz /= len; newEvent.nunChuckz /= len;
float angle = acos((newEvent.nunChuckx * mtLastNunChuckX) + float angle = acos((newEvent.nunChuckx * mtLastNunChuckX) +
(newEvent.nunChucky * mtLastNunChuckY) + (newEvent.nunChucky * mtLastNunChuckY) +
(newEvent.nunChuckz * mtLastNunChuckZ)); (newEvent.nunChuckz * mtLastNunChuckZ));
if( angle > (mVector3Sensitivity * (M_PI / 180.0)) ) if( angle > (mVector3Sensitivity * (M_PI / 180.0)) )
{ //Store for next check { //Store for next check
mtLastNunChuckX = newEvent.nunChuckx; mtLastNunChuckX = newEvent.nunChuckx;
mtLastNunChuckY = newEvent.nunChucky; mtLastNunChuckY = newEvent.nunChucky;
mtLastNunChuckZ = newEvent.nunChuckz; mtLastNunChuckZ = newEvent.nunChuckz;
if( _mWiiMoteMotionDelay <= 0 ) if( _mWiiMoteMotionDelay <= 0 )
newEvent.movementChuck = true; newEvent.movementChuck = true;
} }
//Ok, Now check both NunChuck Joystick axes for movement //Ok, Now check both NunChuck Joystick axes for movement
float tempX = 0.0f, tempY = 0.0f; float tempX = 0.0f, tempY = 0.0f;
mWiiMote.GetCalibratedChuckStick(tempX, tempY); mWiiMote.GetCalibratedChuckStick(tempX, tempY);
//Convert to int and clip //Convert to int and clip
newEvent.nunChuckXAxis = (int)(tempX * JoyStick::MAX_AXIS); newEvent.nunChuckXAxis = (int)(tempX * JoyStick::MAX_AXIS);
if( newEvent.nunChuckXAxis > JoyStick::MAX_AXIS ) if( newEvent.nunChuckXAxis > JoyStick::MAX_AXIS )
newEvent.nunChuckXAxis = JoyStick::MAX_AXIS; newEvent.nunChuckXAxis = JoyStick::MAX_AXIS;
else if( newEvent.nunChuckXAxis < JoyStick::MIN_AXIS ) else if( newEvent.nunChuckXAxis < JoyStick::MIN_AXIS )
newEvent.nunChuckXAxis = JoyStick::MIN_AXIS; newEvent.nunChuckXAxis = JoyStick::MIN_AXIS;
newEvent.nunChuckYAxis = (int)(tempY * JoyStick::MAX_AXIS); newEvent.nunChuckYAxis = (int)(tempY * JoyStick::MAX_AXIS);
if( newEvent.nunChuckYAxis > JoyStick::MAX_AXIS ) if( newEvent.nunChuckYAxis > JoyStick::MAX_AXIS )
newEvent.nunChuckYAxis = JoyStick::MAX_AXIS; newEvent.nunChuckYAxis = JoyStick::MAX_AXIS;
else if( newEvent.nunChuckYAxis < JoyStick::MIN_AXIS ) else if( newEvent.nunChuckYAxis < JoyStick::MIN_AXIS )
newEvent.nunChuckYAxis = JoyStick::MIN_AXIS; newEvent.nunChuckYAxis = JoyStick::MIN_AXIS;
//Apply a little dead-zone dampner //Apply a little dead-zone dampner
int xDiff = newEvent.nunChuckXAxis - mLastNunChuckXAxis; int xDiff = newEvent.nunChuckXAxis - mLastNunChuckXAxis;
if( xDiff > 1500 || xDiff < -1500 ) if( xDiff > 1500 || xDiff < -1500 )
{ {
mLastNunChuckXAxis = newEvent.nunChuckXAxis; mLastNunChuckXAxis = newEvent.nunChuckXAxis;
newEvent.nunChuckXAxisMoved = true; newEvent.nunChuckXAxisMoved = true;
} }
int yDiff = newEvent.nunChuckYAxis - mLastNunChuckYAxis; int yDiff = newEvent.nunChuckYAxis - mLastNunChuckYAxis;
if( yDiff > 1500 || yDiff < -1500 ) if( yDiff > 1500 || yDiff < -1500 )
{ {
mLastNunChuckYAxis = newEvent.nunChuckYAxis; mLastNunChuckYAxis = newEvent.nunChuckYAxis;
newEvent.nunChuckYAxisMoved = true; newEvent.nunChuckYAxisMoved = true;
} }
} }
//Ok, put entry in ringbuffer if something changed //Ok, put entry in ringbuffer if something changed
if(newEvent.pushedButtons || newEvent.releasedButtons || newEvent.povChanged || newEvent.movement || if(newEvent.pushedButtons || newEvent.releasedButtons || newEvent.povChanged || newEvent.movement ||
newEvent.movementChuck || newEvent.nunChuckXAxisMoved || newEvent.nunChuckYAxisMoved) newEvent.movementChuck || newEvent.nunChuckXAxisMoved || newEvent.nunChuckYAxisMoved)
{ {
mRingBuffer.Write(&newEvent, 1); mRingBuffer.Write(&newEvent, 1);
} }
//mWiiMote.PrintStatus(); //mWiiMote.PrintStatus();
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::_doButtonCheck(bool new_state, int ois_button, unsigned int &pushed, unsigned int &released) void WiiMote::_doButtonCheck(bool new_state, int ois_button, unsigned int &pushed, unsigned int &released)
{ {
const bool old_state = ((mtLastButtonStates & ( 1L << ois_button )) == 0) ? false : true; const bool old_state = ((mtLastButtonStates & ( 1L << ois_button )) == 0) ? false : true;
//Check to see if new state and old state are the same, and hence, need no change //Check to see if new state and old state are the same, and hence, need no change
if( new_state == old_state ) if( new_state == old_state )
return; return;
//Ok, so it changed... but how? //Ok, so it changed... but how?
if( new_state ) if( new_state )
{ //Ok, new state is pushed, old state was not pushed.. so send button press { //Ok, new state is pushed, old state was not pushed.. so send button press
mtLastButtonStates |= 1 << ois_button; //turn the bit flag on mtLastButtonStates |= 1 << ois_button; //turn the bit flag on
pushed |= 1 << ois_button; pushed |= 1 << ois_button;
} }
else else
{ //Ok, so new state is not pushed, and old state was pushed.. So, send release { //Ok, so new state is not pushed, and old state was pushed.. So, send release
mtLastButtonStates &= ~(1 << ois_button); //turn the bit flag off mtLastButtonStates &= ~(1 << ois_button); //turn the bit flag off
released |= 1 << ois_button; released |= 1 << ois_button;
} }
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
bool WiiMote::_doPOVCheck(const cWiiMote::tButtonStatus &bState, unsigned int &newPosition) bool WiiMote::_doPOVCheck(const cWiiMote::tButtonStatus &bState, unsigned int &newPosition)
{ {
newPosition = Pov::Centered; newPosition = Pov::Centered;
if( bState.mUp ) if( bState.mUp )
newPosition |= Pov::North; newPosition |= Pov::North;
else if( bState.mDown ) else if( bState.mDown )
newPosition |= Pov::South; newPosition |= Pov::South;
if( bState.mLeft ) if( bState.mLeft )
newPosition |= Pov::West; newPosition |= Pov::West;
else if( bState.mRight ) else if( bState.mRight )
newPosition |= Pov::East; newPosition |= Pov::East;
//Was there a change? //Was there a change?
if( mtLastPOVState != newPosition ) if( mtLastPOVState != newPosition )
{ {
mtLastPOVState = newPosition; mtLastPOVState = newPosition;
return true; return true;
} }
return false; return false;
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::setBuffered(bool buffered) void WiiMote::setBuffered(bool buffered)
{ {
mBuffered = buffered; mBuffered = buffered;
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::capture() void WiiMote::capture()
{ {
//Anything to read? //Anything to read?
int entries = mRingBuffer.GetReadAvailable(); int entries = mRingBuffer.GetReadAvailable();
if( entries <= 0 ) if( entries <= 0 )
return; return;
WiiMoteEvent events[OIS_WII_EVENT_BUFFER]; WiiMoteEvent events[OIS_WII_EVENT_BUFFER];
if( entries > OIS_WII_EVENT_BUFFER ) if( entries > OIS_WII_EVENT_BUFFER )
entries = OIS_WII_EVENT_BUFFER; entries = OIS_WII_EVENT_BUFFER;
mRingBuffer.Read(events, entries); mRingBuffer.Read(events, entries);
//Loop through each event //Loop through each event
for( int i = 0; i < entries; ++i ) for( int i = 0; i < entries; ++i )
{ {
//Any movement changes in the main accellerometers? //Any movement changes in the main accellerometers?
if( events[i].movement ) if( events[i].movement )
{ {
mState.mVectors[0].x = events[i].x; mState.mVectors[0].x = events[i].x;
mState.mVectors[0].y = events[i].y; mState.mVectors[0].y = events[i].y;
mState.mVectors[0].z = events[i].z; mState.mVectors[0].z = events[i].z;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 0 ) ) return; if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 0 ) ) return;
} }
//Check NunChuck movements //Check NunChuck movements
if( events[i].movementChuck ) if( events[i].movementChuck )
{ {
mState.mVectors[1].x = events[i].nunChuckx; mState.mVectors[1].x = events[i].nunChuckx;
mState.mVectors[1].y = events[i].nunChucky; mState.mVectors[1].y = events[i].nunChucky;
mState.mVectors[1].z = events[i].nunChuckz; mState.mVectors[1].z = events[i].nunChuckz;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 1 ) ) return; if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 1 ) ) return;
} }
if( events[i].nunChuckXAxisMoved ) if( events[i].nunChuckXAxisMoved )
{ {
mState.mAxes[0].abs = events[i].nunChuckXAxis; mState.mAxes[0].abs = events[i].nunChuckXAxis;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->axisMoved( JoyStickEvent( this, mState ), 0 ) ) return; if( !mListener->axisMoved( JoyStickEvent( this, mState ), 0 ) ) return;
} }
if( events[i].nunChuckYAxisMoved ) if( events[i].nunChuckYAxisMoved )
{ {
mState.mAxes[1].abs = events[i].nunChuckYAxis; mState.mAxes[1].abs = events[i].nunChuckYAxis;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->axisMoved( JoyStickEvent( this, mState ), 1 ) ) return; if( !mListener->axisMoved( JoyStickEvent( this, mState ), 1 ) ) return;
} }
//Has the hat swtich changed? //Has the hat swtich changed?
if( events[i].povChanged ) if( events[i].povChanged )
{ {
mState.mPOV[0].direction = events[i].povDirection; mState.mPOV[0].direction = events[i].povDirection;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->povMoved( JoyStickEvent( this, mState ), 0 ) ) return; if( !mListener->povMoved( JoyStickEvent( this, mState ), 0 ) ) return;
} }
//Check for any pushed/released events for each button bit //Check for any pushed/released events for each button bit
int buttons = (int)mState.mButtons.size(); int buttons = (int)mState.mButtons.size();
for( int b = 0; b < buttons; ++b ) for( int b = 0; b < buttons; ++b )
{ {
unsigned bit_flag = 1 << b; unsigned bit_flag = 1 << b;
if( (events[i].pushedButtons & bit_flag) != 0 ) if( (events[i].pushedButtons & bit_flag) != 0 )
{ //send event { //send event
mState.mButtons[b] = true; mState.mButtons[b] = true;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->buttonPressed( JoyStickEvent( this, mState ), b ) ) return; if( !mListener->buttonPressed( JoyStickEvent( this, mState ), b ) ) return;
} }
if( (events[i].releasedButtons & bit_flag) != 0 ) if( (events[i].releasedButtons & bit_flag) != 0 )
{ //send event { //send event
mState.mButtons[b] = false; mState.mButtons[b] = false;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->buttonReleased( JoyStickEvent( this, mState ), b ) ) return; if( !mListener->buttonReleased( JoyStickEvent( this, mState ), b ) ) return;
} }
} }
} }
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
Interface* WiiMote::queryInterface(Interface::IType type) Interface* WiiMote::queryInterface(Interface::IType type)
{ {
if( type == Interface::ForceFeedback && mtInitialized ) if( type == Interface::ForceFeedback && mtInitialized )
return mRumble; return mRumble;
return 0; return 0;
} }
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef OIS_WiiMote_H #ifndef OIS_WiiMote_H
#define OIS_WiiMote_H #define OIS_WiiMote_H
#include "OISJoyStick.h" #include "OISJoyStick.h"
#include "OISWiiMoteRingBuffer.h" #include "OISWiiMoteRingBuffer.h"
#include "wiimote.h" #include "wiimote.h"
namespace OIS namespace OIS
{ {
class WiiMoteFactoryCreator; class WiiMoteFactoryCreator;
class WiiMoteForceFeedback; class WiiMoteForceFeedback;
//Number of ring buffer events. should be nice sized (the structure is not very big) //Number of ring buffer events. should be nice sized (the structure is not very big)
//Will be rounded up to power of two automatically //Will be rounded up to power of two automatically
#define OIS_WII_EVENT_BUFFER 32 #define OIS_WII_EVENT_BUFFER 32
/** Specialty joystick - WiiMote controller */ /** Specialty joystick - WiiMote controller */
class _OISExport WiiMote : public JoyStick class _OISExport WiiMote : public JoyStick
{ {
public: public:
WiiMote(InputManager* creator, int id, bool buffered, WiiMoteFactoryCreator* local_creator); WiiMote(InputManager* creator, int id, bool buffered, WiiMoteFactoryCreator* local_creator);
~WiiMote(); ~WiiMote();
//Overrides of Object //Overrides of Object
void setBuffered(bool buffered); void setBuffered(bool buffered);
void capture(); void capture();
Interface* queryInterface(Interface::IType type); Interface* queryInterface(Interface::IType type);
void _initialize(); void _initialize();
void _threadUpdate(); void _threadUpdate();
protected: protected:
void _doButtonCheck(bool new_state, int ois_button, unsigned int &pushed, unsigned int &released); void _doButtonCheck(bool new_state, int ois_button, unsigned int &pushed, unsigned int &released);
bool _doPOVCheck(const cWiiMote::tButtonStatus &bState, unsigned int &newPosition); bool _doPOVCheck(const cWiiMote::tButtonStatus &bState, unsigned int &newPosition);
//! The creator who created us //! The creator who created us
WiiMoteFactoryCreator *mWiiCreator; WiiMoteFactoryCreator *mWiiCreator;
//! Actual WiiMote HID device //! Actual WiiMote HID device
cWiiMote mWiiMote; cWiiMote mWiiMote;
//! Used to signal thread that remote is ready //! Used to signal thread that remote is ready
volatile bool mtInitialized; volatile bool mtInitialized;
//! Ringbuffer is used to store events from thread and be read from capture //! Ringbuffer is used to store events from thread and be read from capture
WiiMoteRingBuffer mRingBuffer; WiiMoteRingBuffer mRingBuffer;
//Following variables are used entirely within threaded context //Following variables are used entirely within threaded context
int mtLastButtonStates; int mtLastButtonStates;
unsigned int mtLastPOVState; unsigned int mtLastPOVState;
float mtLastX, mtLastY, mtLastZ; float mtLastX, mtLastY, mtLastZ;
float mtLastNunChuckX, mtLastNunChuckY, mtLastNunChuckZ; float mtLastNunChuckX, mtLastNunChuckY, mtLastNunChuckZ;
int mLastNunChuckXAxis, mLastNunChuckYAxis; int mLastNunChuckXAxis, mLastNunChuckYAxis;
//Small workaround for slow calibration of wiimote data //Small workaround for slow calibration of wiimote data
int _mWiiMoteMotionDelay; int _mWiiMoteMotionDelay;
//Simple rumble force //Simple rumble force
WiiMoteForceFeedback *mRumble; WiiMoteForceFeedback *mRumble;
}; };
} }
#endif //OIS_WiiMote_H #endif //OIS_WiiMote_H
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "OISWiiMoteFactoryCreator.h" #include "OISWiiMoteFactoryCreator.h"
#include "OISException.h" #include "OISException.h"
#include "OISWiiMote.h" #include "OISWiiMote.h"
#include <assert.h> #include <assert.h>
#include <boost/thread.hpp> //include here, keep compilation times down #include <boost/thread.hpp> //include here, keep compilation times down
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
using namespace OIS; using namespace OIS;
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
WiiMoteFactoryCreator::WiiMoteFactoryCreator() : WiiMoteFactoryCreator::WiiMoteFactoryCreator() :
mVendorName("cWiiMote"), mVendorName("cWiiMote"),
mCount(0), mCount(0),
mtThreadHandler(0), mtThreadHandler(0),
mtWiiMoteListMutex(0), mtWiiMoteListMutex(0),
mtThreadRunning(0) mtThreadRunning(0)
{ {
//Discover how many Wii's there are //Discover how many Wii's there are
for( ; mCount < OIS_cWiiMote_MAX_WIIS; ++mCount ) for( ; mCount < OIS_cWiiMote_MAX_WIIS; ++mCount )
{ {
cWiiMote wii; cWiiMote wii;
if( wii.ConnectToDevice(mCount) == false ) if( wii.ConnectToDevice(mCount) == false )
break; break;
} }
//Store how many WiiMotes there were in the form of integer handles //Store how many WiiMotes there were in the form of integer handles
for(int i = 0; i < mCount; ++i) for(int i = 0; i < mCount; ++i)
mFreeWiis.push_back(i); mFreeWiis.push_back(i);
//The mutex lasts the whole life of this class. The thread does not. //The mutex lasts the whole life of this class. The thread does not.
mtWiiMoteListMutex = new boost::mutex(); mtWiiMoteListMutex = new boost::mutex();
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
WiiMoteFactoryCreator::~WiiMoteFactoryCreator() WiiMoteFactoryCreator::~WiiMoteFactoryCreator()
{ {
//Thread (once all objects destroyed) should be killed off already //Thread (once all objects destroyed) should be killed off already
assert( (mtThreadRunning == false && mtThreadHandler == 0) && assert( (mtThreadRunning == false && mtThreadHandler == 0) &&
"~WiiMoteFactoryCreator(): invalid state.. Some objects left dangling!"); "~WiiMoteFactoryCreator(): invalid state.. Some objects left dangling!");
delete mtWiiMoteListMutex; delete mtWiiMoteListMutex;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
DeviceList WiiMoteFactoryCreator::freeDeviceList() DeviceList WiiMoteFactoryCreator::freeDeviceList()
{ {
DeviceList list; DeviceList list;
for( std::deque<int>::iterator i = mFreeWiis.begin(); i != mFreeWiis.end(); ++i ) for( std::deque<int>::iterator i = mFreeWiis.begin(); i != mFreeWiis.end(); ++i )
{ {
list.insert(std::make_pair(OISJoyStick, mVendorName)); list.insert(std::make_pair(OISJoyStick, mVendorName));
} }
return list; return list;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
int WiiMoteFactoryCreator::totalDevices(Type iType) int WiiMoteFactoryCreator::totalDevices(Type iType)
{ {
if( iType == OISJoyStick ) if( iType == OISJoyStick )
return mCount; return mCount;
else else
return 0; return 0;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
int WiiMoteFactoryCreator::freeDevices(Type iType) int WiiMoteFactoryCreator::freeDevices(Type iType)
{ {
if( iType == OISJoyStick ) if( iType == OISJoyStick )
return (int)mFreeWiis.size(); return (int)mFreeWiis.size();
else else
return 0; return 0;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
bool WiiMoteFactoryCreator::vendorExist(Type iType, const std::string & vendor) bool WiiMoteFactoryCreator::vendorExist(Type iType, const std::string & vendor)
{ {
if( iType == OISJoyStick && mVendorName == vendor ) if( iType == OISJoyStick && mVendorName == vendor )
return true; return true;
else else
return false; return false;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
Object* WiiMoteFactoryCreator::createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor) Object* WiiMoteFactoryCreator::createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor)
{ {
if( mFreeWiis.size() > 0 && (vendor == "" || vendor == mVendorName ) ) if( mFreeWiis.size() > 0 && (vendor == "" || vendor == mVendorName ) )
{ {
int id = mFreeWiis.front(); int id = mFreeWiis.front();
mFreeWiis.pop_front(); mFreeWiis.pop_front();
WiiMote *wii = new WiiMote(creator, id, bufferMode, this); WiiMote *wii = new WiiMote(creator, id, bufferMode, this);
if( mtThreadRunning == false ) if( mtThreadRunning == false )
{ //Create common thread manager (this is the first wiimote created) { //Create common thread manager (this is the first wiimote created)
mtThreadRunning = true; mtThreadRunning = true;
mtThreadHandler = new boost::thread(boost::bind(&WiiMoteFactoryCreator::_updateWiiMotesThread, this)); mtThreadHandler = new boost::thread(boost::bind(&WiiMoteFactoryCreator::_updateWiiMotesThread, this));
} }
//Now, add new WiiMote to thread manager for polling //Now, add new WiiMote to thread manager for polling
{ //Get an auto lock on the list of active wiimotes { //Get an auto lock on the list of active wiimotes
boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex); boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex);
mtInUseWiiMotes.push_back(wii); mtInUseWiiMotes.push_back(wii);
} }
return wii; return wii;
} }
else else
OIS_EXCEPT(E_InputDeviceNonExistant, "No Device found which matches description!"); OIS_EXCEPT(E_InputDeviceNonExistant, "No Device found which matches description!");
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
void WiiMoteFactoryCreator::destroyObject(Object* obj) void WiiMoteFactoryCreator::destroyObject(Object* obj)
{ {
if( obj == 0 ) if( obj == 0 )
return; return;
int wiis_alive = 0; int wiis_alive = 0;
{ //Get an auto lock on the list of active wiimotes { //Get an auto lock on the list of active wiimotes
boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex); boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex);
//Find object //Find object
std::vector<WiiMote*>::iterator i = std::find(mtInUseWiiMotes.begin(), mtInUseWiiMotes.end(), obj); std::vector<WiiMote*>::iterator i = std::find(mtInUseWiiMotes.begin(), mtInUseWiiMotes.end(), obj);
if( i == mtInUseWiiMotes.end() ) if( i == mtInUseWiiMotes.end() )
OIS_EXCEPT(E_General, "Device not found in wimote collection!"); OIS_EXCEPT(E_General, "Device not found in wimote collection!");
//Erase opject //Erase opject
mtInUseWiiMotes.erase(i); mtInUseWiiMotes.erase(i);
//Delete object //Delete object
delete obj; delete obj;
wiis_alive = (int)mtInUseWiiMotes.size(); wiis_alive = (int)mtInUseWiiMotes.size();
} }
//Destroy thread if no longer in use (we do this after unlocking mutex!) //Destroy thread if no longer in use (we do this after unlocking mutex!)
if( wiis_alive == 0 && mtThreadRunning ) if( wiis_alive == 0 && mtThreadRunning )
{ {
mtThreadRunning = false; mtThreadRunning = false;
mtThreadHandler->join(); mtThreadHandler->join();
delete mtThreadHandler; delete mtThreadHandler;
mtThreadHandler = 0; mtThreadHandler = 0;
} }
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
void WiiMoteFactoryCreator::_returnWiiMote(int id) void WiiMoteFactoryCreator::_returnWiiMote(int id)
{ //Restore ID to controller pool { //Restore ID to controller pool
mFreeWiis.push_front(id); mFreeWiis.push_front(id);
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
bool WiiMoteFactoryCreator::_updateWiiMotesThread() bool WiiMoteFactoryCreator::_updateWiiMotesThread()
{ {
boost::xtime timer; boost::xtime timer;
while(mtThreadRunning) while(mtThreadRunning)
{ {
int numMotes = 0; int numMotes = 0;
{ //Get an auto lock on the list of active wiimotes { //Get an auto lock on the list of active wiimotes
boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex); boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex);
numMotes = (int)mtInUseWiiMotes.size(); numMotes = (int)mtInUseWiiMotes.size();
for( std::vector<WiiMote*>::iterator i = mtInUseWiiMotes.begin(), e = mtInUseWiiMotes.end(); i != e; ++i ) for( std::vector<WiiMote*>::iterator i = mtInUseWiiMotes.begin(), e = mtInUseWiiMotes.end(); i != e; ++i )
{ //Update it { //Update it
(*i)->_threadUpdate(); (*i)->_threadUpdate();
} }
} }
//ok, we have updated all wiimotes, let us rest a bit //ok, we have updated all wiimotes, let us rest a bit
//sleep time = 30 / 1000 //sleep time = 30 / 1000
//boost::thread::sleep(xtime) todo xxx wip use sleep instead?? //boost::thread::sleep(xtime) todo xxx wip use sleep instead??
//boost::thread::yield(); //boost::thread::yield();
boost::xtime_get(&timer, boost::TIME_UTC); boost::xtime_get(&timer, boost::TIME_UTC);
timer.nsec += 20000000; //20 000 000 ~= 1/50 sec timer.nsec += 20000000; //20 000 000 ~= 1/50 sec
boost::thread::sleep(timer); boost::thread::sleep(timer);
} }
return true; return true;
} }
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef OIS_WiiMoteFactoryCreator_H #ifndef OIS_WiiMoteFactoryCreator_H
#define OIS_WiiMoteFactoryCreator_H #define OIS_WiiMoteFactoryCreator_H
#include "OISPrereqs.h" #include "OISPrereqs.h"
#include "OISFactoryCreator.h" #include "OISFactoryCreator.h"
#include <deque> #include <deque>
//Forward declare boost classes used //Forward declare boost classes used
namespace boost namespace boost
{ {
class thread; class thread;
class mutex; class mutex;
} }
namespace OIS namespace OIS
{ {
//Forward declare local classes //Forward declare local classes
class WiiMote; class WiiMote;
//! Max amount of Wiis we will attempt to find //! Max amount of Wiis we will attempt to find
#define OIS_cWiiMote_MAX_WIIS 4 #define OIS_cWiiMote_MAX_WIIS 4
/** WiiMote Factory Creator Class */ /** WiiMote Factory Creator Class */
class _OISExport WiiMoteFactoryCreator : public FactoryCreator class _OISExport WiiMoteFactoryCreator : public FactoryCreator
{ {
public: public:
WiiMoteFactoryCreator(); WiiMoteFactoryCreator();
~WiiMoteFactoryCreator(); ~WiiMoteFactoryCreator();
//FactoryCreator Overrides //FactoryCreator Overrides
/** @copydoc FactoryCreator::deviceList */ /** @copydoc FactoryCreator::deviceList */
DeviceList freeDeviceList(); DeviceList freeDeviceList();
/** @copydoc FactoryCreator::totalDevices */ /** @copydoc FactoryCreator::totalDevices */
int totalDevices(Type iType); int totalDevices(Type iType);
/** @copydoc FactoryCreator::freeDevices */ /** @copydoc FactoryCreator::freeDevices */
int freeDevices(Type iType); int freeDevices(Type iType);
/** @copydoc FactoryCreator::vendorExist */ /** @copydoc FactoryCreator::vendorExist */
bool vendorExist(Type iType, const std::string & vendor); bool vendorExist(Type iType, const std::string & vendor);
/** @copydoc FactoryCreator::createObject */ /** @copydoc FactoryCreator::createObject */
Object* createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor = ""); Object* createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor = "");
/** @copydoc FactoryCreator::destroyObject */ /** @copydoc FactoryCreator::destroyObject */
void destroyObject(Object* obj); void destroyObject(Object* obj);
//! Local method used to return controller to pool //! Local method used to return controller to pool
void _returnWiiMote(int id); void _returnWiiMote(int id);
protected: protected:
//! Internal - threaded method //! Internal - threaded method
bool _updateWiiMotesThread(); bool _updateWiiMotesThread();
//! String name of this vendor //! String name of this vendor
std::string mVendorName; std::string mVendorName;
//! queue of open wiimotes (int represents index into hid device) //! queue of open wiimotes (int represents index into hid device)
std::deque<int> mFreeWiis; std::deque<int> mFreeWiis;
//! Number of total wiimotes //! Number of total wiimotes
int mCount; int mCount;
//! Boost thread execution object (only alive when at least 1 wiimote is alive) //! Boost thread execution object (only alive when at least 1 wiimote is alive)
boost::thread *mtThreadHandler; boost::thread *mtThreadHandler;
//! Gaurds access to the Active WiiMote List //! Gaurds access to the Active WiiMote List
boost::mutex *mtWiiMoteListMutex; boost::mutex *mtWiiMoteListMutex;
//! List of created (active) WiiMotes //! List of created (active) WiiMotes
std::vector<WiiMote*> mtInUseWiiMotes; std::vector<WiiMote*> mtInUseWiiMotes;
//! Used to signal thread running or not //! Used to signal thread running or not
volatile bool mtThreadRunning; volatile bool mtThreadRunning;
}; };
} }
#endif //OIS_WiiMoteFactoryCreator_H #endif //OIS_WiiMoteFactoryCreator_H
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "OISWiiMoteForceFeedback.h" #include "OISWiiMoteForceFeedback.h"
#include "OISEffect.h" #include "OISEffect.h"
using namespace OIS; using namespace OIS;
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
WiiMoteForceFeedback::WiiMoteForceFeedback(cWiiMote &wiiMote) : mWiiMote(wiiMote), mHandle(-1) WiiMoteForceFeedback::WiiMoteForceFeedback(cWiiMote &wiiMote) : mWiiMote(wiiMote), mHandle(-1)
{ {
//One and only supported effect //One and only supported effect
_addEffectTypes( OIS::Effect::ConstantForce, OIS::Effect::Constant ); _addEffectTypes( OIS::Effect::ConstantForce, OIS::Effect::Constant );
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
WiiMoteForceFeedback::~WiiMoteForceFeedback() WiiMoteForceFeedback::~WiiMoteForceFeedback()
{ {
mWiiMote.SetVibration(false); mWiiMote.SetVibration(false);
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMoteForceFeedback::upload( const Effect* effect ) void WiiMoteForceFeedback::upload( const Effect* effect )
{ {
if( effect ) if( effect )
{ {
//Multiple effects are useless, just return //Multiple effects are useless, just return
if( mHandle != -1 || effect->_handle != -1) return; if( mHandle != -1 || effect->_handle != -1) return;
//Ok, so we are uploading a fresh effect //Ok, so we are uploading a fresh effect
effect->_handle = mHandle = 1; effect->_handle = mHandle = 1;
mWiiMote.SetVibration(true); mWiiMote.SetVibration(true);
} }
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMoteForceFeedback::modify( const Effect* effect ) void WiiMoteForceFeedback::modify( const Effect* effect )
{ {
//Nothing to modify //Nothing to modify
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMoteForceFeedback::remove( const Effect* effect ) void WiiMoteForceFeedback::remove( const Effect* effect )
{ {
//We have no effects uploaded, so just return //We have no effects uploaded, so just return
if( mHandle == -1 || effect == 0) return; if( mHandle == -1 || effect == 0) return;
if( mHandle == effect->_handle ) if( mHandle == effect->_handle )
{ {
mWiiMote.SetVibration(false); mWiiMote.SetVibration(false);
mHandle = effect->_handle = -1; mHandle = effect->_handle = -1;
} }
} }
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef OIS_WiiMoteForceFeedBack_H #ifndef OIS_WiiMoteForceFeedBack_H
#define OIS_WiiMoteForceFeedBack_H #define OIS_WiiMoteForceFeedBack_H
#include "OISPrereqs.h" #include "OISPrereqs.h"
#include "OISForceFeedback.h" #include "OISForceFeedback.h"
#include "wiimote.h" #include "wiimote.h"
namespace OIS namespace OIS
{ {
class WiiMoteForceFeedback : public ForceFeedback class WiiMoteForceFeedback : public ForceFeedback
{ {
public: public:
WiiMoteForceFeedback(cWiiMote &wiiMote); WiiMoteForceFeedback(cWiiMote &wiiMote);
~WiiMoteForceFeedback(); ~WiiMoteForceFeedback();
/** @copydoc ForceFeedback::upload */ /** @copydoc ForceFeedback::upload */
void upload( const Effect* effect ); void upload( const Effect* effect );
/** @copydoc ForceFeedback::modify */ /** @copydoc ForceFeedback::modify */
void modify( const Effect* effect ); void modify( const Effect* effect );
/** @copydoc ForceFeedback::remove */ /** @copydoc ForceFeedback::remove */
void remove( const Effect* effect ); void remove( const Effect* effect );
/** @copydoc ForceFeedback::setMasterGain */ /** @copydoc ForceFeedback::setMasterGain */
void setMasterGain( float level ) {} void setMasterGain( float level ) {}
/** @copydoc ForceFeedback::setAutoCenterMode */ /** @copydoc ForceFeedback::setAutoCenterMode */
void setAutoCenterMode( bool auto_on ) {} void setAutoCenterMode( bool auto_on ) {}
/** @copydoc ForceFeedback::getFFAxesNumber */ /** @copydoc ForceFeedback::getFFAxesNumber */
short getFFAxesNumber() { return 1; } short getFFAxesNumber() { return 1; }
protected: protected:
//! The WiiMote associated with this effect interface //! The WiiMote associated with this effect interface
cWiiMote &mWiiMote; cWiiMote &mWiiMote;
//! The handle of the one and only allowed effect //! The handle of the one and only allowed effect
int mHandle; int mHandle;
}; };
} }
#endif //OIS_WiiMoteForceFeedBack_H #endif //OIS_WiiMoteForceFeedBack_H
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
# ------------------------# # ------------------------#
# Original License follows: # Original License follows:
# ------------------------# # ------------------------#
* PortAudio Portable Real-Time Audio Library * PortAudio Portable Real-Time Audio Library
* Latest version at: http://www.audiomulch.com/portaudio/ * Latest version at: http://www.audiomulch.com/portaudio/
* <platform> Implementation * <platform> Implementation
* Copyright (c) 1999-2000 <author(s)> * Copyright (c) 1999-2000 <author(s)>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files * a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, * (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, * including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software, * publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, * and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions: * subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
* *
* Any person wishing to distribute modifications to the Software is * Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that * requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. * they can be incorporated into the canonical version.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef OIS_WiiMoteRingBuffer_H #ifndef OIS_WiiMoteRingBuffer_H
#define OIS_WiiMoteRingBuffer_H #define OIS_WiiMoteRingBuffer_H
#include "OISPrereqs.h" #include "OISPrereqs.h"
namespace OIS namespace OIS
{ {
struct WiiMoteEvent struct WiiMoteEvent
{ {
//! (7 buttons) If a button was just pressed, the bit will be set //! (7 buttons) If a button was just pressed, the bit will be set
unsigned int pushedButtons; unsigned int pushedButtons;
//! (7 buttons) If a button was just released, the bit will be set //! (7 buttons) If a button was just released, the bit will be set
unsigned int releasedButtons; unsigned int releasedButtons;
//! Will be true if POV changed this event //! Will be true if POV changed this event
bool povChanged; bool povChanged;
//! Will be valid if povChanged = true //! Will be valid if povChanged = true
unsigned int povDirection; unsigned int povDirection;
//! Will be valid if a movement just occurred on main motion sensing //! Will be valid if a movement just occurred on main motion sensing
bool movement; bool movement;
//Values of main orientation vector //Values of main orientation vector
float x, y, z; float x, y, z;
//! Will be valid if a movement just occurred on main motion sensing //! Will be valid if a movement just occurred on main motion sensing
bool movementChuck; bool movementChuck;
//Values of main orientation vector //Values of main orientation vector
float nunChuckx, nunChucky, nunChuckz; float nunChuckx, nunChucky, nunChuckz;
//Used to flag when a Nunchuck axis moved //Used to flag when a Nunchuck axis moved
bool nunChuckXAxisMoved, nunChuckYAxisMoved; bool nunChuckXAxisMoved, nunChuckYAxisMoved;
//Values of NunChuck JoyStick //Values of NunChuck JoyStick
int nunChuckXAxis, nunChuckYAxis; int nunChuckXAxis, nunChuckYAxis;
//! clear initial state //! clear initial state
void clear() void clear()
{ {
pushedButtons = releasedButtons = 0; pushedButtons = releasedButtons = 0;
povChanged = false; povChanged = false;
povDirection = 0; povDirection = 0;
movement = false; movement = false;
x = y = z = 0.0f; x = y = z = 0.0f;
nunChuckx = nunChucky = nunChuckz = 0; nunChuckx = nunChucky = nunChuckz = 0;
movementChuck = false; movementChuck = false;
nunChuckXAxisMoved = nunChuckYAxisMoved = false; nunChuckXAxisMoved = nunChuckYAxisMoved = false;
nunChuckXAxis = nunChuckYAxis = 0; nunChuckXAxis = nunChuckYAxis = 0;
} }
}; };
/// <summary> /// <summary>
/// Ring Buffer (fifo) used to store 16bit pcm data /// Ring Buffer (fifo) used to store 16bit pcm data
/// </summary> /// </summary>
class WiiMoteRingBuffer class WiiMoteRingBuffer
{ {
private: private:
//! Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init //! Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init
int bufferSize; int bufferSize;
//! Used for wrapping indices with extra bit to distinguish full/empty. //! Used for wrapping indices with extra bit to distinguish full/empty.
int bigMask; int bigMask;
// Used for fitting indices to buffer. // Used for fitting indices to buffer.
int smallMask; int smallMask;
// Buffer holding the actual event buffers // Buffer holding the actual event buffers
WiiMoteEvent *buffer; WiiMoteEvent *buffer;
//! Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. //! Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex.
volatile int writeIndex; volatile int writeIndex;
//! Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. //! Index of next readable byte. Set by RingBuffer_AdvanceReadIndex.
volatile int readIndex; volatile int readIndex;
public: public:
WiiMoteRingBuffer( unsigned int numEntries ) WiiMoteRingBuffer( unsigned int numEntries )
{ {
numEntries = RoundUpToNextPowerOf2( numEntries ); numEntries = RoundUpToNextPowerOf2( numEntries );
//2 bytes per short //2 bytes per short
bufferSize = (int)numEntries; bufferSize = (int)numEntries;
buffer = new WiiMoteEvent[numEntries]; buffer = new WiiMoteEvent[numEntries];
Flush(); Flush();
bigMask = (int)(numEntries*2)-1; bigMask = (int)(numEntries*2)-1;
smallMask = (int)(numEntries)-1; smallMask = (int)(numEntries)-1;
} }
~WiiMoteRingBuffer() ~WiiMoteRingBuffer()
{ {
delete buffer; delete buffer;
} }
unsigned int RoundUpToNextPowerOf2( unsigned int n ) unsigned int RoundUpToNextPowerOf2( unsigned int n )
{ {
int numBits = 0; int numBits = 0;
if( ((n-1) & n) == 0) if( ((n-1) & n) == 0)
return n; //Already Power of two. return n; //Already Power of two.
while( n > 0 ) while( n > 0 )
{ {
n= n>>1; n= n>>1;
numBits++; numBits++;
} }
return (unsigned int)(1<<numBits); return (unsigned int)(1<<numBits);
} }
int GetReadAvailable( ) int GetReadAvailable( )
{ {
return ( (writeIndex - readIndex) & bigMask ); return ( (writeIndex - readIndex) & bigMask );
} }
int GetWriteAvailable( ) int GetWriteAvailable( )
{ {
return ( bufferSize - GetReadAvailable()); return ( bufferSize - GetReadAvailable());
} }
int Write( WiiMoteEvent *data, int numEntries ) int Write( WiiMoteEvent *data, int numEntries )
{ {
int size1 = 0, size2 = 0, numWritten; int size1 = 0, size2 = 0, numWritten;
int data1Ptr = 0, data2Ptr = 0; int data1Ptr = 0, data2Ptr = 0;
numWritten = GetWriteRegions( numEntries, data1Ptr, size1, data2Ptr, size2 ); numWritten = GetWriteRegions( numEntries, data1Ptr, size1, data2Ptr, size2 );
if( size2 > 0 ) if( size2 > 0 )
{ {
//copy to two parts //copy to two parts
memcpy( &buffer[data1Ptr], data, sizeof(WiiMoteEvent) * size1 ); memcpy( &buffer[data1Ptr], data, sizeof(WiiMoteEvent) * size1 );
//Array.Copy( data, offsetPtr, buffer, data1Ptr, size1 ); //Array.Copy( data, offsetPtr, buffer, data1Ptr, size1 );
memcpy( &buffer[data2Ptr], &data[size1], sizeof(WiiMoteEvent) * size2 ); memcpy( &buffer[data2Ptr], &data[size1], sizeof(WiiMoteEvent) * size2 );
//Array.Copy( data, offsetPtr + size1, buffer, data2Ptr, size2 ); //Array.Copy( data, offsetPtr + size1, buffer, data2Ptr, size2 );
} }
else else
{ //Copy all continous { //Copy all continous
memcpy( &buffer[data1Ptr], data, sizeof(WiiMoteEvent) * size1 ); memcpy( &buffer[data1Ptr], data, sizeof(WiiMoteEvent) * size1 );
//Array.Copy( data, offsetPtr, buffer, data1Ptr, size1 ); //Array.Copy( data, offsetPtr, buffer, data1Ptr, size1 );
} }
AdvanceWriteIndex( numWritten ); AdvanceWriteIndex( numWritten );
return numWritten; return numWritten;
} }
/// <summary> /// <summary>
/// Reads requested number of entries into sent array. /// Reads requested number of entries into sent array.
/// Returns number written /// Returns number written
/// </summary> /// </summary>
int Read( WiiMoteEvent *data, int numEntries ) int Read( WiiMoteEvent *data, int numEntries )
{ {
int size1 = 0, size2 = 0, numRead, data1Ptr = 0, data2Ptr = 0; int size1 = 0, size2 = 0, numRead, data1Ptr = 0, data2Ptr = 0;
numRead = GetReadRegions( numEntries, data1Ptr, size1, data2Ptr, size2 ); numRead = GetReadRegions( numEntries, data1Ptr, size1, data2Ptr, size2 );
if( size2 > 0 ) if( size2 > 0 )
{ {
memcpy( data, &buffer[data1Ptr], sizeof(WiiMoteEvent) * size1 ); memcpy( data, &buffer[data1Ptr], sizeof(WiiMoteEvent) * size1 );
//Array.Copy( buffer, data1Ptr, data, 0, size1 ); //Array.Copy( buffer, data1Ptr, data, 0, size1 );
memcpy( &data[size1], &buffer[data2Ptr], sizeof(WiiMoteEvent) * size2 ); memcpy( &data[size1], &buffer[data2Ptr], sizeof(WiiMoteEvent) * size2 );
//Array.Copy( buffer, data2Ptr, data, size1, size2 ); //Array.Copy( buffer, data2Ptr, data, size1, size2 );
} }
else else
memcpy( data, &buffer[data1Ptr], sizeof(WiiMoteEvent) * size1 ); memcpy( data, &buffer[data1Ptr], sizeof(WiiMoteEvent) * size1 );
//Array.Copy( buffer, data1Ptr, data, 0, size1 ); //Array.Copy( buffer, data1Ptr, data, 0, size1 );
AdvanceReadIndex( numRead ); AdvanceReadIndex( numRead );
return numRead; return numRead;
} }
private: private:
int GetWriteRegions( int numEntries, int &dataPtr1, int &sizePtr1, int GetWriteRegions( int numEntries, int &dataPtr1, int &sizePtr1,
int &dataPtr2, int &sizePtr2 ) int &dataPtr2, int &sizePtr2 )
{ {
int index; int index;
int available = GetWriteAvailable(); int available = GetWriteAvailable();
if( numEntries > available ) if( numEntries > available )
numEntries = available; numEntries = available;
//Check to see if write is not contiguous. //Check to see if write is not contiguous.
index = writeIndex & smallMask; index = writeIndex & smallMask;
if( (index + numEntries) > bufferSize ) if( (index + numEntries) > bufferSize )
{ {
//Write data in two blocks that wrap the buffer. //Write data in two blocks that wrap the buffer.
int firstHalf = bufferSize - index; int firstHalf = bufferSize - index;
dataPtr1 = index;//&buffer[index]; dataPtr1 = index;//&buffer[index];
sizePtr1 = firstHalf; sizePtr1 = firstHalf;
dataPtr2 = 0;//&buffer[0]; dataPtr2 = 0;//&buffer[0];
sizePtr2 = numEntries - firstHalf; sizePtr2 = numEntries - firstHalf;
} }
else else
{ {
dataPtr1 = index;//&buffer[index]; dataPtr1 = index;//&buffer[index];
sizePtr1 = numEntries; sizePtr1 = numEntries;
dataPtr2 = 0; dataPtr2 = 0;
sizePtr2 = 0; sizePtr2 = 0;
} }
return numEntries; return numEntries;
} }
int GetReadRegions( int numEntries, int &dataPtr1, int &sizePtr1, int &dataPtr2, int &sizePtr2 ) int GetReadRegions( int numEntries, int &dataPtr1, int &sizePtr1, int &dataPtr2, int &sizePtr2 )
{ {
int index; int index;
int available = GetReadAvailable( ); int available = GetReadAvailable( );
if( numEntries > available ) if( numEntries > available )
numEntries = available; numEntries = available;
// Check to see if read is not contiguous // Check to see if read is not contiguous
index = readIndex & smallMask; index = readIndex & smallMask;
if( (index + numEntries) > bufferSize ) if( (index + numEntries) > bufferSize )
{ {
// Write data in two blocks that wrap the buffer // Write data in two blocks that wrap the buffer
int firstHalf = bufferSize - index; int firstHalf = bufferSize - index;
dataPtr1 = index;//&buffer[index]; dataPtr1 = index;//&buffer[index];
sizePtr1 = firstHalf; sizePtr1 = firstHalf;
dataPtr2 = 0;//&buffer[0]; dataPtr2 = 0;//&buffer[0];
sizePtr2 = numEntries - firstHalf; sizePtr2 = numEntries - firstHalf;
} }
else else
{ {
dataPtr1 = index;//&buffer[index]; dataPtr1 = index;//&buffer[index];
sizePtr1 = numEntries; sizePtr1 = numEntries;
dataPtr2 = 0; dataPtr2 = 0;
sizePtr2 = 0; sizePtr2 = 0;
} }
return numEntries; return numEntries;
} }
int AdvanceWriteIndex( int numEntries ) int AdvanceWriteIndex( int numEntries )
{ {
return writeIndex = (writeIndex + numEntries) & bigMask; return writeIndex = (writeIndex + numEntries) & bigMask;
} }
int AdvanceReadIndex( int numEntries ) int AdvanceReadIndex( int numEntries )
{ {
return readIndex = (readIndex + numEntries) & bigMask; return readIndex = (readIndex + numEntries) & bigMask;
} }
void Flush( ) void Flush( )
{ {
writeIndex = readIndex = 0; writeIndex = readIndex = 0;
} }
}; };
} }
#endif //#define OIS_WiiMoteRingBuffer_H #endif //#define OIS_WiiMoteRingBuffer_H
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
//cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com) //cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
//This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code. //This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code.
//This was based in part on Alan Macek <www.alanmacek.com>'s USB interface library //This was based in part on Alan Macek <www.alanmacek.com>'s USB interface library
//Edited for Toshiba Stack support (hopefully also all others) by //Edited for Toshiba Stack support (hopefully also all others) by
//Sean Stellingwerff (http://sean.stellingwerff.com) using information //Sean Stellingwerff (http://sean.stellingwerff.com) using information
//gathered from http://www.lvr.com/hidpage.htm (Thanks a million! :D) //gathered from http://www.lvr.com/hidpage.htm (Thanks a million! :D)
//#include "stdafx.h" //#include "stdafx.h"
#include "hiddevice.h" #include "hiddevice.h"
extern "C" extern "C"
{ {
#include "hidsdi.h" #include "hidsdi.h"
#include <Setupapi.h> #include <Setupapi.h>
} }
#pragma comment(lib, "setupapi.lib") #pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "hid.lib") #pragma comment(lib, "hid.lib")
HIDP_CAPS Capabilities; HIDP_CAPS Capabilities;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData; PSP_DEVICE_INTERFACE_DETAIL_DATA detailData;
cHIDDevice::cHIDDevice() : mConnected(false), mHandle(NULL), mEvent(NULL) cHIDDevice::cHIDDevice() : mConnected(false), mHandle(NULL), mEvent(NULL)
{ {
} }
cHIDDevice::~cHIDDevice() cHIDDevice::~cHIDDevice()
{ {
if (mConnected) if (mConnected)
{ {
Disconnect(); Disconnect();
} }
} }
bool cHIDDevice::Disconnect() bool cHIDDevice::Disconnect()
{ {
bool retval = false; bool retval = false;
if (mConnected) if (mConnected)
{ {
retval = (CloseHandle(mHandle) == TRUE && CloseHandle(mEvent) == TRUE); retval = (CloseHandle(mHandle) == TRUE && CloseHandle(mEvent) == TRUE);
mConnected = false; mConnected = false;
} }
return retval; return retval;
} }
bool cHIDDevice::Connect(unsigned short device_id, unsigned short vendor_id, int index) bool cHIDDevice::Connect(unsigned short device_id, unsigned short vendor_id, int index)
{ {
if (mConnected) if (mConnected)
{ {
if (!Disconnect()) if (!Disconnect())
{ {
return false; return false;
} }
} }
// Find the wiimote(s) // Find the wiimote(s)
//for (int i = 0; i <= index; i++) //for (int i = 0; i <= index; i++)
OpenDevice( device_id, vendor_id, index ); OpenDevice( device_id, vendor_id, index );
return mConnected; return mConnected;
} }
bool cHIDDevice::OpenDevice(unsigned short device_id, unsigned short vendor_id, int index) bool cHIDDevice::OpenDevice(unsigned short device_id, unsigned short vendor_id, int index)
{ {
//Use a series of API calls to find a HID with a specified Vendor IF and Product ID. //Use a series of API calls to find a HID with a specified Vendor IF and Product ID.
HIDD_ATTRIBUTES Attributes; HIDD_ATTRIBUTES Attributes;
SP_DEVICE_INTERFACE_DATA devInfoData; SP_DEVICE_INTERFACE_DATA devInfoData;
bool LastDevice = FALSE; bool LastDevice = FALSE;
bool MyDeviceDetected = FALSE; bool MyDeviceDetected = FALSE;
int MemberIndex = 0; int MemberIndex = 0;
int MembersFound = 0; int MembersFound = 0;
GUID HidGuid; GUID HidGuid;
ULONG Length; ULONG Length;
LONG Result; LONG Result;
HANDLE hDevInfo; HANDLE hDevInfo;
ULONG Required; ULONG Required;
Length = 0; Length = 0;
detailData = NULL; detailData = NULL;
mHandle=NULL; mHandle=NULL;
HidD_GetHidGuid(&HidGuid); HidD_GetHidGuid(&HidGuid);
hDevInfo=SetupDiGetClassDevs(&HidGuid, NULL, NULL, DIGCF_PRESENT|DIGCF_INTERFACEDEVICE); hDevInfo=SetupDiGetClassDevs(&HidGuid, NULL, NULL, DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
devInfoData.cbSize = sizeof(devInfoData); devInfoData.cbSize = sizeof(devInfoData);
MemberIndex = 0; MemberIndex = 0;
MembersFound = 0; MembersFound = 0;
LastDevice = FALSE; LastDevice = FALSE;
do do
{ {
Result=SetupDiEnumDeviceInterfaces(hDevInfo, 0, &HidGuid, MemberIndex, &devInfoData); Result=SetupDiEnumDeviceInterfaces(hDevInfo, 0, &HidGuid, MemberIndex, &devInfoData);
if (Result != 0) if (Result != 0)
{ {
Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, NULL, 0, &Length, NULL); Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, NULL, 0, &Length, NULL);
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length); detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length);
detailData -> cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); detailData -> cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, detailData, Length, &Required, NULL); Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, detailData, Length, &Required, NULL);
mHandle=CreateFile(detailData->DevicePath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING, 0, NULL); mHandle=CreateFile(detailData->DevicePath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING, 0, NULL);
Attributes.Size = sizeof(Attributes); Attributes.Size = sizeof(Attributes);
Result = HidD_GetAttributes(mHandle, &Attributes); Result = HidD_GetAttributes(mHandle, &Attributes);
//Is it the desired device? //Is it the desired device?
MyDeviceDetected = FALSE; MyDeviceDetected = FALSE;
if (Attributes.VendorID == vendor_id) if (Attributes.VendorID == vendor_id)
{ {
if (Attributes.ProductID == device_id) if (Attributes.ProductID == device_id)
{ {
if (MembersFound == index) if (MembersFound == index)
{ {
//Both the Vendor ID and Product ID match. //Both the Vendor ID and Product ID match.
//printf("Wiimote found!\n"); //printf("Wiimote found!\n");
mConnected = true; mConnected = true;
GetCapabilities(); GetCapabilities();
WriteHandle=CreateFile(detailData->DevicePath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, NULL); WriteHandle=CreateFile(detailData->DevicePath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, NULL);
MyDeviceDetected = TRUE; MyDeviceDetected = TRUE;
PrepareForOverlappedTransfer(); PrepareForOverlappedTransfer();
mEvent = CreateEvent(NULL, TRUE, TRUE, ""); mEvent = CreateEvent(NULL, TRUE, TRUE, "");
mOverlapped.Offset = 0; mOverlapped.Offset = 0;
mOverlapped.OffsetHigh = 0; mOverlapped.OffsetHigh = 0;
mOverlapped.hEvent = mEvent; mOverlapped.hEvent = mEvent;
} else { } else {
//The Product ID doesn't match. //The Product ID doesn't match.
CloseHandle(mHandle); CloseHandle(mHandle);
} }
MembersFound++; MembersFound++;
} }
} else { } else {
CloseHandle(mHandle); CloseHandle(mHandle);
} }
free(detailData); free(detailData);
} else { } else {
LastDevice=TRUE; LastDevice=TRUE;
} }
MemberIndex = MemberIndex + 1; MemberIndex = MemberIndex + 1;
} while ((LastDevice == FALSE) && (MyDeviceDetected == FALSE)); } while ((LastDevice == FALSE) && (MyDeviceDetected == FALSE));
SetupDiDestroyDeviceInfoList(hDevInfo); SetupDiDestroyDeviceInfoList(hDevInfo);
return MyDeviceDetected; return MyDeviceDetected;
} }
bool cHIDDevice::WriteToDevice(unsigned const char * OutputReport, int num_bytes) bool cHIDDevice::WriteToDevice(unsigned const char * OutputReport, int num_bytes)
{ {
bool retval = false; bool retval = false;
if (mConnected) if (mConnected)
{ {
DWORD bytes_written; DWORD bytes_written;
retval = (WriteFile( WriteHandle, OutputReport, num_bytes, &bytes_written, &mOverlapped) == TRUE); retval = (WriteFile( WriteHandle, OutputReport, num_bytes, &bytes_written, &mOverlapped) == TRUE);
retval = retval && bytes_written == num_bytes; retval = retval && bytes_written == num_bytes;
} }
return retval; return retval;
} }
void cHIDDevice::PrepareForOverlappedTransfer() void cHIDDevice::PrepareForOverlappedTransfer()
{ {
//Get a handle to the device for the overlapped ReadFiles. //Get a handle to the device for the overlapped ReadFiles.
ReadHandle=CreateFile(detailData->DevicePath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); ReadHandle=CreateFile(detailData->DevicePath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
} }
void cHIDDevice::GetCapabilities() void cHIDDevice::GetCapabilities()
{ {
//Get the Capabilities structure for the device. //Get the Capabilities structure for the device.
PHIDP_PREPARSED_DATA PreparsedData; PHIDP_PREPARSED_DATA PreparsedData;
HidD_GetPreparsedData(mHandle, &PreparsedData); HidD_GetPreparsedData(mHandle, &PreparsedData);
HidP_GetCaps(PreparsedData, &Capabilities); HidP_GetCaps(PreparsedData, &Capabilities);
//No need for PreparsedData any more, so free the memory it's using. //No need for PreparsedData any more, so free the memory it's using.
HidD_FreePreparsedData(PreparsedData); HidD_FreePreparsedData(PreparsedData);
} }
bool cHIDDevice::ReadFromDevice(unsigned const char * buffer, int max_bytes, int & bytes_read, int timeout) bool cHIDDevice::ReadFromDevice(unsigned const char * buffer, int max_bytes, int & bytes_read, int timeout)
{ {
bool retval = false; bool retval = false;
if (mConnected) if (mConnected)
{ {
ReadFile( ReadHandle, (LPVOID)buffer,max_bytes,(LPDWORD)&bytes_read,(LPOVERLAPPED) &mOverlapped); ReadFile( ReadHandle, (LPVOID)buffer,max_bytes,(LPDWORD)&bytes_read,(LPOVERLAPPED) &mOverlapped);
DWORD Result = WaitForSingleObject(mEvent, timeout); DWORD Result = WaitForSingleObject(mEvent, timeout);
if (Result == WAIT_OBJECT_0) if (Result == WAIT_OBJECT_0)
{ {
retval = true; retval = true;
} }
else else
{ {
CancelIo(mHandle); CancelIo(mHandle);
} }
ResetEvent(mEvent); ResetEvent(mEvent);
} }
return retval; return retval;
} }
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
//cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com) //cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
//This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code. //This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code.
#ifndef HIDDEVICE_H #ifndef HIDDEVICE_H
#define HIDDEVICE_H #define HIDDEVICE_H
#include <windows.h> #include <windows.h>
class cHIDDevice class cHIDDevice
{ {
public: public:
cHIDDevice(); cHIDDevice();
~cHIDDevice(); ~cHIDDevice();
bool Disconnect(); bool Disconnect();
bool Connect(unsigned short device_id, unsigned short vendor_id, int index=0); bool Connect(unsigned short device_id, unsigned short vendor_id, int index=0);
bool IsConnected() const {return mConnected;} bool IsConnected() const {return mConnected;}
bool WriteToDevice(unsigned const char * OutputReport, int num_bytes); bool WriteToDevice(unsigned const char * OutputReport, int num_bytes);
bool ReadFromDevice(unsigned const char * buffer, int max_bytes, int & bytes_read, int timeout=50); bool ReadFromDevice(unsigned const char * buffer, int max_bytes, int & bytes_read, int timeout=50);
private: private:
//bool OpenDevice(int index, unsigned short device_id, unsigned short vendor_id); //bool OpenDevice(int index, unsigned short device_id, unsigned short vendor_id);
bool OpenDevice(unsigned short device_id, unsigned short vendor_id, int index); bool OpenDevice(unsigned short device_id, unsigned short vendor_id, int index);
//bool FindWiimote(); //bool FindWiimote();
void GetCapabilities(); void GetCapabilities();
void PrepareForOverlappedTransfer(); void PrepareForOverlappedTransfer();
HANDLE mHandle; HANDLE mHandle;
HANDLE mEvent; HANDLE mEvent;
HANDLE WriteHandle; HANDLE WriteHandle;
HANDLE ReadHandle; HANDLE ReadHandle;
OVERLAPPED mOverlapped; OVERLAPPED mOverlapped;
OVERLAPPED HIDOverlapped; OVERLAPPED HIDOverlapped;
// HIDP_CAPS Capabilities; // HIDP_CAPS Capabilities;
bool mConnected; bool mConnected;
}; };
#endif #endif
#endif #endif
//cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com) //cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
//This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code. //This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code.
//#include "wiimote.h" //#include "wiimote.h"
//#include <stdio.h> //#include <stdio.h>
//Features: //Features:
// Read Accelerometer, button values from the wiimote // Read Accelerometer, button values from the wiimote
// Read Accelerometer, stick, and button values from the nunchuck // Read Accelerometer, stick, and button values from the nunchuck
// Preliminary IR support // Preliminary IR support
//Known issues: //Known issues:
// The IR support is spotty at best. It tends to kick out if you plug your 'chuck in and out too many times // The IR support is spotty at best. It tends to kick out if you plug your 'chuck in and out too many times
// Reading 'chuck calibration data doesn't seem to work, so the code just uses defaults // Reading 'chuck calibration data doesn't seem to work, so the code just uses defaults
// Multiple Wiimote support not yet tested // Multiple Wiimote support not yet tested
// May only work with Bluesoleil stack? // May only work with Bluesoleil stack?
//Instructions: //Instructions:
// See below for how to connect to a device and start the data stream. // See below for how to connect to a device and start the data stream.
// It is up to the user to call heartbeat fast enough - if you're too slow, you will loose data. Ideally, this would be done in a separate thread // It is up to the user to call heartbeat fast enough - if you're too slow, you will loose data. Ideally, this would be done in a separate thread
// There are several public functions for getting the values from the wiimote. Look in cWiiMote::PrintStatus for examples. // There are several public functions for getting the values from the wiimote. Look in cWiiMote::PrintStatus for examples.
//Version History: //Version History:
//0.1 Preliminary Release //0.1 Preliminary Release
//0.2 Added nunchuck, IR support //0.2 Added nunchuck, IR support
/* /*
int main(int nargs, const char * cargs) int main(int nargs, const char * cargs)
{ {
cWiiMote wiimote; cWiiMote wiimote;
if (wiimote.ConnectToDevice() && if (wiimote.ConnectToDevice() &&
wiimote.StartDataStream()) wiimote.StartDataStream())
{ {
for (;;) for (;;)
{ {
wiimote.HeartBeat(); wiimote.HeartBeat();
wiimote.PrintStatus(); wiimote.PrintStatus();
} }
} }
return 0; return 0;
} }
*/ */
//#eof "$Id: main.cpp,v 1.1.2.1 2008/02/14 03:33:36 pjcast Exp $" //#eof "$Id: main.cpp,v 1.1.2.1 2008/02/14 03:33:36 pjcast Exp $"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment