Commit 24236447 authored by TheOnlyJoey's avatar TheOnlyJoey
Browse files

Merge pull request #5 from hymerman/tidying

General tidy-up
parents c546989f ed6e1ba6
/*
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 $"
#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.
//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 "wiimote.h"
#include <stdio.h>
//output channels
const unsigned char OUTPUT_CHANNEL_FORCE_FEEDBACK = 0x13;
const unsigned char OUTPUT_CHANNEL_LED = 0x11;
const unsigned char OUTPUT_CHANNEL_REPORT = 0x12;
const unsigned char OUTPUT_READ_MEMORY = 0x17;
const unsigned char OUTPUT_WRITE_MEMORY = 0x16;
const unsigned char OUTPUT_ENABLE_IR = 0x13;
const unsigned char OUTPUT_ENABLE_IR2 = 0x1a;
//report request types
const unsigned char REQUEST_CONTINUOUS_REPORTS = 0x4;
const unsigned char REQUEST_SINGLE_REPORTS = 0x0;
//input channels
const unsigned char INPUT_CHANNEL_BUTTONS_ONLY = 0x30;
const unsigned char INPUT_CHANNEL_BUTTONS_MOTION = 0x31;
const unsigned char INPUT_CHANNEL_WRITE_CONFIRM = 0x22;
const unsigned char INPUT_CHANNEL_EXPANSION_PORT = 0x20;
const unsigned char INPUT_CHANNEL_MOTION_IR = 0x33;
const unsigned char INPUT_CHANNEL_MOTION_CHUCK_IR = 0x37;
const unsigned char INPUT_CHANNEL_MOTION_CHUCK = 0x35;
//the ID values for a wiimote
const unsigned short mVendorID = 0x057E;
const unsigned short mDeviceID = 0x0306;
//how to find the calibration data for the wiimote
const unsigned short CALIBRATION_ADDRESS = 0x16;
const unsigned short CALIBRATION_DATA_LENGTH = 7;
//nunchuck constants
const unsigned long NUNCHUCK_STATUS_ADDRESS = 0x04A40000;
const unsigned long NUNCHUCK_CALIBRATION_ADDRESS = 0x04A40020;
const unsigned long NUNCHUCK_CALIBRATION_ADDRESS_2 = 0x04A40030;
const unsigned long NUNCHUCK_INIT_ADDRESS= 0x04A40040;
const unsigned long NUNCHUK_ID_ADDRESS = 0x04a400f0;
const unsigned char NUNCHUCK_INIT_VAL= 0x0;
//IR constants
const unsigned long IR_REG_1 = 0x04b00030;
const unsigned long IR_REG_2 = 0x04b00033;
const unsigned long IR_SENS_ADDR_1 = 0x04b00000;
const unsigned long IR_SENS_ADDR_2 = 0x04b0001a;
const unsigned char IR_SENS_MIDRANGE_PART1[] = {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64};
const unsigned char IR_SENS_MIDRANGE_PART2[] = {0x63, 0x03};
const unsigned char IR_MODE_OFF = 0;
const unsigned char IR_MODE_STD = 1;
const unsigned char IR_MODE_EXP = 3;
const unsigned char IR_MODE_FULL = 5;
cWiiMote::cWiiMote()
{
Init();
}
cWiiMote::~cWiiMote()
{
Disconnect();
}
void cWiiMote::Init()
{
mReportMode = REPORT_MODE_EVENT_BUTTONS;
mLastButtonStatus.Init();
mLastExpansionReport.Init();
mLastMotionReport.Init();
mOutputControls.Init();
mReadInfo.Init();
mAccelCalibrationData.Init();
mNunchuckAccelCalibrationData.Init();
mNunchuckStickCalibrationData.Init();
mLastIRReport.Init();
mNunchuckAttached = false;
mIRRunning = false;
mDataStreamRunning = false;
}
bool cWiiMote::SetReportMode(eReportMode mode)
{
mReportMode = mode;
return SendReportMode();
}
bool cWiiMote::SendReportMode()
{
bool continuous = true;
unsigned char channel = INPUT_CHANNEL_BUTTONS_ONLY;
bool check_chuck = false;
switch (mReportMode)
{
case REPORT_MODE_MOTION_IR:
channel = INPUT_CHANNEL_MOTION_IR;
break;
case REPORT_MODE_MOTION_CHUCK_IR:
channel = INPUT_CHANNEL_MOTION_CHUCK_IR;
check_chuck = true;
break;
case REPORT_MODE_MOTION_CHUCK:
channel = INPUT_CHANNEL_MOTION_CHUCK;
check_chuck = true;
break;
case REPORT_MODE_MOTION:
channel = INPUT_CHANNEL_BUTTONS_MOTION;
break;
case REPORT_MODE_EVENT_BUTTONS:
channel = INPUT_CHANNEL_BUTTONS_ONLY;
continuous = false;
break;
default:
break;
}
//check to make sure that there is a chuck attached
// if (check_chuck && !mNunchuckAttached)
// {
// printf("Supposed to check for nunchuck, but couldn't find one!");
// return false;
// }
bool retval = SelectInputChannel(continuous,channel);
return retval;
}
bool cWiiMote::ConnectToDevice(int index)
{
Init();
const bool retval = mHIDDevice.Connect(mDeviceID,mVendorID,index) &&
SetReportMode(REPORT_MODE_MOTION_CHUCK_IR) &&
UpdateOutput() &&
ReadCalibrationData();
if (retval)
{
InitNunchuck();
}
return retval;
}
bool cWiiMote::Disconnect()
{
bool retval = false;
StopDataStream();
if (mHIDDevice.IsConnected())
{
retval = mHIDDevice.Disconnect();
}
return retval;
}
bool cWiiMote::SetVibration(bool vib_on)
{
bool retval = true;
if (mOutputControls.mVibration != vib_on)
{
mOutputControls.mVibration = vib_on;
retval = UpdateOutput();
}
return retval;
}
void cWiiMote::ClearBuffer()
{
memset(mOutputBuffer,0, mOutputBufferSize);
}
bool cWiiMote::SetLEDs(bool led1, bool led2, bool led3, bool led4)
{
const bool no_change = mOutputControls.mLED1 == led1 &&
mOutputControls.mLED2 == led2 &&
mOutputControls.mLED3 == led3 &&
mOutputControls.mLED4 == led4;
if (no_change)
{
return true;
}
mOutputControls.mLED1 = led1;
mOutputControls.mLED2 = led2;
mOutputControls.mLED3 = led3;
mOutputControls.mLED4 = led4;
return UpdateOutput();
}
bool cWiiMote::UpdateOutput()
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_CHANNEL_LED;
mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0) |
(mOutputControls.mLED1 ? 0x1 : 0x0) << 4 |
(mOutputControls.mLED2 ? 0x1 : 0x0) << 5 |
(mOutputControls.mLED3 ? 0x1 : 0x0) << 6 |
(mOutputControls.mLED4 ? 0x1 : 0x0) << 7;
return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
bool cWiiMote::HeartBeat(int timeout)
{
bool retval = true;
int bytes_read = 0;
//most of these reports aren't implemented yet. I don't have a sensor bar or a nunchuck :)
if (mHIDDevice.ReadFromDevice(mInputBuffer,mInputBufferSize,bytes_read) && (bytes_read > 0,timeout))
{
const int channel = mInputBuffer[0];
switch (channel)
{
case INPUT_CHANNEL_EXPANSION_PORT:// 6 Expansion Port change
{
ParseButtonReport(&mInputBuffer[1]);
ParseExpansionReport(&mInputBuffer[2]);
bool restart = mDataStreamRunning;
StopDataStream();
InitNunchuck();
if (restart)
{
retval = StartDataStream();
}
}
break;
case INPUT_CHANNEL_BUTTONS_ONLY:// 2 Buttons only
ParseButtonReport(&mInputBuffer[1]);
break;
case 0x21:// 21 Read data
ParseButtonReport(&mInputBuffer[1]);
ParseReadData(&mInputBuffer[3]);
break;
case INPUT_CHANNEL_WRITE_CONFIRM:// 4 Write data
break;
case 0x31:// 5 Buttons | Motion Sensing Report
ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]);
break;
case 0x32:// 16 Buttons | Expansion Port | IR??
ParseButtonReport(&mInputBuffer[1]);
break;
case INPUT_CHANNEL_MOTION_IR:
ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]);
ParseIRReport(&mInputBuffer[6]);
break;
case INPUT_CHANNEL_MOTION_CHUCK_IR:
ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]);
ParseIRReport(&mInputBuffer[6]);
ParseChuckReport(&mInputBuffer[16]);
break;
case INPUT_CHANNEL_MOTION_CHUCK:
ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]);
ParseChuckReport(&mInputBuffer[6]);
break;
case 0x34:// 21 Buttons | Expansion Port | IR??
case 0x3d:// 21 Buttons | Expansion Port | IR??
ParseButtonReport(&mInputBuffer[1]);
break;
case 0x3e:// 21 Buttons | Motion Sensing Report | IR??
case 0x3f:// 21 Buttons | Motion Sensing Report | IR??
ParseButtonReport(&mInputBuffer[1]);
break;
default:
retval = false;
//unknown report
break;
}
}
return retval;
}
void cWiiMote::ParseExpansionReport(const unsigned char *data)
{
//four bytes long
mLastExpansionReport.mAttachmentPluggedIn = (data[0] & 0x02) != 0;
mLastExpansionReport.mIREnabled = (data[0] & 0x08) != 0;
mLastExpansionReport.mSpeakerEnabled = (data[0] & 0x04) != 0;
mLastExpansionReport.mLED1On = (data[0] & 0x10) != 0;
mLastExpansionReport.mLED2On = (data[0] & 0x20) != 0;
mLastExpansionReport.mLED3On = (data[0] & 0x40) != 0;
mLastExpansionReport.mLED4On = (data[0] & 0x80) != 0;
//two unknown bytes
mLastExpansionReport.mBatteryLevel = data[3];
}
void cWiiMote::ParseButtonReport(const unsigned char * data)
{
//two bytes long
mLastButtonStatus.mA = (data[1] & 0x08) != 0;
mLastButtonStatus.mB = (data[1] & 0x04) != 0;
mLastButtonStatus.m1 = (data[1] & 0x02) != 0;
mLastButtonStatus.m2 = (data[1] & 0x01) != 0;
mLastButtonStatus.mPlus = (data[0] & 0x10) != 0;
mLastButtonStatus.mMinus = (data[1] & 0x10) != 0;
mLastButtonStatus.mHome = (data[1] & 0x80) != 0;
mLastButtonStatus.mUp = (data[0] & 0x08) != 0;
mLastButtonStatus.mDown = (data[0] & 0x04) != 0;
mLastButtonStatus.mLeft = (data[0] & 0x01) != 0;
mLastButtonStatus.mRight = (data[0] & 0x02) != 0;
}
void cWiiMote::ParseMotionReport(const unsigned char * data)
{
//three bytes long
mLastMotionReport.mX = data[0];
mLastMotionReport.mY = data[1];
mLastMotionReport.mZ = data[2];
}
void cWiiMote::PrintStatus() const
{
float wX,wY,wZ;
float cX,cY,cZ;
float sX,sY;
float irX,irY;
wX =wY=wZ=cX=cY=cZ=sX=sY=irX=irY=0.f;
GetCalibratedAcceleration(wX,wY,wZ);
printf("W:[%+1.2f %+1.2f %+1.2f] ",wX,wY,wZ);
if (mNunchuckAttached)
{
GetCalibratedChuckAcceleration(cX,cY,cZ);
printf("N:[%+1.2f %+1.2f %+1.2f] ",cX,cY,cZ);
GetCalibratedChuckStick(sX,sY);
printf("S:[%+1.2f %+1.2f] ",sX,sY);
}
if (mIRRunning)
{
if (GetIRP1(irX,irY))
{
printf("P1:[%+1.2f %+1.2f]",irX,irY);
}
if (GetIRP2(irX,irY))
{
printf("P2:[%+1.2f %+1.2f]",irX,irY);
}
}
//print the button status
if (mLastButtonStatus.m1)
printf("1");
if (mLastButtonStatus.m2)
printf("2");
if (mLastButtonStatus.mA)
printf("A");
if (mLastButtonStatus.mB)
printf("B");
if (mLastButtonStatus.mPlus)
printf("+");
if (mLastButtonStatus.mMinus)
printf("-");
if (mLastButtonStatus.mUp)
printf("U");
if (mLastButtonStatus.mDown)
printf("D");
if (mLastButtonStatus.mLeft)
printf("L");
if (mLastButtonStatus.mRight)
printf("R");
if (mLastButtonStatus.mHome)
printf("H");
if (mNunchuckAttached)
{
if (mLastChuckReport.mButtonZ)
printf("Z");
if (mLastChuckReport.mButtonC)
printf("C");
}
printf("\n");
}
bool cWiiMote::SelectInputChannel(bool continuous, unsigned char channel)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_CHANNEL_REPORT;
mOutputBuffer[1] = (continuous ? REQUEST_CONTINUOUS_REPORTS : REQUEST_SINGLE_REPORTS) | (mOutputControls.mVibration ? 0x1 : 0x0);
mOutputBuffer[2] = channel;
return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
//this may or may not work to read buffers greater than 16 bytes. . . .
bool cWiiMote::IssueReadRequest(unsigned int address, unsigned short size, unsigned char * buffer)
{
bool retval = false;
if (mReadInfo.mReadStatus != tMemReadInfo::READ_PENDING)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_READ_MEMORY;
mOutputBuffer[1] = (((address & 0xff000000) >> 24) & 0xFE) | (mOutputControls.mVibration ? 0x1 : 0x0);
mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
mOutputBuffer[4] = (address & 0xff);
mOutputBuffer[5] = (size & 0xff00) >> 8;
mOutputBuffer[6] = (size & 0xff);
if (mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize))
{
mReadInfo.mReadStatus = tMemReadInfo::READ_PENDING;
mReadInfo.mReadBuffer = buffer;
mReadInfo.mTotalBytesToRead = size;
mReadInfo.mBytesRead =0;
mReadInfo.mBaseAddress = (unsigned short)(address & 0xFFFF);
retval = true;
}
}
return retval;
}
void cWiiMote::ParseReadData(const unsigned char * data)
{
if(mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
{
const bool error = (data[0] & 0x0F) != 0;
if (error)
{
mReadInfo.mReadStatus = tMemReadInfo::READ_ERROR;
}
else
{
unsigned char bytes = (data[0] >> 4)+1;
unsigned short offset = ((unsigned short)data[1] << 8) + data[2];
unsigned int space_left_in_buffer = mReadInfo.mTotalBytesToRead - mReadInfo.mBytesRead;
if (offset == mReadInfo.mBytesRead + mReadInfo.mBaseAddress &&
space_left_in_buffer >= bytes)
{
memcpy(&mReadInfo.mReadBuffer[mReadInfo.mBytesRead],&data[3],bytes);
mReadInfo.mBytesRead+= bytes;
if (mReadInfo.mBytesRead >= mReadInfo.mTotalBytesToRead)
{
mReadInfo.mReadStatus = tMemReadInfo::READ_COMPLETE;
}
}
}
}
}
bool cWiiMote::ReadData(unsigned int address, unsigned short size, unsigned char * buffer)
{
if (IssueReadRequest(address, size,buffer))
{
while (mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
{
if (!HeartBeat(1000))
{
break;
}
}
}
return mReadInfo.mReadStatus == tMemReadInfo::READ_COMPLETE;
}
bool cWiiMote::ReadCalibrationData()
{
bool retval = false;
unsigned char buffer[CALIBRATION_DATA_LENGTH];
if (ReadData(CALIBRATION_ADDRESS, CALIBRATION_DATA_LENGTH,buffer))
{
mAccelCalibrationData.mXZero = buffer[0];
mAccelCalibrationData.mYZero = buffer[1];
mAccelCalibrationData.mZZero = buffer[2];
mAccelCalibrationData.mXG = buffer[4];
mAccelCalibrationData.mYG = buffer[5];
mAccelCalibrationData.mZG = buffer[6];
retval = true;
}
return retval;
}
void cWiiMote::GetCalibratedAcceleration(float & x, float & y, float &z) const
{
x = (mLastMotionReport.mX - mAccelCalibrationData.mXZero) / (float)(mAccelCalibrationData.mXG- mAccelCalibrationData.mXZero);
y = (mLastMotionReport.mY - mAccelCalibrationData.mYZero) / (float)(mAccelCalibrationData.mYG- mAccelCalibrationData.mYZero);
z = (mLastMotionReport.mZ - mAccelCalibrationData.mZZero) / (float)(mAccelCalibrationData.mZG- mAccelCalibrationData.mZZero);
}
void cWiiMote::GetCalibratedChuckAcceleration(float & x, float & y, float &z) const
{
if (!mNunchuckAttached)
{
x = y = z = 0.f;
return;
}
x = (mLastChuckReport.mAccelX - mNunchuckAccelCalibrationData.mXZero) / (float)(mNunchuckAccelCalibrationData.mXG- mNunchuckAccelCalibrationData.mXZero);
y = (mLastChuckReport.mAccelY - mNunchuckAccelCalibrationData.mYZero) / (float)(mNunchuckAccelCalibrationData.mYG- mNunchuckAccelCalibrationData.mYZero);
z = (mLastChuckReport.mAccelZ - mNunchuckAccelCalibrationData.mZZero) / (float)(mNunchuckAccelCalibrationData.mZG- mNunchuckAccelCalibrationData.mZZero);
}
void cWiiMote::GetCalibratedChuckStick(float & x, float & y) const
{
if (!mNunchuckAttached)
{
x = y = 0.f;
return;
}
if (mLastChuckReport.mStickX < mNunchuckStickCalibrationData.mXmid)
{
x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmin) / (float)(mNunchuckStickCalibrationData.mXmid - mNunchuckStickCalibrationData.mXmin)) - 1.f;
}
else
{
x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmid) / (float)(mNunchuckStickCalibrationData.mXmax - mNunchuckStickCalibrationData.mXmid));
}
if (mLastChuckReport.mStickY < mNunchuckStickCalibrationData.mYmid)
{
y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmin) / (float)(mNunchuckStickCalibrationData.mYmid - mNunchuckStickCalibrationData.mYmin)) - 1.f;
}
else
{
y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmid) / (float)(mNunchuckStickCalibrationData.mYmax - mNunchuckStickCalibrationData.mYmid));
}
}
bool cWiiMote::WriteMemory(unsigned int address, unsigned char size, const unsigned char * buffer)
{
bool retval = false;
if (size <= 16)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_WRITE_MEMORY;
mOutputBuffer[1] = (address & 0xff000000) >> 24 | (mOutputControls.mVibration ? 0x1 : 0x0);
mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
mOutputBuffer[4] = (address & 0xff);
mOutputBuffer[5] = size;
memcpy(&mOutputBuffer[6],buffer,size);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
return retval;
}
bool cWiiMote::InitNunchuck()
{
bool retval = false;
//first init the nunchuck, if it is present
if (WriteMemory(NUNCHUCK_INIT_ADDRESS,1,&NUNCHUCK_INIT_VAL))
{
unsigned char buffer[16];
//now try to read the nunchuck's calibration data
if (ReadData(NUNCHUCK_CALIBRATION_ADDRESS,16,buffer))
{
//note that this hasn't worked properly for me yet (I get all 0xff).
/*mNunchuckAccelCalibrationData.mXZero = NunChuckByte(buffer[0]);
mNunchuckAccelCalibrationData.mYZero = NunChuckByte(buffer[1]);
mNunchuckAccelCalibrationData.mZZero = NunChuckByte(buffer[2]);
mNunchuckAccelCalibrationData.mXG = NunChuckByte(buffer[4]);
mNunchuckAccelCalibrationData.mYG = NunChuckByte(buffer[5]);
mNunchuckAccelCalibrationData.mZG = NunChuckByte(buffer[6]);
mNunchuckStickCalibrationData.mXmax = NunChuckByte(buffer[8]);
mNunchuckStickCalibrationData.mXmin = NunChuckByte(buffer[9]);
mNunchuckStickCalibrationData.mXmid = NunChuckByte(buffer[10]);
mNunchuckStickCalibrationData.mYmax = NunChuckByte(buffer[11]);
mNunchuckStickCalibrationData.mYmin = NunChuckByte(buffer[12]);
mNunchuckStickCalibrationData.mYmid = NunChuckByte(buffer[13]);*/
//these are default values from the wiili wiki
mNunchuckAccelCalibrationData.mXZero = 0x7E;
mNunchuckAccelCalibrationData.mYZero = 0x7A;
mNunchuckAccelCalibrationData.mZZero = 0x7D;
mNunchuckAccelCalibrationData.mXG = 0xB0;
mNunchuckAccelCalibrationData.mYG = 0xAF;
mNunchuckAccelCalibrationData.mZG = 0xB1;
mNunchuckStickCalibrationData.mXmax = 0xe5;
mNunchuckStickCalibrationData.mXmin = 0x21;
mNunchuckStickCalibrationData.mXmid = 0x7c;
mNunchuckStickCalibrationData.mYmax = 0xe7;
mNunchuckStickCalibrationData.mYmin = 0x23;
mNunchuckStickCalibrationData.mYmid = 0x7a;
retval = true;
}
}
mNunchuckAttached = retval;
return retval;
}
void cWiiMote::ParseChuckReport(const unsigned char * data)
{
mLastChuckReport.mStickX = NunChuckByte(data[0]);
mLastChuckReport.mStickY = NunChuckByte(data[1]);
mLastChuckReport.mAccelX = NunChuckByte(data[2]);
mLastChuckReport.mAccelY = NunChuckByte(data[3]);
mLastChuckReport.mAccelZ = NunChuckByte(data[4]);
mLastChuckReport.mButtonC = (NunChuckByte(data[5]) & 0x2) == 0;
mLastChuckReport.mButtonZ = (NunChuckByte(data[5]) & 0x1) == 0;
}
bool cWiiMote::EnableIR()
{
bool retval = false;
DisableIR();
if (!mIRRunning)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_ENABLE_IR;
mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
if (retval)
{
mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
if (retval)
{
unsigned char val = 0x1;
retval = WriteMemory(IR_REG_1,1,&val);
}
if (retval)
{
retval = WriteMemory(IR_SENS_ADDR_1,9,IR_SENS_MIDRANGE_PART1);
}
if (retval)
{
retval = WriteMemory(IR_SENS_ADDR_2,2,IR_SENS_MIDRANGE_PART2);
}
if (retval)
{
retval = WriteMemory(IR_REG_2,1,&IR_MODE_EXP);
}
if (retval)
{
unsigned char val = 0x8;
retval = WriteMemory(IR_REG_1,1,&val);
}
mIRRunning = retval;
}
return retval;
}
bool cWiiMote::DisableIR()
{
bool retval = false;
if (mIRRunning)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_ENABLE_IR;
mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
if (retval)
{
mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
mIRRunning = false;
}
return retval;
}
void cWiiMote::ParseIRReport(const unsigned char * data)
{
mLastIRReport.mP1X = data[0] << 2 | (data[2] & 0x30) >>4;
mLastIRReport.mP1Y = data[1] << 2 | (data[2] & 0xc0) >>6;
mLastIRReport.mP1Size = data[2] & 0xf;
mLastIRReport.mP2X = data[3] << 2 | (data[5] & 0x30) >>4;
mLastIRReport.mP2Y = data[4] << 2 | (data[5] & 0xc0) >>6;
mLastIRReport.mP2Size = data[5] & 0xf;
mLastIRReport.mP1Found = !(data[0] == 0xff && data[1] == 0xff && data[2] == 0xff);
mLastIRReport.mP2Found = !(data[3] == 0xff && data[4] == 0xff && data[5] == 0xff);
}
bool cWiiMote::GetIRP1(float &x, float &y) const
{
bool retval = false;
if (mIRRunning && mLastIRReport.mP1Found)
{
x = mLastIRReport.mP1X / 1024.f;
y = mLastIRReport.mP1Y / 1024.f;
retval = true;
}
return retval;
}
bool cWiiMote::GetIRP2(float &x, float &y) const
{
bool retval = false;
if (mIRRunning && mLastIRReport.mP2Found)
{
x = mLastIRReport.mP2X / 1024.f;
y = mLastIRReport.mP2Y / 1024.f;
retval = true;
}
return retval;
}
bool cWiiMote::StartDataStream()
{
bool retval = false;
StopDataStream();
if (mNunchuckAttached)
{
retval =SetReportMode(REPORT_MODE_MOTION_CHUCK_IR);
}
else
{
retval = SetReportMode(REPORT_MODE_MOTION_IR);
}
EnableIR();
mDataStreamRunning = retval;
return retval;
}
bool cWiiMote::StopDataStream()
{
if (mDataStreamRunning)
{
mDataStreamRunning = false;
DisableIR();
SetReportMode(REPORT_MODE_EVENT_BUTTONS);
}
return true;;
}
#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.
//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 "wiimote.h"
#include <stdio.h>
//output channels
const unsigned char OUTPUT_CHANNEL_FORCE_FEEDBACK = 0x13;
const unsigned char OUTPUT_CHANNEL_LED = 0x11;
const unsigned char OUTPUT_CHANNEL_REPORT = 0x12;
const unsigned char OUTPUT_READ_MEMORY = 0x17;
const unsigned char OUTPUT_WRITE_MEMORY = 0x16;
const unsigned char OUTPUT_ENABLE_IR = 0x13;
const unsigned char OUTPUT_ENABLE_IR2 = 0x1a;
//report request types
const unsigned char REQUEST_CONTINUOUS_REPORTS = 0x4;
const unsigned char REQUEST_SINGLE_REPORTS = 0x0;
//input channels
const unsigned char INPUT_CHANNEL_BUTTONS_ONLY = 0x30;
const unsigned char INPUT_CHANNEL_BUTTONS_MOTION = 0x31;
const unsigned char INPUT_CHANNEL_WRITE_CONFIRM = 0x22;
const unsigned char INPUT_CHANNEL_EXPANSION_PORT = 0x20;
const unsigned char INPUT_CHANNEL_MOTION_IR = 0x33;
const unsigned char INPUT_CHANNEL_MOTION_CHUCK_IR = 0x37;
const unsigned char INPUT_CHANNEL_MOTION_CHUCK = 0x35;
//the ID values for a wiimote
const unsigned short mVendorID = 0x057E;
const unsigned short mDeviceID = 0x0306;
//how to find the calibration data for the wiimote
const unsigned short CALIBRATION_ADDRESS = 0x16;
const unsigned short CALIBRATION_DATA_LENGTH = 7;
//nunchuck constants
const unsigned long NUNCHUCK_STATUS_ADDRESS = 0x04A40000;
const unsigned long NUNCHUCK_CALIBRATION_ADDRESS = 0x04A40020;
const unsigned long NUNCHUCK_CALIBRATION_ADDRESS_2 = 0x04A40030;
const unsigned long NUNCHUCK_INIT_ADDRESS= 0x04A40040;
const unsigned long NUNCHUK_ID_ADDRESS = 0x04a400f0;
const unsigned char NUNCHUCK_INIT_VAL= 0x0;
//IR constants
const unsigned long IR_REG_1 = 0x04b00030;
const unsigned long IR_REG_2 = 0x04b00033;
const unsigned long IR_SENS_ADDR_1 = 0x04b00000;
const unsigned long IR_SENS_ADDR_2 = 0x04b0001a;
const unsigned char IR_SENS_MIDRANGE_PART1[] = {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64};
const unsigned char IR_SENS_MIDRANGE_PART2[] = {0x63, 0x03};
const unsigned char IR_MODE_OFF = 0;
const unsigned char IR_MODE_STD = 1;
const unsigned char IR_MODE_EXP = 3;
const unsigned char IR_MODE_FULL = 5;
cWiiMote::cWiiMote()
{
Init();
}
cWiiMote::~cWiiMote()
{
Disconnect();
}
void cWiiMote::Init()
{
mReportMode = REPORT_MODE_EVENT_BUTTONS;
mLastButtonStatus.Init();
mLastExpansionReport.Init();
mLastMotionReport.Init();
mOutputControls.Init();
mReadInfo.Init();
mAccelCalibrationData.Init();
mNunchuckAccelCalibrationData.Init();
mNunchuckStickCalibrationData.Init();
mLastIRReport.Init();
mNunchuckAttached = false;
mIRRunning = false;
mDataStreamRunning = false;
}
bool cWiiMote::SetReportMode(eReportMode mode)
{
mReportMode = mode;
return SendReportMode();
}
bool cWiiMote::SendReportMode()
{
bool continuous = true;
unsigned char channel = INPUT_CHANNEL_BUTTONS_ONLY;
bool check_chuck = false;
switch (mReportMode)
{
case REPORT_MODE_MOTION_IR:
channel = INPUT_CHANNEL_MOTION_IR;
break;
case REPORT_MODE_MOTION_CHUCK_IR:
channel = INPUT_CHANNEL_MOTION_CHUCK_IR;
check_chuck = true;
break;
case REPORT_MODE_MOTION_CHUCK:
channel = INPUT_CHANNEL_MOTION_CHUCK;
check_chuck = true;
break;
case REPORT_MODE_MOTION:
channel = INPUT_CHANNEL_BUTTONS_MOTION;
break;
case REPORT_MODE_EVENT_BUTTONS:
channel = INPUT_CHANNEL_BUTTONS_ONLY;
continuous = false;
break;
default:
break;
}
//check to make sure that there is a chuck attached
// if (check_chuck && !mNunchuckAttached)
// {
// printf("Supposed to check for nunchuck, but couldn't find one!");
// return false;
// }
bool retval = SelectInputChannel(continuous,channel);
return retval;
}
bool cWiiMote::ConnectToDevice(int index)
{
Init();
const bool retval = mHIDDevice.Connect(mDeviceID,mVendorID,index) &&
SetReportMode(REPORT_MODE_MOTION_CHUCK_IR) &&
UpdateOutput() &&
ReadCalibrationData();
if (retval)
{
InitNunchuck();
}
return retval;
}
bool cWiiMote::Disconnect()
{
bool retval = false;
StopDataStream();
if (mHIDDevice.IsConnected())
{
retval = mHIDDevice.Disconnect();
}
return retval;
}
bool cWiiMote::SetVibration(bool vib_on)
{
bool retval = true;
if (mOutputControls.mVibration != vib_on)
{
mOutputControls.mVibration = vib_on;
retval = UpdateOutput();
}
return retval;
}
void cWiiMote::ClearBuffer()
{
memset(mOutputBuffer,0, mOutputBufferSize);
}
bool cWiiMote::SetLEDs(bool led1, bool led2, bool led3, bool led4)
{
const bool no_change = mOutputControls.mLED1 == led1 &&
mOutputControls.mLED2 == led2 &&
mOutputControls.mLED3 == led3 &&
mOutputControls.mLED4 == led4;
if (no_change)
{
return true;
}
mOutputControls.mLED1 = led1;
mOutputControls.mLED2 = led2;
mOutputControls.mLED3 = led3;
mOutputControls.mLED4 = led4;
return UpdateOutput();
}
bool cWiiMote::UpdateOutput()
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_CHANNEL_LED;
mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0) |
(mOutputControls.mLED1 ? 0x1 : 0x0) << 4 |
(mOutputControls.mLED2 ? 0x1 : 0x0) << 5 |
(mOutputControls.mLED3 ? 0x1 : 0x0) << 6 |
(mOutputControls.mLED4 ? 0x1 : 0x0) << 7;
return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
bool cWiiMote::HeartBeat(int timeout)
{
bool retval = true;
int bytes_read = 0;
//most of these reports aren't implemented yet. I don't have a sensor bar or a nunchuck :)
if (mHIDDevice.ReadFromDevice(mInputBuffer,mInputBufferSize,bytes_read) && (bytes_read > 0,timeout))
{
const int channel = mInputBuffer[0];
switch (channel)
{
case INPUT_CHANNEL_EXPANSION_PORT:// 6 Expansion Port change
{
ParseButtonReport(&mInputBuffer[1]);
ParseExpansionReport(&mInputBuffer[2]);
bool restart = mDataStreamRunning;
StopDataStream();
InitNunchuck();
if (restart)
{
retval = StartDataStream();
}
}
break;
case INPUT_CHANNEL_BUTTONS_ONLY:// 2 Buttons only
ParseButtonReport(&mInputBuffer[1]);
break;
case 0x21:// 21 Read data
ParseButtonReport(&mInputBuffer[1]);
ParseReadData(&mInputBuffer[3]);
break;
case INPUT_CHANNEL_WRITE_CONFIRM:// 4 Write data
break;
case 0x31:// 5 Buttons | Motion Sensing Report
ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]);
break;
case 0x32:// 16 Buttons | Expansion Port | IR??
ParseButtonReport(&mInputBuffer[1]);
break;
case INPUT_CHANNEL_MOTION_IR:
ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]);
ParseIRReport(&mInputBuffer[6]);
break;
case INPUT_CHANNEL_MOTION_CHUCK_IR:
ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]);
ParseIRReport(&mInputBuffer[6]);
ParseChuckReport(&mInputBuffer[16]);
break;
case INPUT_CHANNEL_MOTION_CHUCK:
ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]);
ParseChuckReport(&mInputBuffer[6]);
break;
case 0x34:// 21 Buttons | Expansion Port | IR??
case 0x3d:// 21 Buttons | Expansion Port | IR??
ParseButtonReport(&mInputBuffer[1]);
break;
case 0x3e:// 21 Buttons | Motion Sensing Report | IR??
case 0x3f:// 21 Buttons | Motion Sensing Report | IR??
ParseButtonReport(&mInputBuffer[1]);
break;
default:
retval = false;
//unknown report
break;
}
}
return retval;
}
void cWiiMote::ParseExpansionReport(const unsigned char *data)
{
//four bytes long
mLastExpansionReport.mAttachmentPluggedIn = (data[0] & 0x02) != 0;
mLastExpansionReport.mIREnabled = (data[0] & 0x08) != 0;
mLastExpansionReport.mSpeakerEnabled = (data[0] & 0x04) != 0;
mLastExpansionReport.mLED1On = (data[0] & 0x10) != 0;
mLastExpansionReport.mLED2On = (data[0] & 0x20) != 0;
mLastExpansionReport.mLED3On = (data[0] & 0x40) != 0;
mLastExpansionReport.mLED4On = (data[0] & 0x80) != 0;
//two unknown bytes
mLastExpansionReport.mBatteryLevel = data[3];
}
void cWiiMote::ParseButtonReport(const unsigned char * data)
{
//two bytes long
mLastButtonStatus.mA = (data[1] & 0x08) != 0;
mLastButtonStatus.mB = (data[1] & 0x04) != 0;
mLastButtonStatus.m1 = (data[1] & 0x02) != 0;
mLastButtonStatus.m2 = (data[1] & 0x01) != 0;
mLastButtonStatus.mPlus = (data[0] & 0x10) != 0;
mLastButtonStatus.mMinus = (data[1] & 0x10) != 0;
mLastButtonStatus.mHome = (data[1] & 0x80) != 0;
mLastButtonStatus.mUp = (data[0] & 0x08) != 0;
mLastButtonStatus.mDown = (data[0] & 0x04) != 0;
mLastButtonStatus.mLeft = (data[0] & 0x01) != 0;
mLastButtonStatus.mRight = (data[0] & 0x02) != 0;
}
void cWiiMote::ParseMotionReport(const unsigned char * data)
{
//three bytes long
mLastMotionReport.mX = data[0];
mLastMotionReport.mY = data[1];
mLastMotionReport.mZ = data[2];
}
void cWiiMote::PrintStatus() const
{
float wX,wY,wZ;
float cX,cY,cZ;
float sX,sY;
float irX,irY;
wX =wY=wZ=cX=cY=cZ=sX=sY=irX=irY=0.f;
GetCalibratedAcceleration(wX,wY,wZ);
printf("W:[%+1.2f %+1.2f %+1.2f] ",wX,wY,wZ);
if (mNunchuckAttached)
{
GetCalibratedChuckAcceleration(cX,cY,cZ);
printf("N:[%+1.2f %+1.2f %+1.2f] ",cX,cY,cZ);
GetCalibratedChuckStick(sX,sY);
printf("S:[%+1.2f %+1.2f] ",sX,sY);
}
if (mIRRunning)
{
if (GetIRP1(irX,irY))
{
printf("P1:[%+1.2f %+1.2f]",irX,irY);
}
if (GetIRP2(irX,irY))
{
printf("P2:[%+1.2f %+1.2f]",irX,irY);
}
}
//print the button status
if (mLastButtonStatus.m1)
printf("1");
if (mLastButtonStatus.m2)
printf("2");
if (mLastButtonStatus.mA)
printf("A");
if (mLastButtonStatus.mB)
printf("B");
if (mLastButtonStatus.mPlus)
printf("+");
if (mLastButtonStatus.mMinus)
printf("-");
if (mLastButtonStatus.mUp)
printf("U");
if (mLastButtonStatus.mDown)
printf("D");
if (mLastButtonStatus.mLeft)
printf("L");
if (mLastButtonStatus.mRight)
printf("R");
if (mLastButtonStatus.mHome)
printf("H");
if (mNunchuckAttached)
{
if (mLastChuckReport.mButtonZ)
printf("Z");
if (mLastChuckReport.mButtonC)
printf("C");
}
printf("\n");
}
bool cWiiMote::SelectInputChannel(bool continuous, unsigned char channel)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_CHANNEL_REPORT;
mOutputBuffer[1] = (continuous ? REQUEST_CONTINUOUS_REPORTS : REQUEST_SINGLE_REPORTS) | (mOutputControls.mVibration ? 0x1 : 0x0);
mOutputBuffer[2] = channel;
return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
//this may or may not work to read buffers greater than 16 bytes. . . .
bool cWiiMote::IssueReadRequest(unsigned int address, unsigned short size, unsigned char * buffer)
{
bool retval = false;
if (mReadInfo.mReadStatus != tMemReadInfo::READ_PENDING)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_READ_MEMORY;
mOutputBuffer[1] = (((address & 0xff000000) >> 24) & 0xFE) | (mOutputControls.mVibration ? 0x1 : 0x0);
mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
mOutputBuffer[4] = (address & 0xff);
mOutputBuffer[5] = (size & 0xff00) >> 8;
mOutputBuffer[6] = (size & 0xff);
if (mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize))
{
mReadInfo.mReadStatus = tMemReadInfo::READ_PENDING;
mReadInfo.mReadBuffer = buffer;
mReadInfo.mTotalBytesToRead = size;
mReadInfo.mBytesRead =0;
mReadInfo.mBaseAddress = (unsigned short)(address & 0xFFFF);
retval = true;
}
}
return retval;
}
void cWiiMote::ParseReadData(const unsigned char * data)
{
if(mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
{
const bool error = (data[0] & 0x0F) != 0;
if (error)
{
mReadInfo.mReadStatus = tMemReadInfo::READ_ERROR;
}
else
{
unsigned char bytes = (data[0] >> 4)+1;
unsigned short offset = ((unsigned short)data[1] << 8) + data[2];
unsigned int space_left_in_buffer = mReadInfo.mTotalBytesToRead - mReadInfo.mBytesRead;
if (offset == mReadInfo.mBytesRead + mReadInfo.mBaseAddress &&
space_left_in_buffer >= bytes)
{
memcpy(&mReadInfo.mReadBuffer[mReadInfo.mBytesRead],&data[3],bytes);
mReadInfo.mBytesRead+= bytes;
if (mReadInfo.mBytesRead >= mReadInfo.mTotalBytesToRead)
{
mReadInfo.mReadStatus = tMemReadInfo::READ_COMPLETE;
}
}
}
}
}
bool cWiiMote::ReadData(unsigned int address, unsigned short size, unsigned char * buffer)
{
if (IssueReadRequest(address, size,buffer))
{
while (mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
{
if (!HeartBeat(1000))
{
break;
}
}
}
return mReadInfo.mReadStatus == tMemReadInfo::READ_COMPLETE;
}
bool cWiiMote::ReadCalibrationData()
{
bool retval = false;
unsigned char buffer[CALIBRATION_DATA_LENGTH];
if (ReadData(CALIBRATION_ADDRESS, CALIBRATION_DATA_LENGTH,buffer))
{
mAccelCalibrationData.mXZero = buffer[0];
mAccelCalibrationData.mYZero = buffer[1];
mAccelCalibrationData.mZZero = buffer[2];
mAccelCalibrationData.mXG = buffer[4];
mAccelCalibrationData.mYG = buffer[5];
mAccelCalibrationData.mZG = buffer[6];
retval = true;
}
return retval;
}
void cWiiMote::GetCalibratedAcceleration(float & x, float & y, float &z) const
{
x = (mLastMotionReport.mX - mAccelCalibrationData.mXZero) / (float)(mAccelCalibrationData.mXG- mAccelCalibrationData.mXZero);
y = (mLastMotionReport.mY - mAccelCalibrationData.mYZero) / (float)(mAccelCalibrationData.mYG- mAccelCalibrationData.mYZero);
z = (mLastMotionReport.mZ - mAccelCalibrationData.mZZero) / (float)(mAccelCalibrationData.mZG- mAccelCalibrationData.mZZero);
}
void cWiiMote::GetCalibratedChuckAcceleration(float & x, float & y, float &z) const
{
if (!mNunchuckAttached)
{
x = y = z = 0.f;
return;
}
x = (mLastChuckReport.mAccelX - mNunchuckAccelCalibrationData.mXZero) / (float)(mNunchuckAccelCalibrationData.mXG- mNunchuckAccelCalibrationData.mXZero);
y = (mLastChuckReport.mAccelY - mNunchuckAccelCalibrationData.mYZero) / (float)(mNunchuckAccelCalibrationData.mYG- mNunchuckAccelCalibrationData.mYZero);
z = (mLastChuckReport.mAccelZ - mNunchuckAccelCalibrationData.mZZero) / (float)(mNunchuckAccelCalibrationData.mZG- mNunchuckAccelCalibrationData.mZZero);
}
void cWiiMote::GetCalibratedChuckStick(float & x, float & y) const
{
if (!mNunchuckAttached)
{
x = y = 0.f;
return;
}
if (mLastChuckReport.mStickX < mNunchuckStickCalibrationData.mXmid)
{
x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmin) / (float)(mNunchuckStickCalibrationData.mXmid - mNunchuckStickCalibrationData.mXmin)) - 1.f;
}
else
{
x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmid) / (float)(mNunchuckStickCalibrationData.mXmax - mNunchuckStickCalibrationData.mXmid));
}
if (mLastChuckReport.mStickY < mNunchuckStickCalibrationData.mYmid)
{
y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmin) / (float)(mNunchuckStickCalibrationData.mYmid - mNunchuckStickCalibrationData.mYmin)) - 1.f;
}
else
{
y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmid) / (float)(mNunchuckStickCalibrationData.mYmax - mNunchuckStickCalibrationData.mYmid));
}
}
bool cWiiMote::WriteMemory(unsigned int address, unsigned char size, const unsigned char * buffer)
{
bool retval = false;
if (size <= 16)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_WRITE_MEMORY;
mOutputBuffer[1] = (address & 0xff000000) >> 24 | (mOutputControls.mVibration ? 0x1 : 0x0);
mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
mOutputBuffer[4] = (address & 0xff);
mOutputBuffer[5] = size;
memcpy(&mOutputBuffer[6],buffer,size);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
return retval;
}
bool cWiiMote::InitNunchuck()
{
bool retval = false;
//first init the nunchuck, if it is present
if (WriteMemory(NUNCHUCK_INIT_ADDRESS,1,&NUNCHUCK_INIT_VAL))
{
unsigned char buffer[16];
//now try to read the nunchuck's calibration data
if (ReadData(NUNCHUCK_CALIBRATION_ADDRESS,16,buffer))
{
//note that this hasn't worked properly for me yet (I get all 0xff).
/*mNunchuckAccelCalibrationData.mXZero = NunChuckByte(buffer[0]);
mNunchuckAccelCalibrationData.mYZero = NunChuckByte(buffer[1]);
mNunchuckAccelCalibrationData.mZZero = NunChuckByte(buffer[2]);
mNunchuckAccelCalibrationData.mXG = NunChuckByte(buffer[4]);
mNunchuckAccelCalibrationData.mYG = NunChuckByte(buffer[5]);
mNunchuckAccelCalibrationData.mZG = NunChuckByte(buffer[6]);
mNunchuckStickCalibrationData.mXmax = NunChuckByte(buffer[8]);
mNunchuckStickCalibrationData.mXmin = NunChuckByte(buffer[9]);
mNunchuckStickCalibrationData.mXmid = NunChuckByte(buffer[10]);
mNunchuckStickCalibrationData.mYmax = NunChuckByte(buffer[11]);
mNunchuckStickCalibrationData.mYmin = NunChuckByte(buffer[12]);
mNunchuckStickCalibrationData.mYmid = NunChuckByte(buffer[13]);*/
//these are default values from the wiili wiki
mNunchuckAccelCalibrationData.mXZero = 0x7E;
mNunchuckAccelCalibrationData.mYZero = 0x7A;
mNunchuckAccelCalibrationData.mZZero = 0x7D;
mNunchuckAccelCalibrationData.mXG = 0xB0;
mNunchuckAccelCalibrationData.mYG = 0xAF;
mNunchuckAccelCalibrationData.mZG = 0xB1;
mNunchuckStickCalibrationData.mXmax = 0xe5;
mNunchuckStickCalibrationData.mXmin = 0x21;
mNunchuckStickCalibrationData.mXmid = 0x7c;
mNunchuckStickCalibrationData.mYmax = 0xe7;
mNunchuckStickCalibrationData.mYmin = 0x23;
mNunchuckStickCalibrationData.mYmid = 0x7a;
retval = true;
}
}
mNunchuckAttached = retval;
return retval;
}
void cWiiMote::ParseChuckReport(const unsigned char * data)
{
mLastChuckReport.mStickX = NunChuckByte(data[0]);
mLastChuckReport.mStickY = NunChuckByte(data[1]);
mLastChuckReport.mAccelX = NunChuckByte(data[2]);
mLastChuckReport.mAccelY = NunChuckByte(data[3]);
mLastChuckReport.mAccelZ = NunChuckByte(data[4]);
mLastChuckReport.mButtonC = (NunChuckByte(data[5]) & 0x2) == 0;
mLastChuckReport.mButtonZ = (NunChuckByte(data[5]) & 0x1) == 0;
}
bool cWiiMote::EnableIR()
{
bool retval = false;
DisableIR();
if (!mIRRunning)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_ENABLE_IR;
mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
if (retval)
{
mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
if (retval)
{
unsigned char val = 0x1;
retval = WriteMemory(IR_REG_1,1,&val);
}
if (retval)
{
retval = WriteMemory(IR_SENS_ADDR_1,9,IR_SENS_MIDRANGE_PART1);
}
if (retval)
{
retval = WriteMemory(IR_SENS_ADDR_2,2,IR_SENS_MIDRANGE_PART2);
}
if (retval)
{
retval = WriteMemory(IR_REG_2,1,&IR_MODE_EXP);
}
if (retval)
{
unsigned char val = 0x8;
retval = WriteMemory(IR_REG_1,1,&val);
}
mIRRunning = retval;
}
return retval;
}
bool cWiiMote::DisableIR()
{
bool retval = false;
if (mIRRunning)
{
ClearBuffer();
mOutputBuffer[0] = OUTPUT_ENABLE_IR;
mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
if (retval)
{
mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
}
mIRRunning = false;
}
return retval;
}
void cWiiMote::ParseIRReport(const unsigned char * data)
{
mLastIRReport.mP1X = data[0] << 2 | (data[2] & 0x30) >>4;
mLastIRReport.mP1Y = data[1] << 2 | (data[2] & 0xc0) >>6;
mLastIRReport.mP1Size = data[2] & 0xf;
mLastIRReport.mP2X = data[3] << 2 | (data[5] & 0x30) >>4;
mLastIRReport.mP2Y = data[4] << 2 | (data[5] & 0xc0) >>6;
mLastIRReport.mP2Size = data[5] & 0xf;
mLastIRReport.mP1Found = !(data[0] == 0xff && data[1] == 0xff && data[2] == 0xff);
mLastIRReport.mP2Found = !(data[3] == 0xff && data[4] == 0xff && data[5] == 0xff);
}
bool cWiiMote::GetIRP1(float &x, float &y) const
{
bool retval = false;
if (mIRRunning && mLastIRReport.mP1Found)
{
x = mLastIRReport.mP1X / 1024.f;
y = mLastIRReport.mP1Y / 1024.f;
retval = true;
}
return retval;
}
bool cWiiMote::GetIRP2(float &x, float &y) const
{
bool retval = false;
if (mIRRunning && mLastIRReport.mP2Found)
{
x = mLastIRReport.mP2X / 1024.f;
y = mLastIRReport.mP2Y / 1024.f;
retval = true;
}
return retval;
}
bool cWiiMote::StartDataStream()
{
bool retval = false;
StopDataStream();
if (mNunchuckAttached)
{
retval =SetReportMode(REPORT_MODE_MOTION_CHUCK_IR);
}
else
{
retval = SetReportMode(REPORT_MODE_MOTION_IR);
}
EnableIR();
mDataStreamRunning = retval;
return retval;
}
bool cWiiMote::StopDataStream()
{
if (mDataStreamRunning)
{
mDataStreamRunning = false;
DisableIR();
SetReportMode(REPORT_MODE_EVENT_BUTTONS);
}
return true;;
}
#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 WIIMOTE_H
#define WIIMOTE_H
#include "hiddevice.h"
class cWiiMote
{
public:
cWiiMote();
~cWiiMote();
//connection management
bool ConnectToDevice(int index = 0);
bool Disconnect();
bool IsConnected() const {return mHIDDevice.IsConnected();}
bool StartDataStream();
bool StopDataStream();
bool IsNunChuckAttached() { return mNunchuckAttached; }
//this is the wiimote message pump. It should probably be called in loop from a thread
bool HeartBeat(int timeout = 1);
bool SetVibration(bool vib_on);
bool SetLEDs(bool led1, bool led2, bool led3, bool led4);
//Querying functions and structures:
void GetCalibratedAcceleration(float & x, float & y, float &z) const;
void GetCalibratedChuckAcceleration(float & x, float & y, float &z) const;
void GetCalibratedChuckStick(float & x, float & y) const;
bool GetIRP1(float &x, float &y) const;
bool GetIRP2(float &x, float &y) const;
struct tExpansionReport
{
bool mAttachmentPluggedIn;
bool mIREnabled;
bool mSpeakerEnabled;
bool mLED1On;
bool mLED2On;
bool mLED3On;
bool mLED4On;
unsigned char mBatteryLevel;
void Init()
{
mAttachmentPluggedIn = false;
mIREnabled = false;
mSpeakerEnabled = false;
mLED1On = false;
mLED2On = false;
mLED3On = false;
mLED4On = false;
mBatteryLevel = 0;
}
};
struct tButtonStatus
{
bool mA;
bool mB;
bool m1;
bool m2;
bool mPlus;
bool mMinus;
bool mHome;
bool mUp;
bool mDown;
bool mLeft;
bool mRight;
void Init()
{
mA = mB = m1 = m2 = mPlus = mMinus = mHome = mUp = mDown = mLeft = mRight = false;
}
};
struct tMotionReport
{
unsigned char mX;
unsigned char mY;
unsigned char mZ;
void Init()
{
mX = mY = mZ = 0;
}
};
struct tChuckReport
{
unsigned char mStickX;
unsigned char mStickY;
unsigned char mAccelX;
unsigned char mAccelY;
unsigned char mAccelZ;
bool mButtonC;
bool mButtonZ;
void Init()
{
mStickX=mStickY=mAccelX=mAccelY=mAccelZ=0;
mButtonC = mButtonZ = false;
};
};
struct tIRReport
{
unsigned short mP1X;
unsigned short mP1Y;
unsigned short mP2X;
unsigned short mP2Y;
unsigned char mP1Size;
unsigned char mP2Size;
bool mP1Found;
bool mP2Found;
void Init()
{
mP1X = mP1Y = mP2X = mP2Y = mP1Size = mP2Size = 0;
mP1Found = mP2Found = false;
}
};
const tButtonStatus & GetLastButtonStatus() const {return mLastButtonStatus;}
const tChuckReport & GetLastChuckReport() const {return mLastChuckReport;}
const tMotionReport & GetLastMotionReport() const { return mLastMotionReport;}
const tExpansionReport & GetLastExpansionReport() const { return mLastExpansionReport;}
const tIRReport & GetLastIRReport() const { return mLastIRReport;}
//debugging functions:
void PrintStatus() const;
private:
//parsing functions for input reports
void ParseExpansionReport(const unsigned char * data);
void ParseButtonReport(const unsigned char * data);
void ParseMotionReport(const unsigned char * data);
void ParseReadData(const unsigned char * data);
void ParseChuckReport(const unsigned char * data);
void ParseIRReport(const unsigned char * data);
//tell the wiimote how to send data
enum eReportMode
{
REPORT_MODE_EVENT_BUTTONS,
REPORT_MODE_MOTION,
REPORT_MODE_MOTION_CHUCK,
REPORT_MODE_MOTION_IR,
REPORT_MODE_MOTION_CHUCK_IR
};
bool SetReportMode(eReportMode mode);
//housekeeping functions
void Init();
void ClearBuffer();
//low level tasks
bool SelectInputChannel(bool continuous, unsigned char channel);
bool UpdateOutput();
bool ReadMemory(unsigned int address, unsigned short size, unsigned char * buffer) const;
bool WriteMemory(unsigned int address, unsigned char size, const unsigned char * buffer);
bool ReadData(unsigned int address, unsigned short size, unsigned char * buffer);
bool IssueReadRequest(unsigned int address, unsigned short size, unsigned char * buffer);
bool ReadCalibrationData();
bool SendReportMode();
bool InitNunchuck();
bool EnableIR();
bool DisableIR();
static inline unsigned char NunChuckByte(unsigned char in) {return (in ^ 0x17)+0x17;}
//flash reading vars
struct tMemReadInfo
{
enum eReadStatus
{
READ_PENDING,
READ_NONE,
READ_COMPLETE,
READ_ERROR
} mReadStatus;
unsigned char * mReadBuffer;
unsigned short mTotalBytesToRead;
unsigned short mBytesRead;
unsigned short mBaseAddress;
void Init()
{
mReadStatus = READ_NONE;
mReadBuffer = NULL;
mTotalBytesToRead = 0;
mBytesRead = 0;
mBaseAddress = 0;
}
} mReadInfo;
//calibration data for the wiimote
struct tAccelCalibrationData
{
unsigned char mXZero;
unsigned char mYZero;
unsigned char mZZero;
unsigned char mXG;
unsigned char mYG;
unsigned char mZG;
void Init()
{
mXZero = mYZero = mZZero = mXG = mYG = mZG= 0;
}
} ;
struct tStickCalibrationData
{
unsigned char mXmin;
unsigned char mXmid;
unsigned char mXmax;
unsigned char mYmin;
unsigned char mYmid;
unsigned char mYmax;
void Init()
{
mXmax = mYmax = mXmin = mYmin = mXmid = mYmid =0;
}
};
tAccelCalibrationData mAccelCalibrationData;
tAccelCalibrationData mNunchuckAccelCalibrationData;
tStickCalibrationData mNunchuckStickCalibrationData;
//output requests
struct tOutputControls
{
bool mVibration;
bool mLED1;
bool mLED2;
bool mLED3;
bool mLED4;
void Init()
{
mVibration = mLED1 = mLED2= mLED3= mLED4 = false;
}
};
//input states
tExpansionReport mLastExpansionReport;
tButtonStatus mLastButtonStatus;
tMotionReport mLastMotionReport;
tChuckReport mLastChuckReport;
tIRReport mLastIRReport;
//output states
tOutputControls mOutputControls;
eReportMode mReportMode;
//our communications device
cHIDDevice mHIDDevice;
bool mNunchuckAttached;
bool mIRRunning;
bool mDataStreamRunning;
//buffers for input/output
static const int mOutputBufferSize = 22;
unsigned char mOutputBuffer[mOutputBufferSize];
static const int mInputBufferSize = 22;
unsigned char mInputBuffer[mInputBufferSize];
};
#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 WIIMOTE_H
#define WIIMOTE_H
#include "hiddevice.h"
class cWiiMote
{
public:
cWiiMote();
~cWiiMote();
//connection management
bool ConnectToDevice(int index = 0);
bool Disconnect();
bool IsConnected() const {return mHIDDevice.IsConnected();}
bool StartDataStream();
bool StopDataStream();
bool IsNunChuckAttached() { return mNunchuckAttached; }
//this is the wiimote message pump. It should probably be called in loop from a thread
bool HeartBeat(int timeout = 1);
bool SetVibration(bool vib_on);
bool SetLEDs(bool led1, bool led2, bool led3, bool led4);
//Querying functions and structures:
void GetCalibratedAcceleration(float & x, float & y, float &z) const;
void GetCalibratedChuckAcceleration(float & x, float & y, float &z) const;
void GetCalibratedChuckStick(float & x, float & y) const;
bool GetIRP1(float &x, float &y) const;
bool GetIRP2(float &x, float &y) const;
struct tExpansionReport
{
bool mAttachmentPluggedIn;
bool mIREnabled;
bool mSpeakerEnabled;
bool mLED1On;
bool mLED2On;
bool mLED3On;
bool mLED4On;
unsigned char mBatteryLevel;
void Init()
{
mAttachmentPluggedIn = false;
mIREnabled = false;
mSpeakerEnabled = false;
mLED1On = false;
mLED2On = false;
mLED3On = false;
mLED4On = false;
mBatteryLevel = 0;
}
};
struct tButtonStatus
{
bool mA;
bool mB;
bool m1;
bool m2;
bool mPlus;
bool mMinus;
bool mHome;
bool mUp;
bool mDown;
bool mLeft;
bool mRight;
void Init()
{
mA = mB = m1 = m2 = mPlus = mMinus = mHome = mUp = mDown = mLeft = mRight = false;
}
};
struct tMotionReport
{
unsigned char mX;
unsigned char mY;
unsigned char mZ;
void Init()
{
mX = mY = mZ = 0;
}
};
struct tChuckReport
{
unsigned char mStickX;
unsigned char mStickY;
unsigned char mAccelX;
unsigned char mAccelY;
unsigned char mAccelZ;
bool mButtonC;
bool mButtonZ;
void Init()
{
mStickX=mStickY=mAccelX=mAccelY=mAccelZ=0;
mButtonC = mButtonZ = false;
};
};
struct tIRReport
{
unsigned short mP1X;
unsigned short mP1Y;
unsigned short mP2X;
unsigned short mP2Y;
unsigned char mP1Size;
unsigned char mP2Size;
bool mP1Found;
bool mP2Found;
void Init()
{
mP1X = mP1Y = mP2X = mP2Y = mP1Size = mP2Size = 0;
mP1Found = mP2Found = false;
}
};
const tButtonStatus & GetLastButtonStatus() const {return mLastButtonStatus;}
const tChuckReport & GetLastChuckReport() const {return mLastChuckReport;}
const tMotionReport & GetLastMotionReport() const { return mLastMotionReport;}
const tExpansionReport & GetLastExpansionReport() const { return mLastExpansionReport;}
const tIRReport & GetLastIRReport() const { return mLastIRReport;}
//debugging functions:
void PrintStatus() const;
private:
//parsing functions for input reports
void ParseExpansionReport(const unsigned char * data);
void ParseButtonReport(const unsigned char * data);
void ParseMotionReport(const unsigned char * data);
void ParseReadData(const unsigned char * data);
void ParseChuckReport(const unsigned char * data);
void ParseIRReport(const unsigned char * data);
//tell the wiimote how to send data
enum eReportMode
{
REPORT_MODE_EVENT_BUTTONS,
REPORT_MODE_MOTION,
REPORT_MODE_MOTION_CHUCK,
REPORT_MODE_MOTION_IR,
REPORT_MODE_MOTION_CHUCK_IR
};
bool SetReportMode(eReportMode mode);
//housekeeping functions
void Init();
void ClearBuffer();
//low level tasks
bool SelectInputChannel(bool continuous, unsigned char channel);
bool UpdateOutput();
bool ReadMemory(unsigned int address, unsigned short size, unsigned char * buffer) const;
bool WriteMemory(unsigned int address, unsigned char size, const unsigned char * buffer);
bool ReadData(unsigned int address, unsigned short size, unsigned char * buffer);
bool IssueReadRequest(unsigned int address, unsigned short size, unsigned char * buffer);
bool ReadCalibrationData();
bool SendReportMode();
bool InitNunchuck();
bool EnableIR();
bool DisableIR();
static inline unsigned char NunChuckByte(unsigned char in) {return (in ^ 0x17)+0x17;}
//flash reading vars
struct tMemReadInfo
{
enum eReadStatus
{
READ_PENDING,
READ_NONE,
READ_COMPLETE,
READ_ERROR
} mReadStatus;
unsigned char * mReadBuffer;
unsigned short mTotalBytesToRead;
unsigned short mBytesRead;
unsigned short mBaseAddress;
void Init()
{
mReadStatus = READ_NONE;
mReadBuffer = NULL;
mTotalBytesToRead = 0;
mBytesRead = 0;
mBaseAddress = 0;
}
} mReadInfo;
//calibration data for the wiimote
struct tAccelCalibrationData
{
unsigned char mXZero;
unsigned char mYZero;
unsigned char mZZero;
unsigned char mXG;
unsigned char mYG;
unsigned char mZG;
void Init()
{
mXZero = mYZero = mZZero = mXG = mYG = mZG= 0;
}
} ;
struct tStickCalibrationData
{
unsigned char mXmin;
unsigned char mXmid;
unsigned char mXmax;
unsigned char mYmin;
unsigned char mYmid;
unsigned char mYmax;
void Init()
{
mXmax = mYmax = mXmin = mYmin = mXmid = mYmid =0;
}
};
tAccelCalibrationData mAccelCalibrationData;
tAccelCalibrationData mNunchuckAccelCalibrationData;
tStickCalibrationData mNunchuckStickCalibrationData;
//output requests
struct tOutputControls
{
bool mVibration;
bool mLED1;
bool mLED2;
bool mLED3;
bool mLED4;
void Init()
{
mVibration = mLED1 = mLED2= mLED3= mLED4 = false;
}
};
//input states
tExpansionReport mLastExpansionReport;
tButtonStatus mLastButtonStatus;
tMotionReport mLastMotionReport;
tChuckReport mLastChuckReport;
tIRReport mLastIRReport;
//output states
tOutputControls mOutputControls;
eReportMode mReportMode;
//our communications device
cHIDDevice mHIDDevice;
bool mNunchuckAttached;
bool mIRRunning;
bool mDataStreamRunning;
//buffers for input/output
static const int mOutputBufferSize = 22;
unsigned char mOutputBuffer[mOutputBufferSize];
static const int mInputBufferSize = 22;
unsigned char mInputBuffer[mInputBufferSize];
};
#endif
#endif
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