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