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 The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "win32/Win32InputManager.h" #include "win32/Win32InputManager.h"
#include "win32/Win32KeyBoard.h" #include "win32/Win32KeyBoard.h"
#include "win32/Win32Mouse.h" #include "win32/Win32Mouse.h"
#include "win32/Win32JoyStick.h" #include "win32/Win32JoyStick.h"
#include "OISException.h" #include "OISException.h"
using namespace OIS; using namespace OIS;
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
Win32InputManager::Win32InputManager() : InputManager("Win32InputManager") Win32InputManager::Win32InputManager() : InputManager("Win32InputManager")
{ {
hWnd = 0; hWnd = 0;
mDirectInput = 0; mDirectInput = 0;
kbSettings = 0; kbSettings = 0;
mouseSettings = 0; mouseSettings = 0;
joySettings = 0; joySettings = 0;
joySticks = 0; joySticks = 0;
keyboardUsed = mouseUsed = false; keyboardUsed = mouseUsed = false;
//Setup our internal factories //Setup our internal factories
mFactories.push_back(this); mFactories.push_back(this);
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
Win32InputManager::~Win32InputManager() Win32InputManager::~Win32InputManager()
{ {
if( mDirectInput ) if( mDirectInput )
{ {
mDirectInput->Release(); mDirectInput->Release();
mDirectInput = 0; mDirectInput = 0;
} }
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
void Win32InputManager::_initialize( ParamList &paramList ) void Win32InputManager::_initialize( ParamList &paramList )
{ {
HINSTANCE hInst = 0; HINSTANCE hInst = 0;
HRESULT hr; HRESULT hr;
//First of all, get the Windows Handle and Instance //First of all, get the Windows Handle and Instance
ParamList::iterator i = paramList.find("WINDOW"); ParamList::iterator i = paramList.find("WINDOW");
if( i == paramList.end() ) if( i == paramList.end() )
OIS_EXCEPT( E_InvalidParam, "Win32InputManager::Win32InputManager >> No HWND found!" ); OIS_EXCEPT( E_InvalidParam, "Win32InputManager::Win32InputManager >> No HWND found!" );
// Get number as 64 bit and then convert. Handles the case of 32 or 64 bit HWND // Get number as 64 bit and then convert. Handles the case of 32 or 64 bit HWND
unsigned __int64 handle = _strtoui64(i->second.c_str(), 0, 10); unsigned __int64 handle = _strtoui64(i->second.c_str(), 0, 10);
hWnd = (HWND)handle; hWnd = (HWND)handle;
if( IsWindow(hWnd) == 0 ) if( IsWindow(hWnd) == 0 )
OIS_EXCEPT( E_General, "Win32InputManager::Win32InputManager >> The sent HWND is not valid!"); OIS_EXCEPT( E_General, "Win32InputManager::Win32InputManager >> The sent HWND is not valid!");
hInst = GetModuleHandle(0); hInst = GetModuleHandle(0);
//Create the device //Create the device
hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&mDirectInput, NULL ); hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&mDirectInput, NULL );
if (FAILED(hr)) if (FAILED(hr))
OIS_EXCEPT( E_General, "Win32InputManager::Win32InputManager >> Not able to init DirectX8 Input!"); OIS_EXCEPT( E_General, "Win32InputManager::Win32InputManager >> Not able to init DirectX8 Input!");
//Ok, now we have DirectInput, parse whatever extra settings were sent to us //Ok, now we have DirectInput, parse whatever extra settings were sent to us
_parseConfigSettings( paramList ); _parseConfigSettings( paramList );
// Enumerate devices ... // Enumerate devices ...
_enumerateDevices(); _enumerateDevices();
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
void Win32InputManager::_parseConfigSettings( ParamList &paramList ) void Win32InputManager::_parseConfigSettings( ParamList &paramList )
{ {
//Here we pick up settings such as a device's cooperation mode //Here we pick up settings such as a device's cooperation mode
std::map<std::string, DWORD> temp; std::map<std::string, DWORD> temp;
temp["DISCL_BACKGROUND"] = DISCL_BACKGROUND; temp["DISCL_BACKGROUND"] = DISCL_BACKGROUND;
temp["DISCL_EXCLUSIVE"] = DISCL_EXCLUSIVE; temp["DISCL_EXCLUSIVE"] = DISCL_EXCLUSIVE;
temp["DISCL_FOREGROUND"] = DISCL_FOREGROUND; temp["DISCL_FOREGROUND"] = DISCL_FOREGROUND;
temp["DISCL_NONEXCLUSIVE"] = DISCL_NONEXCLUSIVE; temp["DISCL_NONEXCLUSIVE"] = DISCL_NONEXCLUSIVE;
temp["DISCL_NOWINKEY"] = DISCL_NOWINKEY; temp["DISCL_NOWINKEY"] = DISCL_NOWINKEY;
//Check for pairs: ie. ("w32_keyboard","DISCL_NOWINKEY")("w32_keyboard","DISCL_FOREGROUND") //Check for pairs: ie. ("w32_keyboard","DISCL_NOWINKEY")("w32_keyboard","DISCL_FOREGROUND")
ParamList::iterator i = paramList.begin(), e = paramList.end(); ParamList::iterator i = paramList.begin(), e = paramList.end();
for( ; i != e; ++i ) for( ; i != e; ++i )
{ {
if( i->first == "w32_keyboard" ) if( i->first == "w32_keyboard" )
kbSettings |= temp[i->second]; kbSettings |= temp[i->second];
else if( i->first == "w32_mouse" ) else if( i->first == "w32_mouse" )
mouseSettings |= temp[i->second]; mouseSettings |= temp[i->second];
else if( i->first == "w32_joystick" ) else if( i->first == "w32_joystick" )
joySettings |= temp[i->second]; joySettings |= temp[i->second];
} }
if( kbSettings == 0 ) kbSettings = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY; if( kbSettings == 0 ) kbSettings = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY;
if( mouseSettings == 0 ) mouseSettings = DISCL_FOREGROUND | DISCL_EXCLUSIVE; if( mouseSettings == 0 ) mouseSettings = DISCL_FOREGROUND | DISCL_EXCLUSIVE;
if( joySettings == 0 ) joySettings = DISCL_FOREGROUND | DISCL_EXCLUSIVE; if( joySettings == 0 ) joySettings = DISCL_FOREGROUND | DISCL_EXCLUSIVE;
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
void Win32InputManager::_enumerateDevices() void Win32InputManager::_enumerateDevices()
{ {
//Enumerate all attached devices //Enumerate all attached devices
mDirectInput->EnumDevices(NULL, _DIEnumDevCallback, this, DIEDFL_ATTACHEDONLY); mDirectInput->EnumDevices(NULL, _DIEnumDevCallback, this, DIEDFL_ATTACHEDONLY);
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
//let's check how many possible XInput devices we may have (max 4)... //let's check how many possible XInput devices we may have (max 4)...
for(int i = 0; i < 3; ++i) for(int i = 0; i < 3; ++i)
{ {
XINPUT_STATE state; XINPUT_STATE state;
if(XInputGetState(i, &state) != ERROR_DEVICE_NOT_CONNECTED) if(XInputGetState(i, &state) != ERROR_DEVICE_NOT_CONNECTED)
{ //Once we found 1, just check our whole list against devices { //Once we found 1, just check our whole list against devices
Win32JoyStick::CheckXInputDevices(unusedJoyStickList); Win32JoyStick::CheckXInputDevices(unusedJoyStickList);
break; break;
} }
} }
#endif #endif
} }
//--------------------------------------------------------------------------------// //--------------------------------------------------------------------------------//
BOOL CALLBACK Win32InputManager::_DIEnumDevCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) BOOL CALLBACK Win32InputManager::_DIEnumDevCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
{ {
Win32InputManager *_this_ = static_cast<Win32InputManager*>(pvRef); Win32InputManager *_this_ = static_cast<Win32InputManager*>(pvRef);
// Register only game devices (keyboard and mouse are managed differently). // Register only game devices (keyboard and mouse are managed differently).
if( GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_JOYSTICK || if( GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_JOYSTICK ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_GAMEPAD || GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_GAMEPAD ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_1STPERSON || GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_1STPERSON ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_DRIVING || GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_DRIVING ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_FLIGHT || GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_FLIGHT ||
GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_SUPPLEMENTAL) GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_SUPPLEMENTAL)
{ {
JoyStickInfo jsInfo; JoyStickInfo jsInfo;
jsInfo.isXInput = false; jsInfo.isXInput = false;
jsInfo.productGuid = lpddi->guidProduct; jsInfo.productGuid = lpddi->guidProduct;
jsInfo.deviceID = lpddi->guidInstance; jsInfo.deviceID = lpddi->guidInstance;
jsInfo.vendor = lpddi->tszInstanceName; jsInfo.vendor = lpddi->tszInstanceName;
jsInfo.devId = _this_->joySticks; jsInfo.devId = _this_->joySticks;
_this_->joySticks++; _this_->joySticks++;
_this_->unusedJoyStickList.push_back( jsInfo ); _this_->unusedJoyStickList.push_back( jsInfo );
} }
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
void Win32InputManager::_returnJoyStick(const JoyStickInfo& joystick) void Win32InputManager::_returnJoyStick(const JoyStickInfo& joystick)
{ {
unusedJoyStickList.push_back(joystick); unusedJoyStickList.push_back(joystick);
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
DeviceList Win32InputManager::freeDeviceList() DeviceList Win32InputManager::freeDeviceList()
{ {
DeviceList ret; DeviceList ret;
if( keyboardUsed == false ) if( keyboardUsed == false )
ret.insert(std::make_pair(OISKeyboard, mInputSystemName)); ret.insert(std::make_pair(OISKeyboard, mInputSystemName));
if( mouseUsed == false ) if( mouseUsed == false )
ret.insert(std::make_pair(OISMouse, mInputSystemName)); ret.insert(std::make_pair(OISMouse, mInputSystemName));
for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i) for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i)
ret.insert(std::make_pair(OISJoyStick, i->vendor)); ret.insert(std::make_pair(OISJoyStick, i->vendor));
return ret; return ret;
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
int Win32InputManager::totalDevices(Type iType) int Win32InputManager::totalDevices(Type iType)
{ {
switch(iType) switch(iType)
{ {
case OISKeyboard: return 1; case OISKeyboard: return 1;
case OISMouse: return 1; case OISMouse: return 1;
case OISJoyStick: return joySticks; case OISJoyStick: return joySticks;
default: return 0; default: return 0;
} }
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
int Win32InputManager::freeDevices(Type iType) int Win32InputManager::freeDevices(Type iType)
{ {
switch(iType) switch(iType)
{ {
case OISKeyboard: return keyboardUsed ? 0 : 1; case OISKeyboard: return keyboardUsed ? 0 : 1;
case OISMouse: return mouseUsed ? 0 : 1; case OISMouse: return mouseUsed ? 0 : 1;
case OISJoyStick: return (int)unusedJoyStickList.size(); case OISJoyStick: return (int)unusedJoyStickList.size();
default: return 0; default: return 0;
} }
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
bool Win32InputManager::vendorExist(Type iType, const std::string & vendor) bool Win32InputManager::vendorExist(Type iType, const std::string & vendor)
{ {
if( (iType == OISKeyboard || iType == OISMouse) && vendor == mInputSystemName ) if( (iType == OISKeyboard || iType == OISMouse) && vendor == mInputSystemName )
{ {
return true; return true;
} }
else if( iType == OISJoyStick ) else if( iType == OISJoyStick )
{ {
for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i) for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i)
if(i->vendor == vendor) if(i->vendor == vendor)
return true; return true;
} }
return false; return false;
} }
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
Object* Win32InputManager::createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor) Object* Win32InputManager::createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor)
{ {
Object *obj = 0; OIS_UNUSED(creator);
switch(iType) Object *obj = 0;
{
case OISKeyboard: switch(iType)
{ {
if( keyboardUsed == false ) case OISKeyboard:
obj = new Win32Keyboard(this, mDirectInput, bufferMode, kbSettings); {
break; if( keyboardUsed == false )
} obj = new Win32Keyboard(this, mDirectInput, bufferMode, kbSettings);
case OISMouse: break;
{ }
if( mouseUsed == false ) case OISMouse:
obj = new Win32Mouse(this, mDirectInput, bufferMode, mouseSettings); {
break; if( mouseUsed == false )
} obj = new Win32Mouse(this, mDirectInput, bufferMode, mouseSettings);
case OISJoyStick: break;
{ }
for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i) case OISJoyStick:
{ {
if(vendor == "" || i->vendor == vendor) for(JoyStickInfoList::iterator i = unusedJoyStickList.begin(); i != unusedJoyStickList.end(); ++i)
{ {
obj = new Win32JoyStick(this, mDirectInput, bufferMode, joySettings, *i); if(vendor == "" || i->vendor == vendor)
unusedJoyStickList.erase(i); {
break; obj = new Win32JoyStick(this, mDirectInput, bufferMode, joySettings, *i);
} unusedJoyStickList.erase(i);
} break;
break; }
} }
default: break;
break; }
} default:
break;
if( obj == 0 ) }
OIS_EXCEPT(E_InputDeviceNonExistant, "No devices match requested type.");
if( obj == 0 )
return obj; OIS_EXCEPT(E_InputDeviceNonExistant, "No devices match requested type.");
}
return obj;
//----------------------------------------------------------------------------// }
void Win32InputManager::destroyObject(Object* obj)
{ //----------------------------------------------------------------------------//
delete obj; void Win32InputManager::destroyObject(Object* obj)
} {
delete obj;
}
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "win32/Win32JoyStick.h" #include "win32/Win32JoyStick.h"
#include "win32/Win32InputManager.h" #include "win32/Win32InputManager.h"
#include "win32/Win32ForceFeedback.h" #include "win32/Win32ForceFeedback.h"
#include "OISEvents.h" #include "OISEvents.h"
#include "OISException.h" #include "OISException.h"
#include <cassert> #include <cassert>
// Only if xinput support is enabled // Only if xinput support is enabled
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
#include <wbemidl.h> #include <wbemidl.h>
#include <oleauto.h> #include <oleauto.h>
//#include <wmsstd.h> //#include <wmsstd.h>
#ifndef SAFE_RELEASE #ifndef SAFE_RELEASE
#define SAFE_RELEASE(x) \ #define SAFE_RELEASE(x) \
if(x != NULL) \ if(x != NULL) \
{ \ { \
x->Release(); \ x->Release(); \
x = NULL; \ x = NULL; \
} }
#endif #endif
#pragma comment(lib, "xinput.lib") #pragma comment(lib, "xinput.lib")
#endif #endif
//DX Only defines macros for the JOYSTICK not JOYSTICK2, so fix it //DX Only defines macros for the JOYSTICK not JOYSTICK2, so fix it
#undef DIJOFS_BUTTON #undef DIJOFS_BUTTON
#undef DIJOFS_POV #undef DIJOFS_POV
#define DIJOFS_BUTTON(n) (FIELD_OFFSET(DIJOYSTATE2, rgbButtons) + (n)) #define DIJOFS_BUTTON(n) (FIELD_OFFSET(DIJOYSTATE2, rgbButtons) + (n))
#define DIJOFS_POV(n) (FIELD_OFFSET(DIJOYSTATE2, rgdwPOV)+(n)*sizeof(DWORD)) #define DIJOFS_POV(n) (FIELD_OFFSET(DIJOYSTATE2, rgdwPOV)+(n)*sizeof(DWORD))
#define DIJOFS_SLIDER0(n) (FIELD_OFFSET(DIJOYSTATE2, rglSlider)+(n) * sizeof(LONG)) #define DIJOFS_SLIDER0(n) (FIELD_OFFSET(DIJOYSTATE2, rglSlider)+(n) * sizeof(LONG))
#define DIJOFS_SLIDER1(n) (FIELD_OFFSET(DIJOYSTATE2, rglVSlider)+(n) * sizeof(LONG)) #define DIJOFS_SLIDER1(n) (FIELD_OFFSET(DIJOYSTATE2, rglVSlider)+(n) * sizeof(LONG))
#define DIJOFS_SLIDER2(n) (FIELD_OFFSET(DIJOYSTATE2, rglASlider)+(n) * sizeof(LONG)) #define DIJOFS_SLIDER2(n) (FIELD_OFFSET(DIJOYSTATE2, rglASlider)+(n) * sizeof(LONG))
#define DIJOFS_SLIDER3(n) (FIELD_OFFSET(DIJOYSTATE2, rglFSlider)+(n) * sizeof(LONG)) #define DIJOFS_SLIDER3(n) (FIELD_OFFSET(DIJOYSTATE2, rglFSlider)+(n) * sizeof(LONG))
#define XINPUT_TRANSLATED_BUTTON_COUNT 12 #define XINPUT_TRANSLATED_BUTTON_COUNT 12
#define XINPUT_TRANSLATED_AXIS_COUNT 6 #define XINPUT_TRANSLATED_AXIS_COUNT 6
using namespace OIS; using namespace OIS;
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32JoyStick::Win32JoyStick( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings, const JoyStickInfo &info ) : Win32JoyStick::Win32JoyStick( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings, const JoyStickInfo &info ) :
JoyStick(info.vendor, buffered, info.devId, creator), JoyStick(info.vendor, buffered, info.devId, creator),
mDirectInput(pDI), mDirectInput(pDI),
coopSetting(coopSettings), coopSetting(coopSettings),
mJoyStick(0), mJoyStick(0),
mJoyInfo(info), mJoyInfo(info),
mFfDevice(0) mFfDevice(0)
{ {
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32JoyStick::~Win32JoyStick() Win32JoyStick::~Win32JoyStick()
{ {
delete mFfDevice; delete mFfDevice;
if(mJoyStick) if(mJoyStick)
{ {
mJoyStick->Unacquire(); mJoyStick->Unacquire();
mJoyStick->Release(); mJoyStick->Release();
mJoyStick = 0; mJoyStick = 0;
} }
//Return joystick to pool //Return joystick to pool
static_cast<Win32InputManager*>(mCreator)->_returnJoyStick(mJoyInfo); static_cast<Win32InputManager*>(mCreator)->_returnJoyStick(mJoyInfo);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::_initialize() void Win32JoyStick::_initialize()
{ {
if (mJoyInfo.isXInput) if (mJoyInfo.isXInput)
{ {
_enumerate(); _enumerate();
} }
else else
{ {
//Clear old state //Clear old state
mState.mAxes.clear(); mState.mAxes.clear();
delete mFfDevice; delete mFfDevice;
mFfDevice = 0; mFfDevice = 0;
DIPROPDWORD dipdw; DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0; dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE; dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = JOYSTICK_DX_BUFFERSIZE; dipdw.dwData = JOYSTICK_DX_BUFFERSIZE;
if(FAILED(mDirectInput->CreateDevice(mJoyInfo.deviceID, &mJoyStick, NULL))) if(FAILED(mDirectInput->CreateDevice(mJoyInfo.deviceID, &mJoyStick, NULL)))
OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> Could not initialize joy device!"); OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> Could not initialize joy device!");
if(FAILED(mJoyStick->SetDataFormat(&c_dfDIJoystick2))) if(FAILED(mJoyStick->SetDataFormat(&c_dfDIJoystick2)))
OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> data format error!"); OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> data format error!");
HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle(); HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
if(FAILED(mJoyStick->SetCooperativeLevel( hwin, coopSetting))) if(FAILED(mJoyStick->SetCooperativeLevel( hwin, coopSetting)))
OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> failed to set cooperation level!"); OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> failed to set cooperation level!");
if( FAILED(mJoyStick->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)) ) if( FAILED(mJoyStick->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set buffer size property" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set buffer size property" );
//Enumerate all axes/buttons/sliders/etc before aquiring //Enumerate all axes/buttons/sliders/etc before aquiring
_enumerate(); _enumerate();
mState.clear(); mState.clear();
capture(); capture();
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::_enumerate() void Win32JoyStick::_enumerate()
{ {
if (mJoyInfo.isXInput) if (mJoyInfo.isXInput)
{ {
mPOVs = 1; mPOVs = 1;
mState.mButtons.resize(XINPUT_TRANSLATED_BUTTON_COUNT); mState.mButtons.resize(XINPUT_TRANSLATED_BUTTON_COUNT);
mState.mAxes.resize(XINPUT_TRANSLATED_AXIS_COUNT); mState.mAxes.resize(XINPUT_TRANSLATED_AXIS_COUNT);
} }
else else
{ {
// Get joystick capabilities. // Get joystick capabilities.
mDIJoyCaps.dwSize = sizeof(DIDEVCAPS); mDIJoyCaps.dwSize = sizeof(DIDEVCAPS);
if( FAILED(mJoyStick->GetCapabilities(&mDIJoyCaps)) ) if( FAILED(mJoyStick->GetCapabilities(&mDIJoyCaps)) )
OIS_EXCEPT( E_General, "Win32JoyStick::_enumerate >> Failed to get capabilities" ); OIS_EXCEPT( E_General, "Win32JoyStick::_enumerate >> Failed to get capabilities" );
mPOVs = (short)mDIJoyCaps.dwPOVs; mPOVs = (short)mDIJoyCaps.dwPOVs;
mState.mButtons.resize(mDIJoyCaps.dwButtons); mState.mButtons.resize(mDIJoyCaps.dwButtons);
mState.mAxes.resize(mDIJoyCaps.dwAxes); mState.mAxes.resize(mDIJoyCaps.dwAxes);
//Reset the axis mapping enumeration value //Reset the axis mapping enumeration value
_AxisNumber = 0; _AxisNumber = 0;
//Enumerate Force Feedback (if any) //Enumerate Force Feedback (if any)
mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL); mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL);
//Enumerate and set axis constraints (and check FF Axes) //Enumerate and set axis constraints (and check FF Axes)
mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS); mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS);
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
BOOL CALLBACK Win32JoyStick::DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) BOOL CALLBACK Win32JoyStick::DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
{ {
Win32JoyStick* _this = (Win32JoyStick*)pvRef; Win32JoyStick* _this = (Win32JoyStick*)pvRef;
//Setup mappings //Setup mappings
DIPROPPOINTER diptr; DIPROPPOINTER diptr;
diptr.diph.dwSize = sizeof(DIPROPPOINTER); diptr.diph.dwSize = sizeof(DIPROPPOINTER);
diptr.diph.dwHeaderSize = sizeof(DIPROPHEADER); diptr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diptr.diph.dwHow = DIPH_BYID; diptr.diph.dwHow = DIPH_BYID;
diptr.diph.dwObj = lpddoi->dwType; diptr.diph.dwObj = lpddoi->dwType;
//Add a magic number to recognise we set seomthing //Add a magic number to recognise we set seomthing
diptr.uData = 0x13130000 | _this->_AxisNumber; diptr.uData = 0x13130000 | _this->_AxisNumber;
//Check if axis is slider, if so, do not treat as regular axis //Check if axis is slider, if so, do not treat as regular axis
if(GUID_Slider == lpddoi->guidType) if(GUID_Slider == lpddoi->guidType)
{ {
++_this->mSliders; ++_this->mSliders;
//Decrease Axes, since this slider shows up in a different place //Decrease Axes, since this slider shows up in a different place
_this->mState.mAxes.pop_back(); _this->mState.mAxes.pop_back();
} }
else if (FAILED(_this->mJoyStick->SetProperty(DIPROP_APPDATA, &diptr.diph))) else if (FAILED(_this->mJoyStick->SetProperty(DIPROP_APPDATA, &diptr.diph)))
{ //If for some reason we could not set needed user data, just ignore this axis { //If for some reason we could not set needed user data, just ignore this axis
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
//Increase for next time through //Increase for next time through
if(GUID_Slider != lpddoi->guidType) if(GUID_Slider != lpddoi->guidType)
_this->_AxisNumber += 1; _this->_AxisNumber += 1;
//Set range //Set range
DIPROPRANGE diprg; DIPROPRANGE diprg;
diprg.diph.dwSize = sizeof(DIPROPRANGE); diprg.diph.dwSize = sizeof(DIPROPRANGE);
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diprg.diph.dwHow = DIPH_BYID; diprg.diph.dwHow = DIPH_BYID;
diprg.diph.dwObj = lpddoi->dwType; diprg.diph.dwObj = lpddoi->dwType;
diprg.lMin = MIN_AXIS; diprg.lMin = MIN_AXIS;
diprg.lMax = MAX_AXIS; diprg.lMax = MAX_AXIS;
if (FAILED(_this->mJoyStick->SetProperty(DIPROP_RANGE, &diprg.diph))) if (FAILED(_this->mJoyStick->SetProperty(DIPROP_RANGE, &diprg.diph)))
OIS_EXCEPT( E_General, "Win32JoyStick::_DIEnumDeviceObjectsCallback >> Failed to set min/max range property" ); OIS_EXCEPT( E_General, "Win32JoyStick::_DIEnumDeviceObjectsCallback >> Failed to set min/max range property" );
//Check if FF Axes, and if so, increment counter //Check if FF Axes, and if so, increment counter
if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 ) if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 )
{ {
if( _this->mFfDevice ) if( _this->mFfDevice )
{ {
_this->mFfDevice->_addFFAxis(); _this->mFfDevice->_addFFAxis();
} }
} }
//Force the flags for gain and auto-center support to true, //Force the flags for gain and auto-center support to true,
//as DInput has no API to query the device for these capabilities //as DInput has no API to query the device for these capabilities
//(the only way to know is to try them ...) //(the only way to know is to try them ...)
if( _this->mFfDevice ) if( _this->mFfDevice )
{ {
_this->mFfDevice->_setGainSupport(true); _this->mFfDevice->_setGainSupport(true);
_this->mFfDevice->_setAutoCenterSupport(true); _this->mFfDevice->_setAutoCenterSupport(true);
} }
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
BOOL CALLBACK Win32JoyStick::DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef) BOOL CALLBACK Win32JoyStick::DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef)
{ {
Win32JoyStick* _this = (Win32JoyStick*)pvRef; Win32JoyStick* _this = (Win32JoyStick*)pvRef;
//Create the FF instance only after we know there is at least one effect type //Create the FF instance only after we know there is at least one effect type
if( _this->mFfDevice == 0 ) if( _this->mFfDevice == 0 )
_this->mFfDevice = new Win32ForceFeedback(_this->mJoyStick, &_this->mDIJoyCaps); _this->mFfDevice = new Win32ForceFeedback(_this->mJoyStick, &_this->mDIJoyCaps);
_this->mFfDevice->_addEffectSupport(pdei); _this->mFfDevice->_addEffectSupport(pdei);
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::capture() void Win32JoyStick::capture()
{ {
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
//handle xbox controller differently //handle xbox controller differently
if (mJoyInfo.isXInput) if (mJoyInfo.isXInput)
{ {
captureXInput(); captureXInput();
return; return;
} }
#endif #endif
//handle directinput based devices //handle directinput based devices
DIDEVICEOBJECTDATA diBuff[JOYSTICK_DX_BUFFERSIZE]; DIDEVICEOBJECTDATA diBuff[JOYSTICK_DX_BUFFERSIZE];
DWORD entries = JOYSTICK_DX_BUFFERSIZE; DWORD entries = JOYSTICK_DX_BUFFERSIZE;
// Poll the device to read the current state // Poll the device to read the current state
HRESULT hr = mJoyStick->Poll(); HRESULT hr = mJoyStick->Poll();
if( hr == DI_OK ) if( hr == DI_OK )
hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
if( hr != DI_OK ) if( hr != DI_OK )
{ {
hr = mJoyStick->Acquire(); hr = mJoyStick->Acquire();
while( hr == DIERR_INPUTLOST ) while( hr == DIERR_INPUTLOST )
hr = mJoyStick->Acquire(); hr = mJoyStick->Acquire();
// Poll the device to read the current state // Poll the device to read the current state
mJoyStick->Poll(); mJoyStick->Poll();
hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
//Perhaps the user just tabbed away //Perhaps the user just tabbed away
if( FAILED(hr) ) if( FAILED(hr) )
return; return;
} }
bool axisMoved[24] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false, bool axisMoved[24] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,
false,false,false,false,false,false,false,false}; false,false,false,false,false,false,false,false};
bool sliderMoved[4] = {false,false,false,false}; bool sliderMoved[4] = {false,false,false,false};
//Loop through all the events //Loop through all the events
for(unsigned int i = 0; i < entries; ++i) for(unsigned int i = 0; i < entries; ++i)
{ {
//This may seem outof order, but is in order of the way these variables //This may seem outof order, but is in order of the way these variables
//are declared in the JoyStick State 2 structure. //are declared in the JoyStick State 2 structure.
switch(diBuff[i].dwOfs) switch(diBuff[i].dwOfs)
{ {
//------ slider -// //------ slider -//
case DIJOFS_SLIDER0(0): case DIJOFS_SLIDER0(0):
sliderMoved[0] = true; sliderMoved[0] = true;
mState.mSliders[0].abX = diBuff[i].dwData; mState.mSliders[0].abX = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER0(1): case DIJOFS_SLIDER0(1):
sliderMoved[0] = true; sliderMoved[0] = true;
mState.mSliders[0].abY = diBuff[i].dwData; mState.mSliders[0].abY = diBuff[i].dwData;
break; break;
//----- Max 4 POVs Next ---------------// //----- Max 4 POVs Next ---------------//
case DIJOFS_POV(0): case DIJOFS_POV(0):
if(!_changePOV(0,diBuff[i])) if(!_changePOV(0,diBuff[i]))
return; return;
break; break;
case DIJOFS_POV(1): case DIJOFS_POV(1):
if(!_changePOV(1,diBuff[i])) if(!_changePOV(1,diBuff[i]))
return; return;
break; break;
case DIJOFS_POV(2): case DIJOFS_POV(2):
if(!_changePOV(2,diBuff[i])) if(!_changePOV(2,diBuff[i]))
return; return;
break; break;
case DIJOFS_POV(3): case DIJOFS_POV(3):
if(!_changePOV(3,diBuff[i])) if(!_changePOV(3,diBuff[i]))
return; return;
break; break;
case DIJOFS_SLIDER1(0): case DIJOFS_SLIDER1(0):
sliderMoved[1] = true; sliderMoved[1] = true;
mState.mSliders[1].abX = diBuff[i].dwData; mState.mSliders[1].abX = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER1(1): case DIJOFS_SLIDER1(1):
sliderMoved[1] = true; sliderMoved[1] = true;
mState.mSliders[1].abY = diBuff[i].dwData; mState.mSliders[1].abY = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER2(0): case DIJOFS_SLIDER2(0):
sliderMoved[2] = true; sliderMoved[2] = true;
mState.mSliders[2].abX = diBuff[i].dwData; mState.mSliders[2].abX = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER2(1): case DIJOFS_SLIDER2(1):
sliderMoved[2] = true; sliderMoved[2] = true;
mState.mSliders[2].abY = diBuff[i].dwData; mState.mSliders[2].abY = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER3(0): case DIJOFS_SLIDER3(0):
sliderMoved[3] = true; sliderMoved[3] = true;
mState.mSliders[3].abX = diBuff[i].dwData; mState.mSliders[3].abX = diBuff[i].dwData;
break; break;
case DIJOFS_SLIDER3(1): case DIJOFS_SLIDER3(1):
sliderMoved[3] = true; sliderMoved[3] = true;
mState.mSliders[3].abY = diBuff[i].dwData; mState.mSliders[3].abY = diBuff[i].dwData;
break; break;
//-----------------------------------------// //-----------------------------------------//
default: default:
//Handle Button Events Easily using the DX Offset Macros //Handle Button Events Easily using the DX Offset Macros
if( diBuff[i].dwOfs >= DIJOFS_BUTTON(0) && diBuff[i].dwOfs < DIJOFS_BUTTON(128) ) if( diBuff[i].dwOfs >= DIJOFS_BUTTON(0) && diBuff[i].dwOfs < DIJOFS_BUTTON(128) )
{ {
if(!_doButtonClick((diBuff[i].dwOfs - DIJOFS_BUTTON(0)), diBuff[i])) if(!_doButtonClick((diBuff[i].dwOfs - DIJOFS_BUTTON(0)), diBuff[i]))
return; return;
} }
else if((short)(diBuff[i].uAppData >> 16) == 0x1313) else if((short)(diBuff[i].uAppData >> 16) == 0x1313)
{ //If it was nothing else, might be axis enumerated earlier (determined by magic number) { //If it was nothing else, might be axis enumerated earlier (determined by magic number)
int axis = (int)(0x0000FFFF & diBuff[i].uAppData); //Mask out the high bit int axis = (int)(0x0000FFFF & diBuff[i].uAppData); //Mask out the high bit
assert( axis >= 0 && axis < (int)mState.mAxes.size() && "Axis out of range!"); assert( axis >= 0 && axis < (int)mState.mAxes.size() && "Axis out of range!");
if(axis >= 0 && axis < (int)mState.mAxes.size()) if(axis >= 0 && axis < (int)mState.mAxes.size())
{ {
mState.mAxes[axis].abs = diBuff[i].dwData; mState.mAxes[axis].abs = diBuff[i].dwData;
axisMoved[axis] = true; axisMoved[axis] = true;
} }
} }
break; break;
} //end case } //end case
} //end for } //end for
//Check to see if any of the axes values have changed.. if so send events //Check to see if any of the axes values have changed.. if so send events
if( mBuffered && mListener && entries > 0 ) if( mBuffered && mListener && entries > 0 )
{ {
JoyStickEvent temp(this, mState); JoyStickEvent temp(this, mState);
//Update axes //Update axes
for( int i = 0; i < 24; ++i ) for( int i = 0; i < 24; ++i )
if( axisMoved[i] ) if( axisMoved[i] )
if( mListener->axisMoved( temp, i ) == false ) if( mListener->axisMoved( temp, i ) == false )
return; return;
//Now update sliders //Now update sliders
for( int i = 0; i < 4; ++i ) for( int i = 0; i < 4; ++i )
if( sliderMoved[i] ) if( sliderMoved[i] )
if( mListener->sliderMoved( temp, i ) == false ) if( mListener->sliderMoved( temp, i ) == false )
return; return;
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::captureXInput() void Win32JoyStick::captureXInput()
{ {
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
XINPUT_STATE inputState; XINPUT_STATE inputState;
if (XInputGetState((DWORD)mJoyInfo.xInputDev, &inputState) != ERROR_SUCCESS) if (XInputGetState((DWORD)mJoyInfo.xInputDev, &inputState) != ERROR_SUCCESS)
memset(&inputState, 0, sizeof(inputState)); memset(&inputState, 0, sizeof(inputState));
//Sticks and triggers //Sticks and triggers
int value; int value;
bool axisMoved[XINPUT_TRANSLATED_AXIS_COUNT] = {false,false,false,false,false,false}; bool axisMoved[XINPUT_TRANSLATED_AXIS_COUNT] = {false,false,false,false,false,false};
//LeftY //LeftY
value = -(int)inputState.Gamepad.sThumbLY; value = -(int)inputState.Gamepad.sThumbLY;
mState.mAxes[0].rel = value - mState.mAxes[0].abs; mState.mAxes[0].rel = value - mState.mAxes[0].abs;
mState.mAxes[0].abs = value; mState.mAxes[0].abs = value;
if(mState.mAxes[0].rel != 0) if(mState.mAxes[0].rel != 0)
axisMoved[0] = true; axisMoved[0] = true;
//LeftX //LeftX
mState.mAxes[1].rel = inputState.Gamepad.sThumbLX - mState.mAxes[1].abs; mState.mAxes[1].rel = inputState.Gamepad.sThumbLX - mState.mAxes[1].abs;
mState.mAxes[1].abs = inputState.Gamepad.sThumbLX; mState.mAxes[1].abs = inputState.Gamepad.sThumbLX;
if(mState.mAxes[1].rel != 0) if(mState.mAxes[1].rel != 0)
axisMoved[1] = true; axisMoved[1] = true;
//RightY //RightY
value = -(int)inputState.Gamepad.sThumbRY; value = -(int)inputState.Gamepad.sThumbRY;
mState.mAxes[2].rel = value - mState.mAxes[2].abs; mState.mAxes[2].rel = value - mState.mAxes[2].abs;
mState.mAxes[2].abs = value; mState.mAxes[2].abs = value;
if(mState.mAxes[2].rel != 0) if(mState.mAxes[2].rel != 0)
axisMoved[2] = true; axisMoved[2] = true;
//RightX //RightX
mState.mAxes[3].rel = inputState.Gamepad.sThumbRX - mState.mAxes[3].abs; mState.mAxes[3].rel = inputState.Gamepad.sThumbRX - mState.mAxes[3].abs;
mState.mAxes[3].abs = inputState.Gamepad.sThumbRX; mState.mAxes[3].abs = inputState.Gamepad.sThumbRX;
if(mState.mAxes[3].rel != 0) if(mState.mAxes[3].rel != 0)
axisMoved[3] = true; axisMoved[3] = true;
//Left trigger //Left trigger
value = inputState.Gamepad.bLeftTrigger * 129; value = inputState.Gamepad.bLeftTrigger * 129;
if(value > JoyStick::MAX_AXIS) if(value > JoyStick::MAX_AXIS)
value = JoyStick::MAX_AXIS; value = JoyStick::MAX_AXIS;
mState.mAxes[4].rel = value - mState.mAxes[4].abs; mState.mAxes[4].rel = value - mState.mAxes[4].abs;
mState.mAxes[4].abs = value; mState.mAxes[4].abs = value;
if(mState.mAxes[4].rel != 0) if(mState.mAxes[4].rel != 0)
axisMoved[4] = true; axisMoved[4] = true;
//Right trigger //Right trigger
value = (int)inputState.Gamepad.bRightTrigger * 129; value = (int)inputState.Gamepad.bRightTrigger * 129;
if(value > JoyStick::MAX_AXIS) if(value > JoyStick::MAX_AXIS)
value = JoyStick::MAX_AXIS; value = JoyStick::MAX_AXIS;
mState.mAxes[5].rel = value - mState.mAxes[5].abs; mState.mAxes[5].rel = value - mState.mAxes[5].abs;
mState.mAxes[5].abs = value; mState.mAxes[5].abs = value;
if(mState.mAxes[5].rel != 0) if(mState.mAxes[5].rel != 0)
axisMoved[5] = true; axisMoved[5] = true;
//POV //POV
int previousPov = mState.mPOV[0].direction; int previousPov = mState.mPOV[0].direction;
int& pov = mState.mPOV[0].direction; int& pov = mState.mPOV[0].direction;
pov = Pov::Centered; pov = Pov::Centered;
if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
pov |= Pov::North; pov |= Pov::North;
else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
pov |= Pov::South; pov |= Pov::South;
if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
pov |= Pov::West; pov |= Pov::West;
else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
pov |= Pov::East; pov |= Pov::East;
//Buttons - The first 4 buttons don't need to be checked since they represent the dpad //Buttons - The first 4 buttons don't need to be checked since they represent the dpad
bool previousButtons[XINPUT_TRANSLATED_BUTTON_COUNT]; bool previousButtons[XINPUT_TRANSLATED_BUTTON_COUNT];
std::copy(mState.mButtons.begin(), mState.mButtons.end(), previousButtons); std::copy(mState.mButtons.begin(), mState.mButtons.end(), previousButtons);
for (size_t i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++) for (size_t i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++)
mState.mButtons[i] = (inputState.Gamepad.wButtons & (1 << (i + 4))) != 0; mState.mButtons[i] = (inputState.Gamepad.wButtons & (1 << (i + 4))) != 0;
//Send events //Send events
if (mBuffered && mListener) if (mBuffered && mListener)
{ {
JoyStickEvent joystickEvent(this, mState); JoyStickEvent joystickEvent(this, mState);
//Axes //Axes
for (int i = 0; i < XINPUT_TRANSLATED_AXIS_COUNT; i++) for (int i = 0; i < XINPUT_TRANSLATED_AXIS_COUNT; i++)
{ {
if (axisMoved[i] && !mListener->axisMoved(joystickEvent, i)) if (axisMoved[i] && !mListener->axisMoved(joystickEvent, i))
return; return;
} }
//POV //POV
if (previousPov != pov && !mListener->povMoved(joystickEvent, 0)) if (previousPov != pov && !mListener->povMoved(joystickEvent, 0))
return; return;
//Buttons //Buttons
for (int i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++) for (int i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++)
{ {
if (!previousButtons[i] && mState.mButtons[i]) if (!previousButtons[i] && mState.mButtons[i])
{ {
if (!mListener->buttonPressed(joystickEvent, i)) if (!mListener->buttonPressed(joystickEvent, i))
return; return;
} }
else if (previousButtons[i] && !mState.mButtons[i]) else if (previousButtons[i] && !mState.mButtons[i])
{ {
if (!mListener->buttonReleased(joystickEvent, i)) if (!mListener->buttonReleased(joystickEvent, i))
return; return;
} }
} }
} }
#endif #endif
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
bool Win32JoyStick::_doButtonClick( int button, DIDEVICEOBJECTDATA& di ) bool Win32JoyStick::_doButtonClick( int button, DIDEVICEOBJECTDATA& di )
{ {
if( di.dwData & 0x80 ) if( di.dwData & 0x80 )
{ {
mState.mButtons[button] = true; mState.mButtons[button] = true;
if( mBuffered && mListener ) if( mBuffered && mListener )
return mListener->buttonPressed( JoyStickEvent( this, mState ), button ); return mListener->buttonPressed( JoyStickEvent( this, mState ), button );
} }
else else
{ {
mState.mButtons[button] = false; mState.mButtons[button] = false;
if( mBuffered && mListener ) if( mBuffered && mListener )
return mListener->buttonReleased( JoyStickEvent( this, mState ), button ); return mListener->buttonReleased( JoyStickEvent( this, mState ), button );
} }
return true; return true;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
bool Win32JoyStick::_changePOV( int pov, DIDEVICEOBJECTDATA& di ) bool Win32JoyStick::_changePOV( int pov, DIDEVICEOBJECTDATA& di )
{ {
//Some drivers report a value of 65,535, instead of 1, //Some drivers report a value of 65,535, instead of 1,
//for the center position //for the center position
if(LOWORD(di.dwData) == 0xFFFF) if(LOWORD(di.dwData) == 0xFFFF)
{ {
mState.mPOV[pov].direction = Pov::Centered; mState.mPOV[pov].direction = Pov::Centered;
} }
else else
{ {
switch(di.dwData) switch(di.dwData)
{ {
case 0: mState.mPOV[pov].direction = Pov::North; break; case 0: mState.mPOV[pov].direction = Pov::North; break;
case 4500: mState.mPOV[pov].direction = Pov::NorthEast; break; case 4500: mState.mPOV[pov].direction = Pov::NorthEast; break;
case 9000: mState.mPOV[pov].direction = Pov::East; break; case 9000: mState.mPOV[pov].direction = Pov::East; break;
case 13500: mState.mPOV[pov].direction = Pov::SouthEast; break; case 13500: mState.mPOV[pov].direction = Pov::SouthEast; break;
case 18000: mState.mPOV[pov].direction = Pov::South; break; case 18000: mState.mPOV[pov].direction = Pov::South; break;
case 22500: mState.mPOV[pov].direction = Pov::SouthWest; break; case 22500: mState.mPOV[pov].direction = Pov::SouthWest; break;
case 27000: mState.mPOV[pov].direction = Pov::West; break; case 27000: mState.mPOV[pov].direction = Pov::West; break;
case 31500: mState.mPOV[pov].direction = Pov::NorthWest; break; case 31500: mState.mPOV[pov].direction = Pov::NorthWest; break;
} }
} }
if( mBuffered && mListener ) if( mBuffered && mListener )
return mListener->povMoved( JoyStickEvent( this, mState ), pov ); return mListener->povMoved( JoyStickEvent( this, mState ), pov );
return true; return true;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32JoyStick::setBuffered(bool buffered) void Win32JoyStick::setBuffered(bool buffered)
{ {
mBuffered = buffered; mBuffered = buffered;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Interface* Win32JoyStick::queryInterface(Interface::IType type) Interface* Win32JoyStick::queryInterface(Interface::IType type)
{ {
if( mFfDevice && type == Interface::ForceFeedback ) if( mFfDevice && type == Interface::ForceFeedback )
return mFfDevice; return mFfDevice;
else else
return 0; return 0;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
#ifdef OIS_WIN32_XINPUT_SUPPORT #ifdef OIS_WIN32_XINPUT_SUPPORT
void Win32JoyStick::CheckXInputDevices(JoyStickInfoList &joys) void Win32JoyStick::CheckXInputDevices(JoyStickInfoList &joys)
{ {
IWbemLocator* pIWbemLocator = NULL; IWbemLocator* pIWbemLocator = NULL;
IEnumWbemClassObject* pEnumDevices = NULL; IEnumWbemClassObject* pEnumDevices = NULL;
IWbemClassObject* pDevices[20] = {0}; IWbemClassObject* pDevices[20] = {0};
IWbemServices* pIWbemServices = NULL; IWbemServices* pIWbemServices = NULL;
BSTR bstrNamespace = NULL; BSTR bstrNamespace = NULL;
BSTR bstrDeviceID = NULL; BSTR bstrDeviceID = NULL;
BSTR bstrClassName = NULL; BSTR bstrClassName = NULL;
DWORD uReturned = 0; DWORD uReturned = 0;
bool bIsXinputDevice= false; bool bIsXinputDevice= false;
DWORD iDevice = 0; DWORD iDevice = 0;
int xDevice = 0; int xDevice = 0;
VARIANT var; VARIANT var;
HRESULT hr; HRESULT hr;
if(joys.size() == 0) if(joys.size() == 0)
return; return;
// CoInit if needed // CoInit if needed
hr = CoInitialize(NULL); hr = CoInitialize(NULL);
bool bCleanupCOM = SUCCEEDED(hr); bool bCleanupCOM = SUCCEEDED(hr);
// Create WMI // Create WMI
hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator); hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator);
if( FAILED(hr) || pIWbemLocator == NULL ) if( FAILED(hr) || pIWbemLocator == NULL )
goto LCleanup; goto LCleanup;
bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" ); bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );
if( bstrNamespace == NULL ) if( bstrNamespace == NULL )
goto LCleanup; goto LCleanup;
bstrClassName = SysAllocString( L"Win32_PNPEntity" ); bstrClassName = SysAllocString( L"Win32_PNPEntity" );
if( bstrClassName == NULL ) if( bstrClassName == NULL )
goto LCleanup; goto LCleanup;
bstrDeviceID = SysAllocString( L"DeviceID" ); bstrDeviceID = SysAllocString( L"DeviceID" );
if( bstrDeviceID == NULL ) if( bstrDeviceID == NULL )
goto LCleanup; goto LCleanup;
// Connect to WMI // Connect to WMI
hr = pIWbemLocator->ConnectServer( bstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices ); hr = pIWbemLocator->ConnectServer( bstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices );
if( FAILED(hr) || pIWbemServices == NULL ) if( FAILED(hr) || pIWbemServices == NULL )
goto LCleanup; goto LCleanup;
// Switch security level to IMPERSONATE. // Switch security level to IMPERSONATE.
CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ); CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
hr = pIWbemServices->CreateInstanceEnum( bstrClassName, 0, NULL, &pEnumDevices ); hr = pIWbemServices->CreateInstanceEnum( bstrClassName, 0, NULL, &pEnumDevices );
if( FAILED(hr) || pEnumDevices == NULL ) if( FAILED(hr) || pEnumDevices == NULL )
goto LCleanup; goto LCleanup;
// Loop over all devices // Loop over all devices
for( ;; ) for( ;; )
{ {
// Get 20 at a time // Get 20 at a time
hr = pEnumDevices->Next(5000, 20, pDevices, &uReturned); hr = pEnumDevices->Next(5000, 20, pDevices, &uReturned);
if( FAILED(hr) ) if( FAILED(hr) )
goto LCleanup; goto LCleanup;
if( uReturned == 0 ) if( uReturned == 0 )
break; break;
for(iDevice = 0; iDevice < uReturned; iDevice++) for(iDevice = 0; iDevice < uReturned; iDevice++)
{ {
// For each device, get its device ID // For each device, get its device ID
hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, NULL, NULL); hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, NULL, NULL);
if(SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) if(SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL)
{ {
// Check if the device ID contains "IG_". If it does, then it's an XInput device - This information can not be found from DirectInput // Check if the device ID contains "IG_". If it does, then it's an XInput device - This information can not be found from DirectInput
if(wcsstr(var.bstrVal, L"IG_")) if(wcsstr(var.bstrVal, L"IG_"))
{ {
// If it does, then get the VID/PID from var.bstrVal // If it does, then get the VID/PID from var.bstrVal
DWORD dwPid = 0, dwVid = 0; DWORD dwPid = 0, dwVid = 0;
WCHAR* strVid = wcsstr( var.bstrVal, L"VID_" ); WCHAR* strVid = wcsstr( var.bstrVal, L"VID_" );
if(strVid && swscanf_s( strVid, L"VID_%4X", &dwVid ) != 1) if(strVid && swscanf_s( strVid, L"VID_%4X", &dwVid ) != 1)
dwVid = 0; dwVid = 0;
WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" ); WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" );
if(strPid && swscanf_s( strPid, L"PID_%4X", &dwPid ) != 1) if(strPid && swscanf_s( strPid, L"PID_%4X", &dwPid ) != 1)
dwPid = 0; dwPid = 0;
// Compare the VID/PID to the DInput device // Compare the VID/PID to the DInput device
DWORD dwVidPid = MAKELONG(dwVid, dwPid); DWORD dwVidPid = MAKELONG(dwVid, dwPid);
for(JoyStickInfoList::iterator i = joys.begin(); i != joys.end(); ++i) for(JoyStickInfoList::iterator i = joys.begin(); i != joys.end(); ++i)
{ {
if(!i->isXInput && dwVidPid == i->productGuid.Data1) if(!i->isXInput && dwVidPid == i->productGuid.Data1)
{ {
i->isXInput = true; i->isXInput = true;
i->xInputDev = xDevice; i->xInputDev = xDevice;
++xDevice; ++xDevice;
} }
} }
if(joys.size() == 0) if(joys.size() == 0)
goto LCleanup; goto LCleanup;
} }
} }
SAFE_RELEASE(pDevices[iDevice]); SAFE_RELEASE(pDevices[iDevice]);
} }
} }
LCleanup: LCleanup:
if(bstrNamespace) if(bstrNamespace)
SysFreeString(bstrNamespace); SysFreeString(bstrNamespace);
if(bstrDeviceID) if(bstrDeviceID)
SysFreeString(bstrDeviceID); SysFreeString(bstrDeviceID);
if(bstrClassName) if(bstrClassName)
SysFreeString(bstrClassName); SysFreeString(bstrClassName);
for(iDevice=0; iDevice < 20; iDevice++) for(iDevice=0; iDevice < 20; iDevice++)
SAFE_RELEASE(pDevices[iDevice]); SAFE_RELEASE(pDevices[iDevice]);
SAFE_RELEASE(pEnumDevices); SAFE_RELEASE(pEnumDevices);
SAFE_RELEASE(pIWbemLocator); SAFE_RELEASE(pIWbemLocator);
SAFE_RELEASE(pIWbemServices); SAFE_RELEASE(pIWbemServices);
if(bCleanupCOM) if(bCleanupCOM)
CoUninitialize(); CoUninitialize();
} }
#endif #endif
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "win32/Win32InputManager.h" #include "win32/Win32InputManager.h"
#include "win32/Win32KeyBoard.h" #include "win32/Win32KeyBoard.h"
#include "OISException.h" #include "OISException.h"
#include "OISEvents.h" #include "OISEvents.h"
#include <sstream> #include <sstream>
using namespace OIS; using namespace OIS;
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32Keyboard::Win32Keyboard( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings ) Win32Keyboard::Win32Keyboard( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings )
: Keyboard(creator->inputSystemName(), buffered, 0, creator) : Keyboard(creator->inputSystemName(), buffered, 0, creator)
{ {
mKeyboard = 0; mKeyboard = 0;
mDirectInput = pDI; mDirectInput = pDI;
coopSetting = coopSettings; coopSetting = coopSettings;
//Clear our keyboard state buffer //Clear our keyboard state buffer
memset( &KeyBuffer, 0, 256 ); memset( &KeyBuffer, 0, 256 );
deadKey = '\0'; deadKey = '\0';
static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(true); static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(true);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::_initialize() void Win32Keyboard::_initialize()
{ {
mModifiers = 0; mModifiers = 0;
deadKey = '\0'; deadKey = '\0';
if(FAILED(mDirectInput->CreateDevice(GUID_SysKeyboard, &mKeyboard, NULL))) if(FAILED(mDirectInput->CreateDevice(GUID_SysKeyboard, &mKeyboard, NULL)))
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> Could not init device!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> Could not init device!");
if(FAILED(mKeyboard->SetDataFormat(&c_dfDIKeyboard))) if(FAILED(mKeyboard->SetDataFormat(&c_dfDIKeyboard)))
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> format error!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> format error!");
HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle(); HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
if(FAILED(mKeyboard->SetCooperativeLevel( hwin, coopSetting))) if(FAILED(mKeyboard->SetCooperativeLevel( hwin, coopSetting)))
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> coop error!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> coop error!");
if( mBuffered ) if( mBuffered )
{ {
DIPROPDWORD dipdw; DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0; dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE; dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = KEYBOARD_DX_BUFFERSIZE; dipdw.dwData = KEYBOARD_DX_BUFFERSIZE;
if (FAILED(mKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph ))) if (FAILED(mKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph )))
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> buffer error!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> buffer error!");
} }
HRESULT hr = mKeyboard->Acquire(); HRESULT hr = mKeyboard->Acquire();
if(FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO) if(FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO)
OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> aquire error!"); OIS_EXCEPT( E_General, "Win32Keyboard::Win32Keyboard >> aquire error!");
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32Keyboard::~Win32Keyboard() Win32Keyboard::~Win32Keyboard()
{ {
if(mKeyboard) if(mKeyboard)
{ {
mKeyboard->Unacquire(); mKeyboard->Unacquire();
mKeyboard->Release(); mKeyboard->Release();
mKeyboard = 0; mKeyboard = 0;
} }
static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(false); static_cast<Win32InputManager*>(mCreator)->_setKeyboardUsed(false);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::capture() void Win32Keyboard::capture()
{ {
if( mBuffered ) if( mBuffered )
_readBuffered(); _readBuffered();
else else
_read(); _read();
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::_readBuffered() void Win32Keyboard::_readBuffered()
{ {
DIDEVICEOBJECTDATA diBuff[KEYBOARD_DX_BUFFERSIZE]; DIDEVICEOBJECTDATA diBuff[KEYBOARD_DX_BUFFERSIZE];
DWORD entries = KEYBOARD_DX_BUFFERSIZE; DWORD entries = KEYBOARD_DX_BUFFERSIZE;
HRESULT hr; HRESULT hr;
//Only one keyboard allowed per app, so static is ok //Only one keyboard allowed per app, so static is ok
static bool verifyAfterAltTab = false; static bool verifyAfterAltTab = false;
hr = mKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); hr = mKeyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
if( hr != DI_OK ) if( hr != DI_OK )
{ {
hr = mKeyboard->Acquire(); hr = mKeyboard->Acquire();
if (hr == E_ACCESSDENIED) if (hr == E_ACCESSDENIED)
verifyAfterAltTab = true; verifyAfterAltTab = true;
while( hr == DIERR_INPUTLOST ) while( hr == DIERR_INPUTLOST )
hr = mKeyboard->Acquire(); hr = mKeyboard->Acquire();
return; return;
} }
if( FAILED(hr) ) if( FAILED(hr) )
OIS_EXCEPT( E_General, "Win32Keyboard::_readBuffered() >> Problem with Device!" ); OIS_EXCEPT( E_General, "Win32Keyboard::_readBuffered() >> Problem with Device!" );
//Update keyboard and modifier states.. And, if mListener, fire events //Update keyboard and modifier states.. And, if mListener, fire events
for(unsigned int i = 0; i < entries; ++i ) for(unsigned int i = 0; i < entries; ++i )
{ {
//If the listener returns false, that means that we are probably deleted... //If the listener returns false, that means that we are probably deleted...
//send no more events and just leave as the this pointer is invalid now... //send no more events and just leave as the this pointer is invalid now...
bool ret = true; bool ret = true;
KeyCode kc = (KeyCode)diBuff[ i ].dwOfs; KeyCode kc = (KeyCode)diBuff[ i ].dwOfs;
//Store result in our keyBuffer too //Store result in our keyBuffer too
KeyBuffer[kc] = static_cast<unsigned char>(diBuff[ i ].dwData); KeyBuffer[kc] = static_cast<unsigned char>(diBuff[ i ].dwData);
if( diBuff[ i ].dwData & 0x80 ) if( diBuff[ i ].dwData & 0x80 )
{ {
//Turn on modifier //Turn on modifier
if( kc == KC_LCONTROL || kc == KC_RCONTROL ) if( kc == KC_LCONTROL || kc == KC_RCONTROL )
mModifiers |= Ctrl; mModifiers |= Ctrl;
else if( kc == KC_LSHIFT || kc == KC_RSHIFT ) else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
mModifiers |= Shift; mModifiers |= Shift;
else if( kc == KC_LMENU || kc == KC_RMENU ) else if( kc == KC_LMENU || kc == KC_RMENU )
mModifiers |= Alt; mModifiers |= Alt;
if( mListener ) if( mListener )
ret = mListener->keyPressed( KeyEvent( this, kc, _translateText(kc) ) ); ret = mListener->keyPressed( KeyEvent( this, kc, _translateText(kc) ) );
} }
else else
{ {
//Turn off modifier //Turn off modifier
if( kc == KC_LCONTROL || kc == KC_RCONTROL ) if( kc == KC_LCONTROL || kc == KC_RCONTROL )
mModifiers &= ~Ctrl; mModifiers &= ~Ctrl;
else if( kc == KC_LSHIFT || kc == KC_RSHIFT ) else if( kc == KC_LSHIFT || kc == KC_RSHIFT )
mModifiers &= ~Shift; mModifiers &= ~Shift;
else if( kc == KC_LMENU || kc == KC_RMENU ) else if( kc == KC_LMENU || kc == KC_RMENU )
mModifiers &= ~Alt; mModifiers &= ~Alt;
//Fire off event //Fire off event
if( mListener ) if( mListener )
ret = mListener->keyReleased( KeyEvent( this, kc, 0 ) ); ret = mListener->keyReleased( KeyEvent( this, kc, 0 ) );
} }
if(ret == false) if(ret == false)
break; break;
} }
// If a lost device/access denied was detected, recover gracefully with new events // If a lost device/access denied was detected, recover gracefully with new events
if(verifyAfterAltTab) if(verifyAfterAltTab)
{ {
bool ret = true; bool ret = true;
//Copy old buffer to temp location to compare against //Copy old buffer to temp location to compare against
unsigned char keyBufferCopy[256]; unsigned char keyBufferCopy[256];
memcpy(keyBufferCopy, KeyBuffer, 256); memcpy(keyBufferCopy, KeyBuffer, 256);
//Update new state //Update new state
_read(); _read();
for (unsigned i = 0; i < 256; i++) for (unsigned i = 0; i < 256; i++)
{ {
if (keyBufferCopy[i] != KeyBuffer[i]) if (keyBufferCopy[i] != KeyBuffer[i])
{ {
if (mListener) if (mListener)
{ {
if (KeyBuffer[i]) if (KeyBuffer[i])
ret = mListener->keyPressed( KeyEvent( this, (KeyCode)i, _translateText((KeyCode)i) ) ); ret = mListener->keyPressed( KeyEvent( this, (KeyCode)i, _translateText((KeyCode)i) ) );
else else
ret = mListener->keyReleased( KeyEvent( this, (KeyCode)i, 0 ) ); ret = mListener->keyReleased( KeyEvent( this, (KeyCode)i, 0 ) );
} }
} }
//If user returned false from callback, return immediately //If user returned false from callback, return immediately
if(ret == false) if(ret == false)
return; return;
} }
verifyAfterAltTab = false; verifyAfterAltTab = false;
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::_read() void Win32Keyboard::_read()
{ {
HRESULT hr = mKeyboard->GetDeviceState( sizeof(KeyBuffer), &KeyBuffer ); HRESULT hr = mKeyboard->GetDeviceState( sizeof(KeyBuffer), &KeyBuffer );
if( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) if( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED )
{ {
hr = mKeyboard->Acquire(); hr = mKeyboard->Acquire();
if (hr != DIERR_OTHERAPPHASPRIO) if (hr != DIERR_OTHERAPPHASPRIO)
mKeyboard->GetDeviceState(sizeof(KeyBuffer), &KeyBuffer); mKeyboard->GetDeviceState(sizeof(KeyBuffer), &KeyBuffer);
} }
//Set Shift, Ctrl, Alt //Set Shift, Ctrl, Alt
mModifiers = 0; mModifiers = 0;
if( isKeyDown(KC_LCONTROL) || isKeyDown(KC_RCONTROL) ) if( isKeyDown(KC_LCONTROL) || isKeyDown(KC_RCONTROL) )
mModifiers |= Ctrl; mModifiers |= Ctrl;
if( isKeyDown(KC_LSHIFT) || isKeyDown(KC_RSHIFT) ) if( isKeyDown(KC_LSHIFT) || isKeyDown(KC_RSHIFT) )
mModifiers |= Shift; mModifiers |= Shift;
if( isKeyDown(KC_LMENU) || isKeyDown(KC_RMENU) ) if( isKeyDown(KC_LMENU) || isKeyDown(KC_RMENU) )
mModifiers |= Alt; mModifiers |= Alt;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
int Win32Keyboard::_translateText( KeyCode kc ) int Win32Keyboard::_translateText( KeyCode kc )
{ {
if( mTextMode == Off ) if( mTextMode == Off )
return 0; return 0;
BYTE keyState[256]; BYTE keyState[256];
HKL layout = GetKeyboardLayout(0); HKL layout = GetKeyboardLayout(0);
if( GetKeyboardState(keyState) == 0 ) if( GetKeyboardState(keyState) == 0 )
return 0; return 0;
unsigned int vk = MapVirtualKeyEx(kc, 3, layout); unsigned int vk = MapVirtualKeyEx(kc, 3, layout);
if( vk == 0 ) if( vk == 0 )
return 0; return 0;
WCHAR buff[3] = {0}; WCHAR buff[3] = {0};
int ascii = ToUnicodeEx(vk, kc, keyState, buff, 3, 0, layout); int ascii = ToUnicodeEx(vk, kc, keyState, buff, 3, 0, layout);
if(ascii == 1 && deadKey != '\0' ) if(ascii == 1 && deadKey != '\0' )
{ {
// A dead key is stored and we have just converted a character key // A dead key is stored and we have just converted a character key
// Combine the two into a single character // Combine the two into a single character
WCHAR wcBuff[3] = {buff[0], deadKey, '\0'}; WCHAR wcBuff[3] = {buff[0], deadKey, '\0'};
WCHAR out[3]; WCHAR out[3];
deadKey = '\0'; deadKey = '\0';
if(FoldStringW(MAP_PRECOMPOSED, (LPWSTR)wcBuff, 3, (LPWSTR)out, 3)) if(FoldStringW(MAP_PRECOMPOSED, (LPWSTR)wcBuff, 3, (LPWSTR)out, 3))
return out[0]; return out[0];
} }
else if (ascii == 1) else if (ascii == 1)
{ // We have a single character { // We have a single character
deadKey = '\0'; deadKey = '\0';
return buff[0]; return buff[0];
} }
else if(ascii == 2) else if(ascii == 2)
{ // Convert a non-combining diacritical mark into a combining diacritical mark { // Convert a non-combining diacritical mark into a combining diacritical mark
// Combining versions range from 0x300 to 0x36F; only 5 (for French) have been mapped below // Combining versions range from 0x300 to 0x36F; only 5 (for French) have been mapped below
// http://www.fileformat.info/info/unicode/block/combining_diacritical_marks/images.htm // http://www.fileformat.info/info/unicode/block/combining_diacritical_marks/images.htm
switch(buff[0]) { switch(buff[0]) {
case 0x5E: // Circumflex accent: case 0x5E: // Circumflex accent:
deadKey = 0x302; break; deadKey = 0x302; break;
case 0x60: // Grave accent: case 0x60: // Grave accent:
deadKey = 0x300; break; deadKey = 0x300; break;
case 0xA8: // Diaeresis: case 0xA8: // Diaeresis:
deadKey = 0x308; break; deadKey = 0x308; break;
case 0xB4: // Acute accent: case 0xB4: // Acute accent:
deadKey = 0x301; break; deadKey = 0x301; break;
case 0xB8: // Cedilla: case 0xB8: // Cedilla:
deadKey = 0x327; break; deadKey = 0x327; break;
default: default:
deadKey = buff[0]; break; deadKey = buff[0]; break;
} }
} }
return 0; return 0;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
bool Win32Keyboard::isKeyDown( KeyCode key ) const bool Win32Keyboard::isKeyDown( KeyCode key ) const
{ {
return (KeyBuffer[key] & 0x80) != 0; return (KeyBuffer[key] & 0x80) != 0;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
const std::string& Win32Keyboard::getAsString(KeyCode kc) const std::string& Win32Keyboard::getAsString(KeyCode kc)
{ {
char temp[256]; char temp[256];
DIPROPSTRING prop; DIPROPSTRING prop;
prop.diph.dwSize = sizeof(DIPROPSTRING); prop.diph.dwSize = sizeof(DIPROPSTRING);
prop.diph.dwHeaderSize = sizeof(DIPROPHEADER); prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
prop.diph.dwObj = static_cast<DWORD>(kc); prop.diph.dwObj = static_cast<DWORD>(kc);
prop.diph.dwHow = DIPH_BYOFFSET; prop.diph.dwHow = DIPH_BYOFFSET;
if (SUCCEEDED(mKeyboard->GetProperty(DIPROP_KEYNAME, &prop.diph))) if (SUCCEEDED(mKeyboard->GetProperty(DIPROP_KEYNAME, &prop.diph)))
{ {
// convert the WCHAR in "wsz" to multibyte // convert the WCHAR in "wsz" to multibyte
if (WideCharToMultiByte(CP_ACP, 0, prop.wsz, -1, temp, sizeof(temp), NULL, NULL)) if (WideCharToMultiByte(CP_ACP, 0, prop.wsz, -1, temp, sizeof(temp), NULL, NULL))
return mGetString.assign(temp); return mGetString.assign(temp);
} }
std::stringstream ss; std::stringstream ss;
ss << "Key_" << (int)kc; ss << "Key_" << (int)kc;
return mGetString.assign(ss.str()); return mGetString.assign(ss.str());
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::copyKeyStates( char keys[256] ) const void Win32Keyboard::copyKeyStates( char keys[256] ) const
{ {
for(int i = 0; i < 256; ++i) for(int i = 0; i < 256; ++i)
keys[i] = KeyBuffer[i] > 0; //Normalise the DX values (0x80) keys[i] = KeyBuffer[i] > 0; //Normalise the DX values (0x80)
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Keyboard::setBuffered(bool buffered) void Win32Keyboard::setBuffered(bool buffered)
{ {
if( buffered != mBuffered ) if( buffered != mBuffered )
{ {
if(mKeyboard) if(mKeyboard)
{ {
mKeyboard->Unacquire(); mKeyboard->Unacquire();
mKeyboard->Release(); mKeyboard->Release();
mKeyboard = 0; mKeyboard = 0;
} }
mBuffered = buffered; mBuffered = buffered;
_initialize(); _initialize();
} }
} }
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "win32/Win32Mouse.h" #include "win32/Win32Mouse.h"
#include "win32/Win32InputManager.h" #include "win32/Win32InputManager.h"
#include "OISException.h" #include "OISException.h"
#include "OISEvents.h" #include "OISEvents.h"
using namespace OIS; using namespace OIS;
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32Mouse::Win32Mouse( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings ) Win32Mouse::Win32Mouse( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings )
: Mouse(creator->inputSystemName(), buffered, 0, creator) : Mouse(creator->inputSystemName(), buffered, 0, creator)
{ {
mMouse = 0; mMouse = 0;
mDirectInput = pDI; mDirectInput = pDI;
coopSetting = coopSettings; coopSetting = coopSettings;
mHwnd = 0; mHwnd = 0;
static_cast<Win32InputManager*>(mCreator)->_setMouseUsed(true); static_cast<Win32InputManager*>(mCreator)->_setMouseUsed(true);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Mouse::_initialize() void Win32Mouse::_initialize()
{ {
DIPROPDWORD dipdw; DIPROPDWORD dipdw;
//Clear old state //Clear old state
mState.clear(); mState.clear();
dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0; dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE; dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = MOUSE_DX_BUFFERSIZE; dipdw.dwData = MOUSE_DX_BUFFERSIZE;
if( FAILED(mDirectInput->CreateDevice(GUID_SysMouse, &mMouse, NULL)) ) if( FAILED(mDirectInput->CreateDevice(GUID_SysMouse, &mMouse, NULL)) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to create device" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to create device" );
if( FAILED(mMouse->SetDataFormat(&c_dfDIMouse2)) ) if( FAILED(mMouse->SetDataFormat(&c_dfDIMouse2)) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set format" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set format" );
mHwnd = ((Win32InputManager*)mCreator)->getWindowHandle(); mHwnd = ((Win32InputManager*)mCreator)->getWindowHandle();
if( FAILED(mMouse->SetCooperativeLevel(mHwnd, coopSetting)) ) if( FAILED(mMouse->SetCooperativeLevel(mHwnd, coopSetting)) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set coop level" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set coop level" );
if( FAILED(mMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph )) ) if( FAILED(mMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph )) )
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set property" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set property" );
HRESULT hr = mMouse->Acquire(); HRESULT hr = mMouse->Acquire();
if (FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO) if (FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO)
OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to aquire mouse!" ); OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to aquire mouse!" );
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
Win32Mouse::~Win32Mouse() Win32Mouse::~Win32Mouse()
{ {
if (mMouse) if (mMouse)
{ {
mMouse->Unacquire(); mMouse->Unacquire();
mMouse->Release(); mMouse->Release();
mMouse = 0; mMouse = 0;
} }
static_cast<Win32InputManager*>(mCreator)->_setMouseUsed(false); static_cast<Win32InputManager*>(mCreator)->_setMouseUsed(false);
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Mouse::capture() void Win32Mouse::capture()
{ {
//Clear old relative values //Clear old relative values
mState.X.rel = mState.Y.rel = mState.Z.rel = 0; mState.X.rel = mState.Y.rel = mState.Z.rel = 0;
DIDEVICEOBJECTDATA diBuff[MOUSE_DX_BUFFERSIZE]; DIDEVICEOBJECTDATA diBuff[MOUSE_DX_BUFFERSIZE];
DWORD entries = MOUSE_DX_BUFFERSIZE; DWORD entries = MOUSE_DX_BUFFERSIZE;
HRESULT hr = mMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); HRESULT hr = mMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
if( hr != DI_OK ) if( hr != DI_OK )
{ {
hr = mMouse->Acquire(); hr = mMouse->Acquire();
while( hr == DIERR_INPUTLOST ) while( hr == DIERR_INPUTLOST )
hr = mMouse->Acquire(); hr = mMouse->Acquire();
hr = mMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 ); hr = mMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
//Perhaps the user just tabbed away, and coop settings //Perhaps the user just tabbed away, and coop settings
//are nonexclusive..so just ignore //are nonexclusive..so just ignore
if( FAILED(hr) ) if( FAILED(hr) )
return; return;
} }
bool axesMoved = false; bool axesMoved = false;
//Accumulate all axis movements for one axesMove message.. //Accumulate all axis movements for one axesMove message..
//Buttons are fired off as they are found //Buttons are fired off as they are found
for(unsigned int i = 0; i < entries; ++i ) for(unsigned int i = 0; i < entries; ++i )
{ {
switch( diBuff[i].dwOfs ) switch( diBuff[i].dwOfs )
{ {
case DIMOFS_BUTTON0: case DIMOFS_BUTTON0:
if(!_doMouseClick(0, diBuff[i])) return; if(!_doMouseClick(0, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON1: case DIMOFS_BUTTON1:
if(!_doMouseClick(1, diBuff[i])) return; if(!_doMouseClick(1, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON2: case DIMOFS_BUTTON2:
if(!_doMouseClick(2, diBuff[i])) return; if(!_doMouseClick(2, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON3: case DIMOFS_BUTTON3:
if(!_doMouseClick(3, diBuff[i])) return; if(!_doMouseClick(3, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON4: case DIMOFS_BUTTON4:
if(!_doMouseClick(4, diBuff[i])) return; if(!_doMouseClick(4, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON5: case DIMOFS_BUTTON5:
if(!_doMouseClick(5, diBuff[i])) return; if(!_doMouseClick(5, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON6: case DIMOFS_BUTTON6:
if(!_doMouseClick(6, diBuff[i])) return; if(!_doMouseClick(6, diBuff[i])) return;
break; break;
case DIMOFS_BUTTON7: case DIMOFS_BUTTON7:
if(!_doMouseClick(7, diBuff[i])) return; if(!_doMouseClick(7, diBuff[i])) return;
break; break;
case DIMOFS_X: case DIMOFS_X:
mState.X.rel += diBuff[i].dwData; mState.X.rel += diBuff[i].dwData;
axesMoved = true; axesMoved = true;
break; break;
case DIMOFS_Y: case DIMOFS_Y:
mState.Y.rel += diBuff[i].dwData; mState.Y.rel += diBuff[i].dwData;
axesMoved = true; axesMoved = true;
break; break;
case DIMOFS_Z: case DIMOFS_Z:
mState.Z.rel += diBuff[i].dwData; mState.Z.rel += diBuff[i].dwData;
axesMoved = true; axesMoved = true;
break; break;
default: break; default: break;
} //end switch } //end switch
}//end for }//end for
if( axesMoved ) if( axesMoved )
{ {
if( coopSetting & DISCL_NONEXCLUSIVE ) if( coopSetting & DISCL_NONEXCLUSIVE )
{ {
//DirectInput provides us with meaningless values, so correct that //DirectInput provides us with meaningless values, so correct that
POINT point; POINT point;
GetCursorPos(&point); GetCursorPos(&point);
ScreenToClient(mHwnd, &point); ScreenToClient(mHwnd, &point);
mState.X.abs = point.x; mState.X.abs = point.x;
mState.Y.abs = point.y; mState.Y.abs = point.y;
} }
else else
{ {
mState.X.abs += mState.X.rel; mState.X.abs += mState.X.rel;
mState.Y.abs += mState.Y.rel; mState.Y.abs += mState.Y.rel;
} }
mState.Z.abs += mState.Z.rel; mState.Z.abs += mState.Z.rel;
//Clip values to window //Clip values to window
if( mState.X.abs < 0 ) if( mState.X.abs < 0 )
mState.X.abs = 0; mState.X.abs = 0;
else if( mState.X.abs > mState.width ) else if( mState.X.abs > mState.width )
mState.X.abs = mState.width; mState.X.abs = mState.width;
if( mState.Y.abs < 0 ) if( mState.Y.abs < 0 )
mState.Y.abs = 0; mState.Y.abs = 0;
else if( mState.Y.abs > mState.height ) else if( mState.Y.abs > mState.height )
mState.Y.abs = mState.height; mState.Y.abs = mState.height;
//Do the move //Do the move
if( mListener && mBuffered ) if( mListener && mBuffered )
mListener->mouseMoved( MouseEvent( this, mState ) ); mListener->mouseMoved( MouseEvent( this, mState ) );
} }
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
bool Win32Mouse::_doMouseClick( int mouseButton, DIDEVICEOBJECTDATA& di ) bool Win32Mouse::_doMouseClick( int mouseButton, DIDEVICEOBJECTDATA& di )
{ {
if( di.dwData & 0x80 ) if( di.dwData & 0x80 )
{ {
mState.buttons |= 1 << mouseButton; //turn the bit flag on mState.buttons |= 1 << mouseButton; //turn the bit flag on
if( mListener && mBuffered ) if( mListener && mBuffered )
return mListener->mousePressed( MouseEvent( this, mState ), (MouseButtonID)mouseButton ); return mListener->mousePressed( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
} }
else else
{ {
mState.buttons &= ~(1 << mouseButton); //turn the bit flag off mState.buttons &= ~(1 << mouseButton); //turn the bit flag off
if( mListener && mBuffered ) if( mListener && mBuffered )
return mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)mouseButton ); return mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
} }
return true; return true;
} }
//--------------------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------------------//
void Win32Mouse::setBuffered(bool buffered) void Win32Mouse::setBuffered(bool buffered)
{ {
mBuffered = buffered; mBuffered = buffered;
} }
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "OISWiiMote.h" #include "OISWiiMote.h"
#include "OISWiiMoteFactoryCreator.h" #include "OISWiiMoteFactoryCreator.h"
#include "OISException.h" #include "OISException.h"
#include "OISWiiMoteForceFeedback.h" #include "OISWiiMoteForceFeedback.h"
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include <math.h> #include <math.h>
#include <limits.h> #include <limits.h>
using namespace OIS; using namespace OIS;
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
WiiMote::WiiMote(InputManager* creator, int id, bool buffered, WiiMoteFactoryCreator* local_creator) : WiiMote::WiiMote(InputManager* creator, int id, bool buffered, WiiMoteFactoryCreator* local_creator) :
JoyStick("cWiiMote", buffered, id, creator), JoyStick("cWiiMote", buffered, id, creator),
mWiiCreator(local_creator), mWiiCreator(local_creator),
mtInitialized(false), mtInitialized(false),
mRingBuffer(OIS_WII_EVENT_BUFFER), mRingBuffer(OIS_WII_EVENT_BUFFER),
mtLastButtonStates(0), mtLastButtonStates(0),
mtLastPOVState(0), mtLastPOVState(0),
mtLastX(0.0f), mtLastX(0.0f),
mtLastY(1.0f), mtLastY(1.0f),
mtLastZ(0.0f), mtLastZ(0.0f),
mtLastNunChuckX(0.0f), mtLastNunChuckX(0.0f),
mtLastNunChuckY(1.0f), mtLastNunChuckY(1.0f),
mtLastNunChuckZ(0.0f), mtLastNunChuckZ(0.0f),
mLastNunChuckXAxis(0), mLastNunChuckXAxis(0),
mLastNunChuckYAxis(0), mLastNunChuckYAxis(0),
_mWiiMoteMotionDelay(5), _mWiiMoteMotionDelay(5),
mRumble(0) mRumble(0)
{ {
mRumble = new WiiMoteForceFeedback(mWiiMote); mRumble = new WiiMoteForceFeedback(mWiiMote);
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
WiiMote::~WiiMote() WiiMote::~WiiMote()
{ {
delete mRumble; delete mRumble;
if( mWiiMote.IsConnected() ) if( mWiiMote.IsConnected() )
{ {
mWiiMote.StopDataStream(); mWiiMote.StopDataStream();
mWiiMote.Disconnect(); mWiiMote.Disconnect();
} }
mWiiCreator->_returnWiiMote(mDevID); mWiiCreator->_returnWiiMote(mDevID);
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::_initialize() void WiiMote::_initialize()
{ {
if( mWiiMote.ConnectToDevice(mDevID) == false ) if( mWiiMote.ConnectToDevice(mDevID) == false )
OIS_EXCEPT(E_InputDisconnected, "Error connecting to WiiMote!"); OIS_EXCEPT(E_InputDisconnected, "Error connecting to WiiMote!");
if( mWiiMote.StartDataStream() == false ) if( mWiiMote.StartDataStream() == false )
OIS_EXCEPT(E_InputDisconnected, "Error starting WiiMote data stream!"); OIS_EXCEPT(E_InputDisconnected, "Error starting WiiMote data stream!");
//Fill in joystick information //Fill in joystick information
mState.mVectors.clear(); mState.mVectors.clear();
mState.mButtons.clear(); mState.mButtons.clear();
mState.mAxes.clear(); mState.mAxes.clear();
if( mWiiMote.IsNunChuckAttached() ) if( mWiiMote.IsNunChuckAttached() )
{ //Setup for WiiMote + nunChuck { //Setup for WiiMote + nunChuck
mState.mVectors.resize(2); mState.mVectors.resize(2);
mState.mButtons.resize(9); mState.mButtons.resize(9);
mState.mAxes.resize(2); mState.mAxes.resize(2);
mState.mAxes[0].absOnly = true; mState.mAxes[0].absOnly = true;
mState.mAxes[1].absOnly = true; mState.mAxes[1].absOnly = true;
} }
else else
{ //Setup for WiiMote { //Setup for WiiMote
mState.mVectors.resize(1); mState.mVectors.resize(1);
mState.mButtons.resize(7); mState.mButtons.resize(7);
} }
mPOVs = 1; mPOVs = 1;
mState.clear(); mState.clear();
mtInitialized = true; mtInitialized = true;
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::_threadUpdate() void WiiMote::_threadUpdate()
{ {
//Leave early if nothing is setup yet //Leave early if nothing is setup yet
if( mtInitialized == false ) if( mtInitialized == false )
return; return;
//Oops, no room left in ring buffer.. have to wait for client app to call Capture() //Oops, no room left in ring buffer.. have to wait for client app to call Capture()
if( mRingBuffer.GetWriteAvailable() == 0 ) if( mRingBuffer.GetWriteAvailable() == 0 )
return; return;
WiiMoteEvent newEvent; WiiMoteEvent newEvent;
newEvent.clear(); newEvent.clear();
//Update read //Update read
mWiiMote.HeartBeat(); mWiiMote.HeartBeat();
//Get & check current button states //Get & check current button states
const cWiiMote::tButtonStatus &bState = mWiiMote.GetLastButtonStatus(); const cWiiMote::tButtonStatus &bState = mWiiMote.GetLastButtonStatus();
_doButtonCheck(bState.m1, 0, newEvent.pushedButtons, newEvent.releasedButtons); //1 _doButtonCheck(bState.m1, 0, newEvent.pushedButtons, newEvent.releasedButtons); //1
_doButtonCheck(bState.m2, 1, newEvent.pushedButtons, newEvent.releasedButtons); //2 _doButtonCheck(bState.m2, 1, newEvent.pushedButtons, newEvent.releasedButtons); //2
_doButtonCheck(bState.mA, 2, newEvent.pushedButtons, newEvent.releasedButtons); //A _doButtonCheck(bState.mA, 2, newEvent.pushedButtons, newEvent.releasedButtons); //A
_doButtonCheck(bState.mB, 3, newEvent.pushedButtons, newEvent.releasedButtons); //B _doButtonCheck(bState.mB, 3, newEvent.pushedButtons, newEvent.releasedButtons); //B
_doButtonCheck(bState.mPlus, 4, newEvent.pushedButtons, newEvent.releasedButtons);//+ _doButtonCheck(bState.mPlus, 4, newEvent.pushedButtons, newEvent.releasedButtons);//+
_doButtonCheck(bState.mMinus, 5, newEvent.pushedButtons, newEvent.releasedButtons);//- _doButtonCheck(bState.mMinus, 5, newEvent.pushedButtons, newEvent.releasedButtons);//-
_doButtonCheck(bState.mHome, 6, newEvent.pushedButtons, newEvent.releasedButtons);//Home _doButtonCheck(bState.mHome, 6, newEvent.pushedButtons, newEvent.releasedButtons);//Home
//Check POV //Check POV
newEvent.povChanged = _doPOVCheck(bState, newEvent.povDirection); newEvent.povChanged = _doPOVCheck(bState, newEvent.povDirection);
//Do motion check on main orientation - accounting for sensitivity factor //Do motion check on main orientation - accounting for sensitivity factor
mWiiMote.GetCalibratedAcceleration(newEvent.x, newEvent.y, newEvent.z); mWiiMote.GetCalibratedAcceleration(newEvent.x, newEvent.y, newEvent.z);
//Normalize new vector (old vector is already normalized) //Normalize new vector (old vector is already normalized)
float len = sqrt((newEvent.x*newEvent.x) + (newEvent.y*newEvent.y) + (newEvent.z*newEvent.z)); float len = sqrt((newEvent.x*newEvent.x) + (newEvent.y*newEvent.y) + (newEvent.z*newEvent.z));
newEvent.x /= len; newEvent.x /= len;
newEvent.y /= len; newEvent.y /= len;
newEvent.z /= len; newEvent.z /= len;
//Get new angle //Get new angle
float angle = acos((newEvent.x * mtLastX) + (newEvent.y * mtLastY) + (newEvent.z * mtLastZ)); float angle = acos((newEvent.x * mtLastX) + (newEvent.y * mtLastY) + (newEvent.z * mtLastZ));
if( angle > (mVector3Sensitivity * (M_PI / 180.0)) ) if( angle > (mVector3Sensitivity * (M_PI / 180.0)) )
{ //Store for next check { //Store for next check
mtLastX = newEvent.x; mtLastX = newEvent.x;
mtLastY = newEvent.y; mtLastY = newEvent.y;
mtLastZ = newEvent.z; mtLastZ = newEvent.z;
if( _mWiiMoteMotionDelay <= 0 ) if( _mWiiMoteMotionDelay <= 0 )
newEvent.movement = true; //Set flag as moved newEvent.movement = true; //Set flag as moved
else else
--_mWiiMoteMotionDelay; --_mWiiMoteMotionDelay;
} }
//Act on NunChuck Data //Act on NunChuck Data
if( mWiiMote.IsNunChuckAttached() ) if( mWiiMote.IsNunChuckAttached() )
{ {
const cWiiMote::tChuckReport &bState = mWiiMote.GetLastChuckReport(); const cWiiMote::tChuckReport &bState = mWiiMote.GetLastChuckReport();
_doButtonCheck(bState.mButtonC, 7, newEvent.pushedButtons, newEvent.releasedButtons); //C _doButtonCheck(bState.mButtonC, 7, newEvent.pushedButtons, newEvent.releasedButtons); //C
_doButtonCheck(bState.mButtonZ, 8, newEvent.pushedButtons, newEvent.releasedButtons); //Z _doButtonCheck(bState.mButtonZ, 8, newEvent.pushedButtons, newEvent.releasedButtons); //Z
mWiiMote.GetCalibratedChuckAcceleration(newEvent.nunChuckx, newEvent.nunChucky, newEvent.nunChuckz); mWiiMote.GetCalibratedChuckAcceleration(newEvent.nunChuckx, newEvent.nunChucky, newEvent.nunChuckz);
//Normalize new vector (old vector is already normalized) //Normalize new vector (old vector is already normalized)
float len = sqrt((newEvent.nunChuckx*newEvent.nunChuckx) + float len = sqrt((newEvent.nunChuckx*newEvent.nunChuckx) +
(newEvent.nunChucky*newEvent.nunChucky) + (newEvent.nunChucky*newEvent.nunChucky) +
(newEvent.nunChuckz*newEvent.nunChuckz)); (newEvent.nunChuckz*newEvent.nunChuckz));
newEvent.nunChuckx /= len; newEvent.nunChuckx /= len;
newEvent.nunChucky /= len; newEvent.nunChucky /= len;
newEvent.nunChuckz /= len; newEvent.nunChuckz /= len;
float angle = acos((newEvent.nunChuckx * mtLastNunChuckX) + float angle = acos((newEvent.nunChuckx * mtLastNunChuckX) +
(newEvent.nunChucky * mtLastNunChuckY) + (newEvent.nunChucky * mtLastNunChuckY) +
(newEvent.nunChuckz * mtLastNunChuckZ)); (newEvent.nunChuckz * mtLastNunChuckZ));
if( angle > (mVector3Sensitivity * (M_PI / 180.0)) ) if( angle > (mVector3Sensitivity * (M_PI / 180.0)) )
{ //Store for next check { //Store for next check
mtLastNunChuckX = newEvent.nunChuckx; mtLastNunChuckX = newEvent.nunChuckx;
mtLastNunChuckY = newEvent.nunChucky; mtLastNunChuckY = newEvent.nunChucky;
mtLastNunChuckZ = newEvent.nunChuckz; mtLastNunChuckZ = newEvent.nunChuckz;
if( _mWiiMoteMotionDelay <= 0 ) if( _mWiiMoteMotionDelay <= 0 )
newEvent.movementChuck = true; newEvent.movementChuck = true;
} }
//Ok, Now check both NunChuck Joystick axes for movement //Ok, Now check both NunChuck Joystick axes for movement
float tempX = 0.0f, tempY = 0.0f; float tempX = 0.0f, tempY = 0.0f;
mWiiMote.GetCalibratedChuckStick(tempX, tempY); mWiiMote.GetCalibratedChuckStick(tempX, tempY);
//Convert to int and clip //Convert to int and clip
newEvent.nunChuckXAxis = (int)(tempX * JoyStick::MAX_AXIS); newEvent.nunChuckXAxis = (int)(tempX * JoyStick::MAX_AXIS);
if( newEvent.nunChuckXAxis > JoyStick::MAX_AXIS ) if( newEvent.nunChuckXAxis > JoyStick::MAX_AXIS )
newEvent.nunChuckXAxis = JoyStick::MAX_AXIS; newEvent.nunChuckXAxis = JoyStick::MAX_AXIS;
else if( newEvent.nunChuckXAxis < JoyStick::MIN_AXIS ) else if( newEvent.nunChuckXAxis < JoyStick::MIN_AXIS )
newEvent.nunChuckXAxis = JoyStick::MIN_AXIS; newEvent.nunChuckXAxis = JoyStick::MIN_AXIS;
newEvent.nunChuckYAxis = (int)(tempY * JoyStick::MAX_AXIS); newEvent.nunChuckYAxis = (int)(tempY * JoyStick::MAX_AXIS);
if( newEvent.nunChuckYAxis > JoyStick::MAX_AXIS ) if( newEvent.nunChuckYAxis > JoyStick::MAX_AXIS )
newEvent.nunChuckYAxis = JoyStick::MAX_AXIS; newEvent.nunChuckYAxis = JoyStick::MAX_AXIS;
else if( newEvent.nunChuckYAxis < JoyStick::MIN_AXIS ) else if( newEvent.nunChuckYAxis < JoyStick::MIN_AXIS )
newEvent.nunChuckYAxis = JoyStick::MIN_AXIS; newEvent.nunChuckYAxis = JoyStick::MIN_AXIS;
//Apply a little dead-zone dampner //Apply a little dead-zone dampner
int xDiff = newEvent.nunChuckXAxis - mLastNunChuckXAxis; int xDiff = newEvent.nunChuckXAxis - mLastNunChuckXAxis;
if( xDiff > 1500 || xDiff < -1500 ) if( xDiff > 1500 || xDiff < -1500 )
{ {
mLastNunChuckXAxis = newEvent.nunChuckXAxis; mLastNunChuckXAxis = newEvent.nunChuckXAxis;
newEvent.nunChuckXAxisMoved = true; newEvent.nunChuckXAxisMoved = true;
} }
int yDiff = newEvent.nunChuckYAxis - mLastNunChuckYAxis; int yDiff = newEvent.nunChuckYAxis - mLastNunChuckYAxis;
if( yDiff > 1500 || yDiff < -1500 ) if( yDiff > 1500 || yDiff < -1500 )
{ {
mLastNunChuckYAxis = newEvent.nunChuckYAxis; mLastNunChuckYAxis = newEvent.nunChuckYAxis;
newEvent.nunChuckYAxisMoved = true; newEvent.nunChuckYAxisMoved = true;
} }
} }
//Ok, put entry in ringbuffer if something changed //Ok, put entry in ringbuffer if something changed
if(newEvent.pushedButtons || newEvent.releasedButtons || newEvent.povChanged || newEvent.movement || if(newEvent.pushedButtons || newEvent.releasedButtons || newEvent.povChanged || newEvent.movement ||
newEvent.movementChuck || newEvent.nunChuckXAxisMoved || newEvent.nunChuckYAxisMoved) newEvent.movementChuck || newEvent.nunChuckXAxisMoved || newEvent.nunChuckYAxisMoved)
{ {
mRingBuffer.Write(&newEvent, 1); mRingBuffer.Write(&newEvent, 1);
} }
//mWiiMote.PrintStatus(); //mWiiMote.PrintStatus();
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::_doButtonCheck(bool new_state, int ois_button, unsigned int &pushed, unsigned int &released) void WiiMote::_doButtonCheck(bool new_state, int ois_button, unsigned int &pushed, unsigned int &released)
{ {
const bool old_state = ((mtLastButtonStates & ( 1L << ois_button )) == 0) ? false : true; const bool old_state = ((mtLastButtonStates & ( 1L << ois_button )) == 0) ? false : true;
//Check to see if new state and old state are the same, and hence, need no change //Check to see if new state and old state are the same, and hence, need no change
if( new_state == old_state ) if( new_state == old_state )
return; return;
//Ok, so it changed... but how? //Ok, so it changed... but how?
if( new_state ) if( new_state )
{ //Ok, new state is pushed, old state was not pushed.. so send button press { //Ok, new state is pushed, old state was not pushed.. so send button press
mtLastButtonStates |= 1 << ois_button; //turn the bit flag on mtLastButtonStates |= 1 << ois_button; //turn the bit flag on
pushed |= 1 << ois_button; pushed |= 1 << ois_button;
} }
else else
{ //Ok, so new state is not pushed, and old state was pushed.. So, send release { //Ok, so new state is not pushed, and old state was pushed.. So, send release
mtLastButtonStates &= ~(1 << ois_button); //turn the bit flag off mtLastButtonStates &= ~(1 << ois_button); //turn the bit flag off
released |= 1 << ois_button; released |= 1 << ois_button;
} }
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
bool WiiMote::_doPOVCheck(const cWiiMote::tButtonStatus &bState, unsigned int &newPosition) bool WiiMote::_doPOVCheck(const cWiiMote::tButtonStatus &bState, unsigned int &newPosition)
{ {
newPosition = Pov::Centered; newPosition = Pov::Centered;
if( bState.mUp ) if( bState.mUp )
newPosition |= Pov::North; newPosition |= Pov::North;
else if( bState.mDown ) else if( bState.mDown )
newPosition |= Pov::South; newPosition |= Pov::South;
if( bState.mLeft ) if( bState.mLeft )
newPosition |= Pov::West; newPosition |= Pov::West;
else if( bState.mRight ) else if( bState.mRight )
newPosition |= Pov::East; newPosition |= Pov::East;
//Was there a change? //Was there a change?
if( mtLastPOVState != newPosition ) if( mtLastPOVState != newPosition )
{ {
mtLastPOVState = newPosition; mtLastPOVState = newPosition;
return true; return true;
} }
return false; return false;
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::setBuffered(bool buffered) void WiiMote::setBuffered(bool buffered)
{ {
mBuffered = buffered; mBuffered = buffered;
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMote::capture() void WiiMote::capture()
{ {
//Anything to read? //Anything to read?
int entries = mRingBuffer.GetReadAvailable(); int entries = mRingBuffer.GetReadAvailable();
if( entries <= 0 ) if( entries <= 0 )
return; return;
WiiMoteEvent events[OIS_WII_EVENT_BUFFER]; WiiMoteEvent events[OIS_WII_EVENT_BUFFER];
if( entries > OIS_WII_EVENT_BUFFER ) if( entries > OIS_WII_EVENT_BUFFER )
entries = OIS_WII_EVENT_BUFFER; entries = OIS_WII_EVENT_BUFFER;
mRingBuffer.Read(events, entries); mRingBuffer.Read(events, entries);
//Loop through each event //Loop through each event
for( int i = 0; i < entries; ++i ) for( int i = 0; i < entries; ++i )
{ {
//Any movement changes in the main accellerometers? //Any movement changes in the main accellerometers?
if( events[i].movement ) if( events[i].movement )
{ {
mState.mVectors[0].x = events[i].x; mState.mVectors[0].x = events[i].x;
mState.mVectors[0].y = events[i].y; mState.mVectors[0].y = events[i].y;
mState.mVectors[0].z = events[i].z; mState.mVectors[0].z = events[i].z;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 0 ) ) return; if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 0 ) ) return;
} }
//Check NunChuck movements //Check NunChuck movements
if( events[i].movementChuck ) if( events[i].movementChuck )
{ {
mState.mVectors[1].x = events[i].nunChuckx; mState.mVectors[1].x = events[i].nunChuckx;
mState.mVectors[1].y = events[i].nunChucky; mState.mVectors[1].y = events[i].nunChucky;
mState.mVectors[1].z = events[i].nunChuckz; mState.mVectors[1].z = events[i].nunChuckz;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 1 ) ) return; if( !mListener->vector3Moved( JoyStickEvent( this, mState ), 1 ) ) return;
} }
if( events[i].nunChuckXAxisMoved ) if( events[i].nunChuckXAxisMoved )
{ {
mState.mAxes[0].abs = events[i].nunChuckXAxis; mState.mAxes[0].abs = events[i].nunChuckXAxis;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->axisMoved( JoyStickEvent( this, mState ), 0 ) ) return; if( !mListener->axisMoved( JoyStickEvent( this, mState ), 0 ) ) return;
} }
if( events[i].nunChuckYAxisMoved ) if( events[i].nunChuckYAxisMoved )
{ {
mState.mAxes[1].abs = events[i].nunChuckYAxis; mState.mAxes[1].abs = events[i].nunChuckYAxis;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->axisMoved( JoyStickEvent( this, mState ), 1 ) ) return; if( !mListener->axisMoved( JoyStickEvent( this, mState ), 1 ) ) return;
} }
//Has the hat swtich changed? //Has the hat swtich changed?
if( events[i].povChanged ) if( events[i].povChanged )
{ {
mState.mPOV[0].direction = events[i].povDirection; mState.mPOV[0].direction = events[i].povDirection;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->povMoved( JoyStickEvent( this, mState ), 0 ) ) return; if( !mListener->povMoved( JoyStickEvent( this, mState ), 0 ) ) return;
} }
//Check for any pushed/released events for each button bit //Check for any pushed/released events for each button bit
int buttons = (int)mState.mButtons.size(); int buttons = (int)mState.mButtons.size();
for( int b = 0; b < buttons; ++b ) for( int b = 0; b < buttons; ++b )
{ {
unsigned bit_flag = 1 << b; unsigned bit_flag = 1 << b;
if( (events[i].pushedButtons & bit_flag) != 0 ) if( (events[i].pushedButtons & bit_flag) != 0 )
{ //send event { //send event
mState.mButtons[b] = true; mState.mButtons[b] = true;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->buttonPressed( JoyStickEvent( this, mState ), b ) ) return; if( !mListener->buttonPressed( JoyStickEvent( this, mState ), b ) ) return;
} }
if( (events[i].releasedButtons & bit_flag) != 0 ) if( (events[i].releasedButtons & bit_flag) != 0 )
{ //send event { //send event
mState.mButtons[b] = false; mState.mButtons[b] = false;
if( mBuffered && mListener ) if( mBuffered && mListener )
if( !mListener->buttonReleased( JoyStickEvent( this, mState ), b ) ) return; if( !mListener->buttonReleased( JoyStickEvent( this, mState ), b ) ) return;
} }
} }
} }
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
Interface* WiiMote::queryInterface(Interface::IType type) Interface* WiiMote::queryInterface(Interface::IType type)
{ {
if( type == Interface::ForceFeedback && mtInitialized ) if( type == Interface::ForceFeedback && mtInitialized )
return mRumble; return mRumble;
return 0; return 0;
} }
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef OIS_WiiMote_H #ifndef OIS_WiiMote_H
#define OIS_WiiMote_H #define OIS_WiiMote_H
#include "OISJoyStick.h" #include "OISJoyStick.h"
#include "OISWiiMoteRingBuffer.h" #include "OISWiiMoteRingBuffer.h"
#include "wiimote.h" #include "wiimote.h"
namespace OIS namespace OIS
{ {
class WiiMoteFactoryCreator; class WiiMoteFactoryCreator;
class WiiMoteForceFeedback; class WiiMoteForceFeedback;
//Number of ring buffer events. should be nice sized (the structure is not very big) //Number of ring buffer events. should be nice sized (the structure is not very big)
//Will be rounded up to power of two automatically //Will be rounded up to power of two automatically
#define OIS_WII_EVENT_BUFFER 32 #define OIS_WII_EVENT_BUFFER 32
/** Specialty joystick - WiiMote controller */ /** Specialty joystick - WiiMote controller */
class _OISExport WiiMote : public JoyStick class _OISExport WiiMote : public JoyStick
{ {
public: public:
WiiMote(InputManager* creator, int id, bool buffered, WiiMoteFactoryCreator* local_creator); WiiMote(InputManager* creator, int id, bool buffered, WiiMoteFactoryCreator* local_creator);
~WiiMote(); ~WiiMote();
//Overrides of Object //Overrides of Object
void setBuffered(bool buffered); void setBuffered(bool buffered);
void capture(); void capture();
Interface* queryInterface(Interface::IType type); Interface* queryInterface(Interface::IType type);
void _initialize(); void _initialize();
void _threadUpdate(); void _threadUpdate();
protected: protected:
void _doButtonCheck(bool new_state, int ois_button, unsigned int &pushed, unsigned int &released); void _doButtonCheck(bool new_state, int ois_button, unsigned int &pushed, unsigned int &released);
bool _doPOVCheck(const cWiiMote::tButtonStatus &bState, unsigned int &newPosition); bool _doPOVCheck(const cWiiMote::tButtonStatus &bState, unsigned int &newPosition);
//! The creator who created us //! The creator who created us
WiiMoteFactoryCreator *mWiiCreator; WiiMoteFactoryCreator *mWiiCreator;
//! Actual WiiMote HID device //! Actual WiiMote HID device
cWiiMote mWiiMote; cWiiMote mWiiMote;
//! Used to signal thread that remote is ready //! Used to signal thread that remote is ready
volatile bool mtInitialized; volatile bool mtInitialized;
//! Ringbuffer is used to store events from thread and be read from capture //! Ringbuffer is used to store events from thread and be read from capture
WiiMoteRingBuffer mRingBuffer; WiiMoteRingBuffer mRingBuffer;
//Following variables are used entirely within threaded context //Following variables are used entirely within threaded context
int mtLastButtonStates; int mtLastButtonStates;
unsigned int mtLastPOVState; unsigned int mtLastPOVState;
float mtLastX, mtLastY, mtLastZ; float mtLastX, mtLastY, mtLastZ;
float mtLastNunChuckX, mtLastNunChuckY, mtLastNunChuckZ; float mtLastNunChuckX, mtLastNunChuckY, mtLastNunChuckZ;
int mLastNunChuckXAxis, mLastNunChuckYAxis; int mLastNunChuckXAxis, mLastNunChuckYAxis;
//Small workaround for slow calibration of wiimote data //Small workaround for slow calibration of wiimote data
int _mWiiMoteMotionDelay; int _mWiiMoteMotionDelay;
//Simple rumble force //Simple rumble force
WiiMoteForceFeedback *mRumble; WiiMoteForceFeedback *mRumble;
}; };
} }
#endif //OIS_WiiMote_H #endif //OIS_WiiMote_H
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "OISWiiMoteFactoryCreator.h" #include "OISWiiMoteFactoryCreator.h"
#include "OISException.h" #include "OISException.h"
#include "OISWiiMote.h" #include "OISWiiMote.h"
#include <assert.h> #include <assert.h>
#include <boost/thread.hpp> //include here, keep compilation times down #include <boost/thread.hpp> //include here, keep compilation times down
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
using namespace OIS; using namespace OIS;
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
WiiMoteFactoryCreator::WiiMoteFactoryCreator() : WiiMoteFactoryCreator::WiiMoteFactoryCreator() :
mVendorName("cWiiMote"), mVendorName("cWiiMote"),
mCount(0), mCount(0),
mtThreadHandler(0), mtThreadHandler(0),
mtWiiMoteListMutex(0), mtWiiMoteListMutex(0),
mtThreadRunning(0) mtThreadRunning(0)
{ {
//Discover how many Wii's there are //Discover how many Wii's there are
for( ; mCount < OIS_cWiiMote_MAX_WIIS; ++mCount ) for( ; mCount < OIS_cWiiMote_MAX_WIIS; ++mCount )
{ {
cWiiMote wii; cWiiMote wii;
if( wii.ConnectToDevice(mCount) == false ) if( wii.ConnectToDevice(mCount) == false )
break; break;
} }
//Store how many WiiMotes there were in the form of integer handles //Store how many WiiMotes there were in the form of integer handles
for(int i = 0; i < mCount; ++i) for(int i = 0; i < mCount; ++i)
mFreeWiis.push_back(i); mFreeWiis.push_back(i);
//The mutex lasts the whole life of this class. The thread does not. //The mutex lasts the whole life of this class. The thread does not.
mtWiiMoteListMutex = new boost::mutex(); mtWiiMoteListMutex = new boost::mutex();
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
WiiMoteFactoryCreator::~WiiMoteFactoryCreator() WiiMoteFactoryCreator::~WiiMoteFactoryCreator()
{ {
//Thread (once all objects destroyed) should be killed off already //Thread (once all objects destroyed) should be killed off already
assert( (mtThreadRunning == false && mtThreadHandler == 0) && assert( (mtThreadRunning == false && mtThreadHandler == 0) &&
"~WiiMoteFactoryCreator(): invalid state.. Some objects left dangling!"); "~WiiMoteFactoryCreator(): invalid state.. Some objects left dangling!");
delete mtWiiMoteListMutex; delete mtWiiMoteListMutex;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
DeviceList WiiMoteFactoryCreator::freeDeviceList() DeviceList WiiMoteFactoryCreator::freeDeviceList()
{ {
DeviceList list; DeviceList list;
for( std::deque<int>::iterator i = mFreeWiis.begin(); i != mFreeWiis.end(); ++i ) for( std::deque<int>::iterator i = mFreeWiis.begin(); i != mFreeWiis.end(); ++i )
{ {
list.insert(std::make_pair(OISJoyStick, mVendorName)); list.insert(std::make_pair(OISJoyStick, mVendorName));
} }
return list; return list;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
int WiiMoteFactoryCreator::totalDevices(Type iType) int WiiMoteFactoryCreator::totalDevices(Type iType)
{ {
if( iType == OISJoyStick ) if( iType == OISJoyStick )
return mCount; return mCount;
else else
return 0; return 0;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
int WiiMoteFactoryCreator::freeDevices(Type iType) int WiiMoteFactoryCreator::freeDevices(Type iType)
{ {
if( iType == OISJoyStick ) if( iType == OISJoyStick )
return (int)mFreeWiis.size(); return (int)mFreeWiis.size();
else else
return 0; return 0;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
bool WiiMoteFactoryCreator::vendorExist(Type iType, const std::string & vendor) bool WiiMoteFactoryCreator::vendorExist(Type iType, const std::string & vendor)
{ {
if( iType == OISJoyStick && mVendorName == vendor ) if( iType == OISJoyStick && mVendorName == vendor )
return true; return true;
else else
return false; return false;
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
Object* WiiMoteFactoryCreator::createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor) Object* WiiMoteFactoryCreator::createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor)
{ {
if( mFreeWiis.size() > 0 && (vendor == "" || vendor == mVendorName ) ) if( mFreeWiis.size() > 0 && (vendor == "" || vendor == mVendorName ) )
{ {
int id = mFreeWiis.front(); int id = mFreeWiis.front();
mFreeWiis.pop_front(); mFreeWiis.pop_front();
WiiMote *wii = new WiiMote(creator, id, bufferMode, this); WiiMote *wii = new WiiMote(creator, id, bufferMode, this);
if( mtThreadRunning == false ) if( mtThreadRunning == false )
{ //Create common thread manager (this is the first wiimote created) { //Create common thread manager (this is the first wiimote created)
mtThreadRunning = true; mtThreadRunning = true;
mtThreadHandler = new boost::thread(boost::bind(&WiiMoteFactoryCreator::_updateWiiMotesThread, this)); mtThreadHandler = new boost::thread(boost::bind(&WiiMoteFactoryCreator::_updateWiiMotesThread, this));
} }
//Now, add new WiiMote to thread manager for polling //Now, add new WiiMote to thread manager for polling
{ //Get an auto lock on the list of active wiimotes { //Get an auto lock on the list of active wiimotes
boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex); boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex);
mtInUseWiiMotes.push_back(wii); mtInUseWiiMotes.push_back(wii);
} }
return wii; return wii;
} }
else else
OIS_EXCEPT(E_InputDeviceNonExistant, "No Device found which matches description!"); OIS_EXCEPT(E_InputDeviceNonExistant, "No Device found which matches description!");
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
void WiiMoteFactoryCreator::destroyObject(Object* obj) void WiiMoteFactoryCreator::destroyObject(Object* obj)
{ {
if( obj == 0 ) if( obj == 0 )
return; return;
int wiis_alive = 0; int wiis_alive = 0;
{ //Get an auto lock on the list of active wiimotes { //Get an auto lock on the list of active wiimotes
boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex); boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex);
//Find object //Find object
std::vector<WiiMote*>::iterator i = std::find(mtInUseWiiMotes.begin(), mtInUseWiiMotes.end(), obj); std::vector<WiiMote*>::iterator i = std::find(mtInUseWiiMotes.begin(), mtInUseWiiMotes.end(), obj);
if( i == mtInUseWiiMotes.end() ) if( i == mtInUseWiiMotes.end() )
OIS_EXCEPT(E_General, "Device not found in wimote collection!"); OIS_EXCEPT(E_General, "Device not found in wimote collection!");
//Erase opject //Erase opject
mtInUseWiiMotes.erase(i); mtInUseWiiMotes.erase(i);
//Delete object //Delete object
delete obj; delete obj;
wiis_alive = (int)mtInUseWiiMotes.size(); wiis_alive = (int)mtInUseWiiMotes.size();
} }
//Destroy thread if no longer in use (we do this after unlocking mutex!) //Destroy thread if no longer in use (we do this after unlocking mutex!)
if( wiis_alive == 0 && mtThreadRunning ) if( wiis_alive == 0 && mtThreadRunning )
{ {
mtThreadRunning = false; mtThreadRunning = false;
mtThreadHandler->join(); mtThreadHandler->join();
delete mtThreadHandler; delete mtThreadHandler;
mtThreadHandler = 0; mtThreadHandler = 0;
} }
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
void WiiMoteFactoryCreator::_returnWiiMote(int id) void WiiMoteFactoryCreator::_returnWiiMote(int id)
{ //Restore ID to controller pool { //Restore ID to controller pool
mFreeWiis.push_front(id); mFreeWiis.push_front(id);
} }
//---------------------------------------------------------------------------------// //---------------------------------------------------------------------------------//
bool WiiMoteFactoryCreator::_updateWiiMotesThread() bool WiiMoteFactoryCreator::_updateWiiMotesThread()
{ {
boost::xtime timer; boost::xtime timer;
while(mtThreadRunning) while(mtThreadRunning)
{ {
int numMotes = 0; int numMotes = 0;
{ //Get an auto lock on the list of active wiimotes { //Get an auto lock on the list of active wiimotes
boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex); boost::mutex::scoped_lock arrayLock(*mtWiiMoteListMutex);
numMotes = (int)mtInUseWiiMotes.size(); numMotes = (int)mtInUseWiiMotes.size();
for( std::vector<WiiMote*>::iterator i = mtInUseWiiMotes.begin(), e = mtInUseWiiMotes.end(); i != e; ++i ) for( std::vector<WiiMote*>::iterator i = mtInUseWiiMotes.begin(), e = mtInUseWiiMotes.end(); i != e; ++i )
{ //Update it { //Update it
(*i)->_threadUpdate(); (*i)->_threadUpdate();
} }
} }
//ok, we have updated all wiimotes, let us rest a bit //ok, we have updated all wiimotes, let us rest a bit
//sleep time = 30 / 1000 //sleep time = 30 / 1000
//boost::thread::sleep(xtime) todo xxx wip use sleep instead?? //boost::thread::sleep(xtime) todo xxx wip use sleep instead??
//boost::thread::yield(); //boost::thread::yield();
boost::xtime_get(&timer, boost::TIME_UTC); boost::xtime_get(&timer, boost::TIME_UTC);
timer.nsec += 20000000; //20 000 000 ~= 1/50 sec timer.nsec += 20000000; //20 000 000 ~= 1/50 sec
boost::thread::sleep(timer); boost::thread::sleep(timer);
} }
return true; return true;
} }
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef OIS_WiiMoteFactoryCreator_H #ifndef OIS_WiiMoteFactoryCreator_H
#define OIS_WiiMoteFactoryCreator_H #define OIS_WiiMoteFactoryCreator_H
#include "OISPrereqs.h" #include "OISPrereqs.h"
#include "OISFactoryCreator.h" #include "OISFactoryCreator.h"
#include <deque> #include <deque>
//Forward declare boost classes used //Forward declare boost classes used
namespace boost namespace boost
{ {
class thread; class thread;
class mutex; class mutex;
} }
namespace OIS namespace OIS
{ {
//Forward declare local classes //Forward declare local classes
class WiiMote; class WiiMote;
//! Max amount of Wiis we will attempt to find //! Max amount of Wiis we will attempt to find
#define OIS_cWiiMote_MAX_WIIS 4 #define OIS_cWiiMote_MAX_WIIS 4
/** WiiMote Factory Creator Class */ /** WiiMote Factory Creator Class */
class _OISExport WiiMoteFactoryCreator : public FactoryCreator class _OISExport WiiMoteFactoryCreator : public FactoryCreator
{ {
public: public:
WiiMoteFactoryCreator(); WiiMoteFactoryCreator();
~WiiMoteFactoryCreator(); ~WiiMoteFactoryCreator();
//FactoryCreator Overrides //FactoryCreator Overrides
/** @copydoc FactoryCreator::deviceList */ /** @copydoc FactoryCreator::deviceList */
DeviceList freeDeviceList(); DeviceList freeDeviceList();
/** @copydoc FactoryCreator::totalDevices */ /** @copydoc FactoryCreator::totalDevices */
int totalDevices(Type iType); int totalDevices(Type iType);
/** @copydoc FactoryCreator::freeDevices */ /** @copydoc FactoryCreator::freeDevices */
int freeDevices(Type iType); int freeDevices(Type iType);
/** @copydoc FactoryCreator::vendorExist */ /** @copydoc FactoryCreator::vendorExist */
bool vendorExist(Type iType, const std::string & vendor); bool vendorExist(Type iType, const std::string & vendor);
/** @copydoc FactoryCreator::createObject */ /** @copydoc FactoryCreator::createObject */
Object* createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor = ""); Object* createObject(InputManager* creator, Type iType, bool bufferMode, const std::string & vendor = "");
/** @copydoc FactoryCreator::destroyObject */ /** @copydoc FactoryCreator::destroyObject */
void destroyObject(Object* obj); void destroyObject(Object* obj);
//! Local method used to return controller to pool //! Local method used to return controller to pool
void _returnWiiMote(int id); void _returnWiiMote(int id);
protected: protected:
//! Internal - threaded method //! Internal - threaded method
bool _updateWiiMotesThread(); bool _updateWiiMotesThread();
//! String name of this vendor //! String name of this vendor
std::string mVendorName; std::string mVendorName;
//! queue of open wiimotes (int represents index into hid device) //! queue of open wiimotes (int represents index into hid device)
std::deque<int> mFreeWiis; std::deque<int> mFreeWiis;
//! Number of total wiimotes //! Number of total wiimotes
int mCount; int mCount;
//! Boost thread execution object (only alive when at least 1 wiimote is alive) //! Boost thread execution object (only alive when at least 1 wiimote is alive)
boost::thread *mtThreadHandler; boost::thread *mtThreadHandler;
//! Gaurds access to the Active WiiMote List //! Gaurds access to the Active WiiMote List
boost::mutex *mtWiiMoteListMutex; boost::mutex *mtWiiMoteListMutex;
//! List of created (active) WiiMotes //! List of created (active) WiiMotes
std::vector<WiiMote*> mtInUseWiiMotes; std::vector<WiiMote*> mtInUseWiiMotes;
//! Used to signal thread running or not //! Used to signal thread running or not
volatile bool mtThreadRunning; volatile bool mtThreadRunning;
}; };
} }
#endif //OIS_WiiMoteFactoryCreator_H #endif //OIS_WiiMoteFactoryCreator_H
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#include "OISWiiMoteForceFeedback.h" #include "OISWiiMoteForceFeedback.h"
#include "OISEffect.h" #include "OISEffect.h"
using namespace OIS; using namespace OIS;
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
WiiMoteForceFeedback::WiiMoteForceFeedback(cWiiMote &wiiMote) : mWiiMote(wiiMote), mHandle(-1) WiiMoteForceFeedback::WiiMoteForceFeedback(cWiiMote &wiiMote) : mWiiMote(wiiMote), mHandle(-1)
{ {
//One and only supported effect //One and only supported effect
_addEffectTypes( OIS::Effect::ConstantForce, OIS::Effect::Constant ); _addEffectTypes( OIS::Effect::ConstantForce, OIS::Effect::Constant );
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
WiiMoteForceFeedback::~WiiMoteForceFeedback() WiiMoteForceFeedback::~WiiMoteForceFeedback()
{ {
mWiiMote.SetVibration(false); mWiiMote.SetVibration(false);
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMoteForceFeedback::upload( const Effect* effect ) void WiiMoteForceFeedback::upload( const Effect* effect )
{ {
if( effect ) if( effect )
{ {
//Multiple effects are useless, just return //Multiple effects are useless, just return
if( mHandle != -1 || effect->_handle != -1) return; if( mHandle != -1 || effect->_handle != -1) return;
//Ok, so we are uploading a fresh effect //Ok, so we are uploading a fresh effect
effect->_handle = mHandle = 1; effect->_handle = mHandle = 1;
mWiiMote.SetVibration(true); mWiiMote.SetVibration(true);
} }
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMoteForceFeedback::modify( const Effect* effect ) void WiiMoteForceFeedback::modify( const Effect* effect )
{ {
//Nothing to modify //Nothing to modify
} }
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
void WiiMoteForceFeedback::remove( const Effect* effect ) void WiiMoteForceFeedback::remove( const Effect* effect )
{ {
//We have no effects uploaded, so just return //We have no effects uploaded, so just return
if( mHandle == -1 || effect == 0) return; if( mHandle == -1 || effect == 0) return;
if( mHandle == effect->_handle ) if( mHandle == effect->_handle )
{ {
mWiiMote.SetVibration(false); mWiiMote.SetVibration(false);
mHandle = effect->_handle = -1; mHandle = effect->_handle = -1;
} }
} }
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef OIS_WiiMoteForceFeedBack_H #ifndef OIS_WiiMoteForceFeedBack_H
#define OIS_WiiMoteForceFeedBack_H #define OIS_WiiMoteForceFeedBack_H
#include "OISPrereqs.h" #include "OISPrereqs.h"
#include "OISForceFeedback.h" #include "OISForceFeedback.h"
#include "wiimote.h" #include "wiimote.h"
namespace OIS namespace OIS
{ {
class WiiMoteForceFeedback : public ForceFeedback class WiiMoteForceFeedback : public ForceFeedback
{ {
public: public:
WiiMoteForceFeedback(cWiiMote &wiiMote); WiiMoteForceFeedback(cWiiMote &wiiMote);
~WiiMoteForceFeedback(); ~WiiMoteForceFeedback();
/** @copydoc ForceFeedback::upload */ /** @copydoc ForceFeedback::upload */
void upload( const Effect* effect ); void upload( const Effect* effect );
/** @copydoc ForceFeedback::modify */ /** @copydoc ForceFeedback::modify */
void modify( const Effect* effect ); void modify( const Effect* effect );
/** @copydoc ForceFeedback::remove */ /** @copydoc ForceFeedback::remove */
void remove( const Effect* effect ); void remove( const Effect* effect );
/** @copydoc ForceFeedback::setMasterGain */ /** @copydoc ForceFeedback::setMasterGain */
void setMasterGain( float level ) {} void setMasterGain( float level ) {}
/** @copydoc ForceFeedback::setAutoCenterMode */ /** @copydoc ForceFeedback::setAutoCenterMode */
void setAutoCenterMode( bool auto_on ) {} void setAutoCenterMode( bool auto_on ) {}
/** @copydoc ForceFeedback::getFFAxesNumber */ /** @copydoc ForceFeedback::getFFAxesNumber */
short getFFAxesNumber() { return 1; } short getFFAxesNumber() { return 1; }
protected: protected:
//! The WiiMote associated with this effect interface //! The WiiMote associated with this effect interface
cWiiMote &mWiiMote; cWiiMote &mWiiMote;
//! The handle of the one and only allowed effect //! The handle of the one and only allowed effect
int mHandle; int mHandle;
}; };
} }
#endif //OIS_WiiMoteForceFeedBack_H #endif //OIS_WiiMoteForceFeedBack_H
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
/* /*
The zlib/libpng License The zlib/libpng License
Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
This software is provided 'as-is', without any express or implied warranty. In no event will This software is provided 'as-is', without any express or implied warranty. In no event will
the authors be held liable for any damages arising from the use of this software. the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following applications, and to alter it and redistribute it freely, subject to the following
restrictions: restrictions:
1. The origin of this software must not be misrepresented; you must not claim that 1. The origin of this software must not be misrepresented; you must not claim that
you wrote the original software. If you use this software in a product, you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is an acknowledgment in the product documentation would be appreciated but is
not required. not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
# ------------------------# # ------------------------#
# Original License follows: # Original License follows:
# ------------------------# # ------------------------#
* PortAudio Portable Real-Time Audio Library * PortAudio Portable Real-Time Audio Library
* Latest version at: http://www.audiomulch.com/portaudio/ * Latest version at: http://www.audiomulch.com/portaudio/
* <platform> Implementation * <platform> Implementation
* Copyright (c) 1999-2000 <author(s)> * Copyright (c) 1999-2000 <author(s)>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files * a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, * (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, * including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software, * publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, * and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions: * subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
* *
* Any person wishing to distribute modifications to the Software is * Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that * requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. * they can be incorporated into the canonical version.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef OIS_WiiMoteRingBuffer_H #ifndef OIS_WiiMoteRingBuffer_H
#define OIS_WiiMoteRingBuffer_H #define OIS_WiiMoteRingBuffer_H
#include "OISPrereqs.h" #include "OISPrereqs.h"
namespace OIS namespace OIS
{ {
struct WiiMoteEvent struct WiiMoteEvent
{ {
//! (7 buttons) If a button was just pressed, the bit will be set //! (7 buttons) If a button was just pressed, the bit will be set
unsigned int pushedButtons; unsigned int pushedButtons;
//! (7 buttons) If a button was just released, the bit will be set //! (7 buttons) If a button was just released, the bit will be set
unsigned int releasedButtons; unsigned int releasedButtons;
//! Will be true if POV changed this event //! Will be true if POV changed this event
bool povChanged; bool povChanged;
//! Will be valid if povChanged = true //! Will be valid if povChanged = true
unsigned int povDirection; unsigned int povDirection;
//! Will be valid if a movement just occurred on main motion sensing //! Will be valid if a movement just occurred on main motion sensing
bool movement; bool movement;
//Values of main orientation vector //Values of main orientation vector
float x, y, z; float x, y, z;
//! Will be valid if a movement just occurred on main motion sensing //! Will be valid if a movement just occurred on main motion sensing
bool movementChuck; bool movementChuck;
//Values of main orientation vector //Values of main orientation vector
float nunChuckx, nunChucky, nunChuckz; float nunChuckx, nunChucky, nunChuckz;
//Used to flag when a Nunchuck axis moved //Used to flag when a Nunchuck axis moved
bool nunChuckXAxisMoved, nunChuckYAxisMoved; bool nunChuckXAxisMoved, nunChuckYAxisMoved;
//Values of NunChuck JoyStick //Values of NunChuck JoyStick
int nunChuckXAxis, nunChuckYAxis; int nunChuckXAxis, nunChuckYAxis;
//! clear initial state //! clear initial state
void clear() void clear()
{ {
pushedButtons = releasedButtons = 0; pushedButtons = releasedButtons = 0;
povChanged = false; povChanged = false;
povDirection = 0; povDirection = 0;
movement = false; movement = false;
x = y = z = 0.0f; x = y = z = 0.0f;
nunChuckx = nunChucky = nunChuckz = 0; nunChuckx = nunChucky = nunChuckz = 0;
movementChuck = false; movementChuck = false;
nunChuckXAxisMoved = nunChuckYAxisMoved = false; nunChuckXAxisMoved = nunChuckYAxisMoved = false;
nunChuckXAxis = nunChuckYAxis = 0; nunChuckXAxis = nunChuckYAxis = 0;
} }
}; };
/// <summary> /// <summary>
/// Ring Buffer (fifo) used to store 16bit pcm data /// Ring Buffer (fifo) used to store 16bit pcm data
/// </summary> /// </summary>
class WiiMoteRingBuffer class WiiMoteRingBuffer
{ {
private: private:
//! Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init //! Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init
int bufferSize; int bufferSize;
//! Used for wrapping indices with extra bit to distinguish full/empty. //! Used for wrapping indices with extra bit to distinguish full/empty.
int bigMask; int bigMask;
// Used for fitting indices to buffer. // Used for fitting indices to buffer.
int smallMask; int smallMask;
// Buffer holding the actual event buffers // Buffer holding the actual event buffers
WiiMoteEvent *buffer; WiiMoteEvent *buffer;
//! Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. //! Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex.
volatile int writeIndex; volatile int writeIndex;
//! Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. //! Index of next readable byte. Set by RingBuffer_AdvanceReadIndex.
volatile int readIndex; volatile int readIndex;
public: public:
WiiMoteRingBuffer( unsigned int numEntries ) WiiMoteRingBuffer( unsigned int numEntries )
{ {
numEntries = RoundUpToNextPowerOf2( numEntries ); numEntries = RoundUpToNextPowerOf2( numEntries );
//2 bytes per short //2 bytes per short
bufferSize = (int)numEntries; bufferSize = (int)numEntries;
buffer = new WiiMoteEvent[numEntries]; buffer = new WiiMoteEvent[numEntries];
Flush(); Flush();
bigMask = (int)(numEntries*2)-1; bigMask = (int)(numEntries*2)-1;
smallMask = (int)(numEntries)-1; smallMask = (int)(numEntries)-1;
} }
~WiiMoteRingBuffer() ~WiiMoteRingBuffer()
{ {
delete buffer; delete buffer;
} }
unsigned int RoundUpToNextPowerOf2( unsigned int n ) unsigned int RoundUpToNextPowerOf2( unsigned int n )
{ {
int numBits = 0; int numBits = 0;
if( ((n-1) & n) == 0) if( ((n-1) & n) == 0)
return n; //Already Power of two. return n; //Already Power of two.
while( n > 0 ) while( n > 0 )
{ {
n= n>>1; n= n>>1;
numBits++; numBits++;
} }
return (unsigned int)(1<<numBits); return (unsigned int)(1<<numBits);
} }
int GetReadAvailable( ) int GetReadAvailable( )
{ {
return ( (writeIndex - readIndex) & bigMask ); return ( (writeIndex - readIndex) & bigMask );
} }
int GetWriteAvailable( ) int GetWriteAvailable( )
{ {
return ( bufferSize - GetReadAvailable()); return ( bufferSize - GetReadAvailable());
} }
int Write( WiiMoteEvent *data, int numEntries ) int Write( WiiMoteEvent *data, int numEntries )
{ {
int size1 = 0, size2 = 0, numWritten; int size1 = 0, size2 = 0, numWritten;
int data1Ptr = 0, data2Ptr = 0; int data1Ptr = 0, data2Ptr = 0;
numWritten = GetWriteRegions( numEntries, data1Ptr, size1, data2Ptr, size2 ); numWritten = GetWriteRegions( numEntries, data1Ptr, size1, data2Ptr, size2 );
if( size2 > 0 ) if( size2 > 0 )
{ {
//copy to two parts //copy to two parts
memcpy( &buffer[data1Ptr], data, sizeof(WiiMoteEvent) * size1 ); memcpy( &buffer[data1Ptr], data, sizeof(WiiMoteEvent) * size1 );
//Array.Copy( data, offsetPtr, buffer, data1Ptr, size1 ); //Array.Copy( data, offsetPtr, buffer, data1Ptr, size1 );
memcpy( &buffer[data2Ptr], &data[size1], sizeof(WiiMoteEvent) * size2 ); memcpy( &buffer[data2Ptr], &data[size1], sizeof(WiiMoteEvent) * size2 );
//Array.Copy( data, offsetPtr + size1, buffer, data2Ptr, size2 ); //Array.Copy( data, offsetPtr + size1, buffer, data2Ptr, size2 );
} }
else else
{ //Copy all continous { //Copy all continous
memcpy( &buffer[data1Ptr], data, sizeof(WiiMoteEvent) * size1 ); memcpy( &buffer[data1Ptr], data, sizeof(WiiMoteEvent) * size1 );
//Array.Copy( data, offsetPtr, buffer, data1Ptr, size1 ); //Array.Copy( data, offsetPtr, buffer, data1Ptr, size1 );
} }
AdvanceWriteIndex( numWritten ); AdvanceWriteIndex( numWritten );
return numWritten; return numWritten;
} }
/// <summary> /// <summary>
/// Reads requested number of entries into sent array. /// Reads requested number of entries into sent array.
/// Returns number written /// Returns number written
/// </summary> /// </summary>
int Read( WiiMoteEvent *data, int numEntries ) int Read( WiiMoteEvent *data, int numEntries )
{ {
int size1 = 0, size2 = 0, numRead, data1Ptr = 0, data2Ptr = 0; int size1 = 0, size2 = 0, numRead, data1Ptr = 0, data2Ptr = 0;
numRead = GetReadRegions( numEntries, data1Ptr, size1, data2Ptr, size2 ); numRead = GetReadRegions( numEntries, data1Ptr, size1, data2Ptr, size2 );
if( size2 > 0 ) if( size2 > 0 )
{ {
memcpy( data, &buffer[data1Ptr], sizeof(WiiMoteEvent) * size1 ); memcpy( data, &buffer[data1Ptr], sizeof(WiiMoteEvent) * size1 );
//Array.Copy( buffer, data1Ptr, data, 0, size1 ); //Array.Copy( buffer, data1Ptr, data, 0, size1 );
memcpy( &data[size1], &buffer[data2Ptr], sizeof(WiiMoteEvent) * size2 ); memcpy( &data[size1], &buffer[data2Ptr], sizeof(WiiMoteEvent) * size2 );
//Array.Copy( buffer, data2Ptr, data, size1, size2 ); //Array.Copy( buffer, data2Ptr, data, size1, size2 );
} }
else else
memcpy( data, &buffer[data1Ptr], sizeof(WiiMoteEvent) * size1 ); memcpy( data, &buffer[data1Ptr], sizeof(WiiMoteEvent) * size1 );
//Array.Copy( buffer, data1Ptr, data, 0, size1 ); //Array.Copy( buffer, data1Ptr, data, 0, size1 );
AdvanceReadIndex( numRead ); AdvanceReadIndex( numRead );
return numRead; return numRead;
} }
private: private:
int GetWriteRegions( int numEntries, int &dataPtr1, int &sizePtr1, int GetWriteRegions( int numEntries, int &dataPtr1, int &sizePtr1,
int &dataPtr2, int &sizePtr2 ) int &dataPtr2, int &sizePtr2 )
{ {
int index; int index;
int available = GetWriteAvailable(); int available = GetWriteAvailable();
if( numEntries > available ) if( numEntries > available )
numEntries = available; numEntries = available;
//Check to see if write is not contiguous. //Check to see if write is not contiguous.
index = writeIndex & smallMask; index = writeIndex & smallMask;
if( (index + numEntries) > bufferSize ) if( (index + numEntries) > bufferSize )
{ {
//Write data in two blocks that wrap the buffer. //Write data in two blocks that wrap the buffer.
int firstHalf = bufferSize - index; int firstHalf = bufferSize - index;
dataPtr1 = index;//&buffer[index]; dataPtr1 = index;//&buffer[index];
sizePtr1 = firstHalf; sizePtr1 = firstHalf;
dataPtr2 = 0;//&buffer[0]; dataPtr2 = 0;//&buffer[0];
sizePtr2 = numEntries - firstHalf; sizePtr2 = numEntries - firstHalf;
} }
else else
{ {
dataPtr1 = index;//&buffer[index]; dataPtr1 = index;//&buffer[index];
sizePtr1 = numEntries; sizePtr1 = numEntries;
dataPtr2 = 0; dataPtr2 = 0;
sizePtr2 = 0; sizePtr2 = 0;
} }
return numEntries; return numEntries;
} }
int GetReadRegions( int numEntries, int &dataPtr1, int &sizePtr1, int &dataPtr2, int &sizePtr2 ) int GetReadRegions( int numEntries, int &dataPtr1, int &sizePtr1, int &dataPtr2, int &sizePtr2 )
{ {
int index; int index;
int available = GetReadAvailable( ); int available = GetReadAvailable( );
if( numEntries > available ) if( numEntries > available )
numEntries = available; numEntries = available;
// Check to see if read is not contiguous // Check to see if read is not contiguous
index = readIndex & smallMask; index = readIndex & smallMask;
if( (index + numEntries) > bufferSize ) if( (index + numEntries) > bufferSize )
{ {
// Write data in two blocks that wrap the buffer // Write data in two blocks that wrap the buffer
int firstHalf = bufferSize - index; int firstHalf = bufferSize - index;
dataPtr1 = index;//&buffer[index]; dataPtr1 = index;//&buffer[index];
sizePtr1 = firstHalf; sizePtr1 = firstHalf;
dataPtr2 = 0;//&buffer[0]; dataPtr2 = 0;//&buffer[0];
sizePtr2 = numEntries - firstHalf; sizePtr2 = numEntries - firstHalf;
} }
else else
{ {
dataPtr1 = index;//&buffer[index]; dataPtr1 = index;//&buffer[index];
sizePtr1 = numEntries; sizePtr1 = numEntries;
dataPtr2 = 0; dataPtr2 = 0;
sizePtr2 = 0; sizePtr2 = 0;
} }
return numEntries; return numEntries;
} }
int AdvanceWriteIndex( int numEntries ) int AdvanceWriteIndex( int numEntries )
{ {
return writeIndex = (writeIndex + numEntries) & bigMask; return writeIndex = (writeIndex + numEntries) & bigMask;
} }
int AdvanceReadIndex( int numEntries ) int AdvanceReadIndex( int numEntries )
{ {
return readIndex = (readIndex + numEntries) & bigMask; return readIndex = (readIndex + numEntries) & bigMask;
} }
void Flush( ) void Flush( )
{ {
writeIndex = readIndex = 0; writeIndex = readIndex = 0;
} }
}; };
} }
#endif //#define OIS_WiiMoteRingBuffer_H #endif //#define OIS_WiiMoteRingBuffer_H
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
//cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com) //cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
//This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code. //This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code.
//This was based in part on Alan Macek <www.alanmacek.com>'s USB interface library //This was based in part on Alan Macek <www.alanmacek.com>'s USB interface library
//Edited for Toshiba Stack support (hopefully also all others) by //Edited for Toshiba Stack support (hopefully also all others) by
//Sean Stellingwerff (http://sean.stellingwerff.com) using information //Sean Stellingwerff (http://sean.stellingwerff.com) using information
//gathered from http://www.lvr.com/hidpage.htm (Thanks a million! :D) //gathered from http://www.lvr.com/hidpage.htm (Thanks a million! :D)
//#include "stdafx.h" //#include "stdafx.h"
#include "hiddevice.h" #include "hiddevice.h"
extern "C" extern "C"
{ {
#include "hidsdi.h" #include "hidsdi.h"
#include <Setupapi.h> #include <Setupapi.h>
} }
#pragma comment(lib, "setupapi.lib") #pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "hid.lib") #pragma comment(lib, "hid.lib")
HIDP_CAPS Capabilities; HIDP_CAPS Capabilities;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData; PSP_DEVICE_INTERFACE_DETAIL_DATA detailData;
cHIDDevice::cHIDDevice() : mConnected(false), mHandle(NULL), mEvent(NULL) cHIDDevice::cHIDDevice() : mConnected(false), mHandle(NULL), mEvent(NULL)
{ {
} }
cHIDDevice::~cHIDDevice() cHIDDevice::~cHIDDevice()
{ {
if (mConnected) if (mConnected)
{ {
Disconnect(); Disconnect();
} }
} }
bool cHIDDevice::Disconnect() bool cHIDDevice::Disconnect()
{ {
bool retval = false; bool retval = false;
if (mConnected) if (mConnected)
{ {
retval = (CloseHandle(mHandle) == TRUE && CloseHandle(mEvent) == TRUE); retval = (CloseHandle(mHandle) == TRUE && CloseHandle(mEvent) == TRUE);
mConnected = false; mConnected = false;
} }
return retval; return retval;
} }
bool cHIDDevice::Connect(unsigned short device_id, unsigned short vendor_id, int index) bool cHIDDevice::Connect(unsigned short device_id, unsigned short vendor_id, int index)
{ {
if (mConnected) if (mConnected)
{ {
if (!Disconnect()) if (!Disconnect())
{ {
return false; return false;
} }
} }
// Find the wiimote(s) // Find the wiimote(s)
//for (int i = 0; i <= index; i++) //for (int i = 0; i <= index; i++)
OpenDevice( device_id, vendor_id, index ); OpenDevice( device_id, vendor_id, index );
return mConnected; return mConnected;
} }
bool cHIDDevice::OpenDevice(unsigned short device_id, unsigned short vendor_id, int index) bool cHIDDevice::OpenDevice(unsigned short device_id, unsigned short vendor_id, int index)
{ {
//Use a series of API calls to find a HID with a specified Vendor IF and Product ID. //Use a series of API calls to find a HID with a specified Vendor IF and Product ID.
HIDD_ATTRIBUTES Attributes; HIDD_ATTRIBUTES Attributes;
SP_DEVICE_INTERFACE_DATA devInfoData; SP_DEVICE_INTERFACE_DATA devInfoData;
bool LastDevice = FALSE; bool LastDevice = FALSE;
bool MyDeviceDetected = FALSE; bool MyDeviceDetected = FALSE;
int MemberIndex = 0; int MemberIndex = 0;
int MembersFound = 0; int MembersFound = 0;
GUID HidGuid; GUID HidGuid;
ULONG Length; ULONG Length;
LONG Result; LONG Result;
HANDLE hDevInfo; HANDLE hDevInfo;
ULONG Required; ULONG Required;
Length = 0; Length = 0;
detailData = NULL; detailData = NULL;
mHandle=NULL; mHandle=NULL;
HidD_GetHidGuid(&HidGuid); HidD_GetHidGuid(&HidGuid);
hDevInfo=SetupDiGetClassDevs(&HidGuid, NULL, NULL, DIGCF_PRESENT|DIGCF_INTERFACEDEVICE); hDevInfo=SetupDiGetClassDevs(&HidGuid, NULL, NULL, DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
devInfoData.cbSize = sizeof(devInfoData); devInfoData.cbSize = sizeof(devInfoData);
MemberIndex = 0; MemberIndex = 0;
MembersFound = 0; MembersFound = 0;
LastDevice = FALSE; LastDevice = FALSE;
do do
{ {
Result=SetupDiEnumDeviceInterfaces(hDevInfo, 0, &HidGuid, MemberIndex, &devInfoData); Result=SetupDiEnumDeviceInterfaces(hDevInfo, 0, &HidGuid, MemberIndex, &devInfoData);
if (Result != 0) if (Result != 0)
{ {
Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, NULL, 0, &Length, NULL); Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, NULL, 0, &Length, NULL);
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length); detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length);
detailData -> cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); detailData -> cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, detailData, Length, &Required, NULL); Result = SetupDiGetDeviceInterfaceDetail(hDevInfo, &devInfoData, detailData, Length, &Required, NULL);
mHandle=CreateFile(detailData->DevicePath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING, 0, NULL); mHandle=CreateFile(detailData->DevicePath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING, 0, NULL);
Attributes.Size = sizeof(Attributes); Attributes.Size = sizeof(Attributes);
Result = HidD_GetAttributes(mHandle, &Attributes); Result = HidD_GetAttributes(mHandle, &Attributes);
//Is it the desired device? //Is it the desired device?
MyDeviceDetected = FALSE; MyDeviceDetected = FALSE;
if (Attributes.VendorID == vendor_id) if (Attributes.VendorID == vendor_id)
{ {
if (Attributes.ProductID == device_id) if (Attributes.ProductID == device_id)
{ {
if (MembersFound == index) if (MembersFound == index)
{ {
//Both the Vendor ID and Product ID match. //Both the Vendor ID and Product ID match.
//printf("Wiimote found!\n"); //printf("Wiimote found!\n");
mConnected = true; mConnected = true;
GetCapabilities(); GetCapabilities();
WriteHandle=CreateFile(detailData->DevicePath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, NULL); WriteHandle=CreateFile(detailData->DevicePath, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, NULL);
MyDeviceDetected = TRUE; MyDeviceDetected = TRUE;
PrepareForOverlappedTransfer(); PrepareForOverlappedTransfer();
mEvent = CreateEvent(NULL, TRUE, TRUE, ""); mEvent = CreateEvent(NULL, TRUE, TRUE, "");
mOverlapped.Offset = 0; mOverlapped.Offset = 0;
mOverlapped.OffsetHigh = 0; mOverlapped.OffsetHigh = 0;
mOverlapped.hEvent = mEvent; mOverlapped.hEvent = mEvent;
} else { } else {
//The Product ID doesn't match. //The Product ID doesn't match.
CloseHandle(mHandle); CloseHandle(mHandle);
} }
MembersFound++; MembersFound++;
} }
} else { } else {
CloseHandle(mHandle); CloseHandle(mHandle);
} }
free(detailData); free(detailData);
} else { } else {
LastDevice=TRUE; LastDevice=TRUE;
} }
MemberIndex = MemberIndex + 1; MemberIndex = MemberIndex + 1;
} while ((LastDevice == FALSE) && (MyDeviceDetected == FALSE)); } while ((LastDevice == FALSE) && (MyDeviceDetected == FALSE));
SetupDiDestroyDeviceInfoList(hDevInfo); SetupDiDestroyDeviceInfoList(hDevInfo);
return MyDeviceDetected; return MyDeviceDetected;
} }
bool cHIDDevice::WriteToDevice(unsigned const char * OutputReport, int num_bytes) bool cHIDDevice::WriteToDevice(unsigned const char * OutputReport, int num_bytes)
{ {
bool retval = false; bool retval = false;
if (mConnected) if (mConnected)
{ {
DWORD bytes_written; DWORD bytes_written;
retval = (WriteFile( WriteHandle, OutputReport, num_bytes, &bytes_written, &mOverlapped) == TRUE); retval = (WriteFile( WriteHandle, OutputReport, num_bytes, &bytes_written, &mOverlapped) == TRUE);
retval = retval && bytes_written == num_bytes; retval = retval && bytes_written == num_bytes;
} }
return retval; return retval;
} }
void cHIDDevice::PrepareForOverlappedTransfer() void cHIDDevice::PrepareForOverlappedTransfer()
{ {
//Get a handle to the device for the overlapped ReadFiles. //Get a handle to the device for the overlapped ReadFiles.
ReadHandle=CreateFile(detailData->DevicePath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); ReadHandle=CreateFile(detailData->DevicePath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
} }
void cHIDDevice::GetCapabilities() void cHIDDevice::GetCapabilities()
{ {
//Get the Capabilities structure for the device. //Get the Capabilities structure for the device.
PHIDP_PREPARSED_DATA PreparsedData; PHIDP_PREPARSED_DATA PreparsedData;
HidD_GetPreparsedData(mHandle, &PreparsedData); HidD_GetPreparsedData(mHandle, &PreparsedData);
HidP_GetCaps(PreparsedData, &Capabilities); HidP_GetCaps(PreparsedData, &Capabilities);
//No need for PreparsedData any more, so free the memory it's using. //No need for PreparsedData any more, so free the memory it's using.
HidD_FreePreparsedData(PreparsedData); HidD_FreePreparsedData(PreparsedData);
} }
bool cHIDDevice::ReadFromDevice(unsigned const char * buffer, int max_bytes, int & bytes_read, int timeout) bool cHIDDevice::ReadFromDevice(unsigned const char * buffer, int max_bytes, int & bytes_read, int timeout)
{ {
bool retval = false; bool retval = false;
if (mConnected) if (mConnected)
{ {
ReadFile( ReadHandle, (LPVOID)buffer,max_bytes,(LPDWORD)&bytes_read,(LPOVERLAPPED) &mOverlapped); ReadFile( ReadHandle, (LPVOID)buffer,max_bytes,(LPDWORD)&bytes_read,(LPOVERLAPPED) &mOverlapped);
DWORD Result = WaitForSingleObject(mEvent, timeout); DWORD Result = WaitForSingleObject(mEvent, timeout);
if (Result == WAIT_OBJECT_0) if (Result == WAIT_OBJECT_0)
{ {
retval = true; retval = true;
} }
else else
{ {
CancelIo(mHandle); CancelIo(mHandle);
} }
ResetEvent(mEvent); ResetEvent(mEvent);
} }
return retval; return retval;
} }
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
//cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com) //cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
//This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code. //This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code.
#ifndef HIDDEVICE_H #ifndef HIDDEVICE_H
#define HIDDEVICE_H #define HIDDEVICE_H
#include <windows.h> #include <windows.h>
class cHIDDevice class cHIDDevice
{ {
public: public:
cHIDDevice(); cHIDDevice();
~cHIDDevice(); ~cHIDDevice();
bool Disconnect(); bool Disconnect();
bool Connect(unsigned short device_id, unsigned short vendor_id, int index=0); bool Connect(unsigned short device_id, unsigned short vendor_id, int index=0);
bool IsConnected() const {return mConnected;} bool IsConnected() const {return mConnected;}
bool WriteToDevice(unsigned const char * OutputReport, int num_bytes); bool WriteToDevice(unsigned const char * OutputReport, int num_bytes);
bool ReadFromDevice(unsigned const char * buffer, int max_bytes, int & bytes_read, int timeout=50); bool ReadFromDevice(unsigned const char * buffer, int max_bytes, int & bytes_read, int timeout=50);
private: private:
//bool OpenDevice(int index, unsigned short device_id, unsigned short vendor_id); //bool OpenDevice(int index, unsigned short device_id, unsigned short vendor_id);
bool OpenDevice(unsigned short device_id, unsigned short vendor_id, int index); bool OpenDevice(unsigned short device_id, unsigned short vendor_id, int index);
//bool FindWiimote(); //bool FindWiimote();
void GetCapabilities(); void GetCapabilities();
void PrepareForOverlappedTransfer(); void PrepareForOverlappedTransfer();
HANDLE mHandle; HANDLE mHandle;
HANDLE mEvent; HANDLE mEvent;
HANDLE WriteHandle; HANDLE WriteHandle;
HANDLE ReadHandle; HANDLE ReadHandle;
OVERLAPPED mOverlapped; OVERLAPPED mOverlapped;
OVERLAPPED HIDOverlapped; OVERLAPPED HIDOverlapped;
// HIDP_CAPS Capabilities; // HIDP_CAPS Capabilities;
bool mConnected; bool mConnected;
}; };
#endif #endif
#endif #endif
//cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com) //cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
//This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code. //This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code.
//#include "wiimote.h" //#include "wiimote.h"
//#include <stdio.h> //#include <stdio.h>
//Features: //Features:
// Read Accelerometer, button values from the wiimote // Read Accelerometer, button values from the wiimote
// Read Accelerometer, stick, and button values from the nunchuck // Read Accelerometer, stick, and button values from the nunchuck
// Preliminary IR support // Preliminary IR support
//Known issues: //Known issues:
// The IR support is spotty at best. It tends to kick out if you plug your 'chuck in and out too many times // The IR support is spotty at best. It tends to kick out if you plug your 'chuck in and out too many times
// Reading 'chuck calibration data doesn't seem to work, so the code just uses defaults // Reading 'chuck calibration data doesn't seem to work, so the code just uses defaults
// Multiple Wiimote support not yet tested // Multiple Wiimote support not yet tested
// May only work with Bluesoleil stack? // May only work with Bluesoleil stack?
//Instructions: //Instructions:
// See below for how to connect to a device and start the data stream. // See below for how to connect to a device and start the data stream.
// It is up to the user to call heartbeat fast enough - if you're too slow, you will loose data. Ideally, this would be done in a separate thread // It is up to the user to call heartbeat fast enough - if you're too slow, you will loose data. Ideally, this would be done in a separate thread
// There are several public functions for getting the values from the wiimote. Look in cWiiMote::PrintStatus for examples. // There are several public functions for getting the values from the wiimote. Look in cWiiMote::PrintStatus for examples.
//Version History: //Version History:
//0.1 Preliminary Release //0.1 Preliminary Release
//0.2 Added nunchuck, IR support //0.2 Added nunchuck, IR support
/* /*
int main(int nargs, const char * cargs) int main(int nargs, const char * cargs)
{ {
cWiiMote wiimote; cWiiMote wiimote;
if (wiimote.ConnectToDevice() && if (wiimote.ConnectToDevice() &&
wiimote.StartDataStream()) wiimote.StartDataStream())
{ {
for (;;) for (;;)
{ {
wiimote.HeartBeat(); wiimote.HeartBeat();
wiimote.PrintStatus(); wiimote.PrintStatus();
} }
} }
return 0; return 0;
} }
*/ */
//#eof "$Id: main.cpp,v 1.1.2.1 2008/02/14 03:33:36 pjcast Exp $" //#eof "$Id: main.cpp,v 1.1.2.1 2008/02/14 03:33:36 pjcast Exp $"
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
//cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com) //cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
//This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code. //This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code.
//Edited for Toshiba Stack support (hopefully also all others) by //Edited for Toshiba Stack support (hopefully also all others) by
//Sean Stellingwerff (http://sean.stellingwerff.com) using information //Sean Stellingwerff (http://sean.stellingwerff.com) using information
//gathered from http://www.lvr.com/hidpage.htm (Thanks a million! :D) //gathered from http://www.lvr.com/hidpage.htm (Thanks a million! :D)
//#include "stdafx.h" //#include "stdafx.h"
#include "wiimote.h" #include "wiimote.h"
#include <stdio.h> #include <stdio.h>
//output channels //output channels
const unsigned char OUTPUT_CHANNEL_FORCE_FEEDBACK = 0x13; const unsigned char OUTPUT_CHANNEL_FORCE_FEEDBACK = 0x13;
const unsigned char OUTPUT_CHANNEL_LED = 0x11; const unsigned char OUTPUT_CHANNEL_LED = 0x11;
const unsigned char OUTPUT_CHANNEL_REPORT = 0x12; const unsigned char OUTPUT_CHANNEL_REPORT = 0x12;
const unsigned char OUTPUT_READ_MEMORY = 0x17; const unsigned char OUTPUT_READ_MEMORY = 0x17;
const unsigned char OUTPUT_WRITE_MEMORY = 0x16; const unsigned char OUTPUT_WRITE_MEMORY = 0x16;
const unsigned char OUTPUT_ENABLE_IR = 0x13; const unsigned char OUTPUT_ENABLE_IR = 0x13;
const unsigned char OUTPUT_ENABLE_IR2 = 0x1a; const unsigned char OUTPUT_ENABLE_IR2 = 0x1a;
//report request types //report request types
const unsigned char REQUEST_CONTINUOUS_REPORTS = 0x4; const unsigned char REQUEST_CONTINUOUS_REPORTS = 0x4;
const unsigned char REQUEST_SINGLE_REPORTS = 0x0; const unsigned char REQUEST_SINGLE_REPORTS = 0x0;
//input channels //input channels
const unsigned char INPUT_CHANNEL_BUTTONS_ONLY = 0x30; const unsigned char INPUT_CHANNEL_BUTTONS_ONLY = 0x30;
const unsigned char INPUT_CHANNEL_BUTTONS_MOTION = 0x31; const unsigned char INPUT_CHANNEL_BUTTONS_MOTION = 0x31;
const unsigned char INPUT_CHANNEL_WRITE_CONFIRM = 0x22; const unsigned char INPUT_CHANNEL_WRITE_CONFIRM = 0x22;
const unsigned char INPUT_CHANNEL_EXPANSION_PORT = 0x20; const unsigned char INPUT_CHANNEL_EXPANSION_PORT = 0x20;
const unsigned char INPUT_CHANNEL_MOTION_IR = 0x33; const unsigned char INPUT_CHANNEL_MOTION_IR = 0x33;
const unsigned char INPUT_CHANNEL_MOTION_CHUCK_IR = 0x37; const unsigned char INPUT_CHANNEL_MOTION_CHUCK_IR = 0x37;
const unsigned char INPUT_CHANNEL_MOTION_CHUCK = 0x35; const unsigned char INPUT_CHANNEL_MOTION_CHUCK = 0x35;
//the ID values for a wiimote //the ID values for a wiimote
const unsigned short mVendorID = 0x057E; const unsigned short mVendorID = 0x057E;
const unsigned short mDeviceID = 0x0306; const unsigned short mDeviceID = 0x0306;
//how to find the calibration data for the wiimote //how to find the calibration data for the wiimote
const unsigned short CALIBRATION_ADDRESS = 0x16; const unsigned short CALIBRATION_ADDRESS = 0x16;
const unsigned short CALIBRATION_DATA_LENGTH = 7; const unsigned short CALIBRATION_DATA_LENGTH = 7;
//nunchuck constants //nunchuck constants
const unsigned long NUNCHUCK_STATUS_ADDRESS = 0x04A40000; const unsigned long NUNCHUCK_STATUS_ADDRESS = 0x04A40000;
const unsigned long NUNCHUCK_CALIBRATION_ADDRESS = 0x04A40020; const unsigned long NUNCHUCK_CALIBRATION_ADDRESS = 0x04A40020;
const unsigned long NUNCHUCK_CALIBRATION_ADDRESS_2 = 0x04A40030; const unsigned long NUNCHUCK_CALIBRATION_ADDRESS_2 = 0x04A40030;
const unsigned long NUNCHUCK_INIT_ADDRESS= 0x04A40040; const unsigned long NUNCHUCK_INIT_ADDRESS= 0x04A40040;
const unsigned long NUNCHUK_ID_ADDRESS = 0x04a400f0; const unsigned long NUNCHUK_ID_ADDRESS = 0x04a400f0;
const unsigned char NUNCHUCK_INIT_VAL= 0x0; const unsigned char NUNCHUCK_INIT_VAL= 0x0;
//IR constants //IR constants
const unsigned long IR_REG_1 = 0x04b00030; const unsigned long IR_REG_1 = 0x04b00030;
const unsigned long IR_REG_2 = 0x04b00033; const unsigned long IR_REG_2 = 0x04b00033;
const unsigned long IR_SENS_ADDR_1 = 0x04b00000; const unsigned long IR_SENS_ADDR_1 = 0x04b00000;
const unsigned long IR_SENS_ADDR_2 = 0x04b0001a; 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_PART1[] = {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64};
const unsigned char IR_SENS_MIDRANGE_PART2[] = {0x63, 0x03}; const unsigned char IR_SENS_MIDRANGE_PART2[] = {0x63, 0x03};
const unsigned char IR_MODE_OFF = 0; const unsigned char IR_MODE_OFF = 0;
const unsigned char IR_MODE_STD = 1; const unsigned char IR_MODE_STD = 1;
const unsigned char IR_MODE_EXP = 3; const unsigned char IR_MODE_EXP = 3;
const unsigned char IR_MODE_FULL = 5; const unsigned char IR_MODE_FULL = 5;
cWiiMote::cWiiMote() cWiiMote::cWiiMote()
{ {
Init(); Init();
} }
cWiiMote::~cWiiMote() cWiiMote::~cWiiMote()
{ {
Disconnect(); Disconnect();
} }
void cWiiMote::Init() void cWiiMote::Init()
{ {
mReportMode = REPORT_MODE_EVENT_BUTTONS; mReportMode = REPORT_MODE_EVENT_BUTTONS;
mLastButtonStatus.Init(); mLastButtonStatus.Init();
mLastExpansionReport.Init(); mLastExpansionReport.Init();
mLastMotionReport.Init(); mLastMotionReport.Init();
mOutputControls.Init(); mOutputControls.Init();
mReadInfo.Init(); mReadInfo.Init();
mAccelCalibrationData.Init(); mAccelCalibrationData.Init();
mNunchuckAccelCalibrationData.Init(); mNunchuckAccelCalibrationData.Init();
mNunchuckStickCalibrationData.Init(); mNunchuckStickCalibrationData.Init();
mLastIRReport.Init(); mLastIRReport.Init();
mNunchuckAttached = false; mNunchuckAttached = false;
mIRRunning = false; mIRRunning = false;
mDataStreamRunning = false; mDataStreamRunning = false;
} }
bool cWiiMote::SetReportMode(eReportMode mode) bool cWiiMote::SetReportMode(eReportMode mode)
{ {
mReportMode = mode; mReportMode = mode;
return SendReportMode(); return SendReportMode();
} }
bool cWiiMote::SendReportMode() bool cWiiMote::SendReportMode()
{ {
bool continuous = true; bool continuous = true;
unsigned char channel = INPUT_CHANNEL_BUTTONS_ONLY; unsigned char channel = INPUT_CHANNEL_BUTTONS_ONLY;
bool check_chuck = false; bool check_chuck = false;
switch (mReportMode) switch (mReportMode)
{ {
case REPORT_MODE_MOTION_IR: case REPORT_MODE_MOTION_IR:
channel = INPUT_CHANNEL_MOTION_IR; channel = INPUT_CHANNEL_MOTION_IR;
break; break;
case REPORT_MODE_MOTION_CHUCK_IR: case REPORT_MODE_MOTION_CHUCK_IR:
channel = INPUT_CHANNEL_MOTION_CHUCK_IR; channel = INPUT_CHANNEL_MOTION_CHUCK_IR;
check_chuck = true; check_chuck = true;
break; break;
case REPORT_MODE_MOTION_CHUCK: case REPORT_MODE_MOTION_CHUCK:
channel = INPUT_CHANNEL_MOTION_CHUCK; channel = INPUT_CHANNEL_MOTION_CHUCK;
check_chuck = true; check_chuck = true;
break; break;
case REPORT_MODE_MOTION: case REPORT_MODE_MOTION:
channel = INPUT_CHANNEL_BUTTONS_MOTION; channel = INPUT_CHANNEL_BUTTONS_MOTION;
break; break;
case REPORT_MODE_EVENT_BUTTONS: case REPORT_MODE_EVENT_BUTTONS:
channel = INPUT_CHANNEL_BUTTONS_ONLY; channel = INPUT_CHANNEL_BUTTONS_ONLY;
continuous = false; continuous = false;
break; break;
default: default:
break; break;
} }
//check to make sure that there is a chuck attached //check to make sure that there is a chuck attached
// if (check_chuck && !mNunchuckAttached) // if (check_chuck && !mNunchuckAttached)
// { // {
// printf("Supposed to check for nunchuck, but couldn't find one!"); // printf("Supposed to check for nunchuck, but couldn't find one!");
// return false; // return false;
// } // }
bool retval = SelectInputChannel(continuous,channel); bool retval = SelectInputChannel(continuous,channel);
return retval; return retval;
} }
bool cWiiMote::ConnectToDevice(int index) bool cWiiMote::ConnectToDevice(int index)
{ {
Init(); Init();
const bool retval = mHIDDevice.Connect(mDeviceID,mVendorID,index) && const bool retval = mHIDDevice.Connect(mDeviceID,mVendorID,index) &&
SetReportMode(REPORT_MODE_MOTION_CHUCK_IR) && SetReportMode(REPORT_MODE_MOTION_CHUCK_IR) &&
UpdateOutput() && UpdateOutput() &&
ReadCalibrationData(); ReadCalibrationData();
if (retval) if (retval)
{ {
InitNunchuck(); InitNunchuck();
} }
return retval; return retval;
} }
bool cWiiMote::Disconnect() bool cWiiMote::Disconnect()
{ {
bool retval = false; bool retval = false;
StopDataStream(); StopDataStream();
if (mHIDDevice.IsConnected()) if (mHIDDevice.IsConnected())
{ {
retval = mHIDDevice.Disconnect(); retval = mHIDDevice.Disconnect();
} }
return retval; return retval;
} }
bool cWiiMote::SetVibration(bool vib_on) bool cWiiMote::SetVibration(bool vib_on)
{ {
bool retval = true; bool retval = true;
if (mOutputControls.mVibration != vib_on) if (mOutputControls.mVibration != vib_on)
{ {
mOutputControls.mVibration = vib_on; mOutputControls.mVibration = vib_on;
retval = UpdateOutput(); retval = UpdateOutput();
} }
return retval; return retval;
} }
void cWiiMote::ClearBuffer() void cWiiMote::ClearBuffer()
{ {
memset(mOutputBuffer,0, mOutputBufferSize); memset(mOutputBuffer,0, mOutputBufferSize);
} }
bool cWiiMote::SetLEDs(bool led1, bool led2, bool led3, bool led4) bool cWiiMote::SetLEDs(bool led1, bool led2, bool led3, bool led4)
{ {
const bool no_change = mOutputControls.mLED1 == led1 && const bool no_change = mOutputControls.mLED1 == led1 &&
mOutputControls.mLED2 == led2 && mOutputControls.mLED2 == led2 &&
mOutputControls.mLED3 == led3 && mOutputControls.mLED3 == led3 &&
mOutputControls.mLED4 == led4; mOutputControls.mLED4 == led4;
if (no_change) if (no_change)
{ {
return true; return true;
} }
mOutputControls.mLED1 = led1; mOutputControls.mLED1 = led1;
mOutputControls.mLED2 = led2; mOutputControls.mLED2 = led2;
mOutputControls.mLED3 = led3; mOutputControls.mLED3 = led3;
mOutputControls.mLED4 = led4; mOutputControls.mLED4 = led4;
return UpdateOutput(); return UpdateOutput();
} }
bool cWiiMote::UpdateOutput() bool cWiiMote::UpdateOutput()
{ {
ClearBuffer(); ClearBuffer();
mOutputBuffer[0] = OUTPUT_CHANNEL_LED; mOutputBuffer[0] = OUTPUT_CHANNEL_LED;
mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0) | mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0) |
(mOutputControls.mLED1 ? 0x1 : 0x0) << 4 | (mOutputControls.mLED1 ? 0x1 : 0x0) << 4 |
(mOutputControls.mLED2 ? 0x1 : 0x0) << 5 | (mOutputControls.mLED2 ? 0x1 : 0x0) << 5 |
(mOutputControls.mLED3 ? 0x1 : 0x0) << 6 | (mOutputControls.mLED3 ? 0x1 : 0x0) << 6 |
(mOutputControls.mLED4 ? 0x1 : 0x0) << 7; (mOutputControls.mLED4 ? 0x1 : 0x0) << 7;
return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize); return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
} }
bool cWiiMote::HeartBeat(int timeout) bool cWiiMote::HeartBeat(int timeout)
{ {
bool retval = true; bool retval = true;
int bytes_read = 0; int bytes_read = 0;
//most of these reports aren't implemented yet. I don't have a sensor bar or a nunchuck :) //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)) if (mHIDDevice.ReadFromDevice(mInputBuffer,mInputBufferSize,bytes_read) && (bytes_read > 0,timeout))
{ {
const int channel = mInputBuffer[0]; const int channel = mInputBuffer[0];
switch (channel) switch (channel)
{ {
case INPUT_CHANNEL_EXPANSION_PORT:// 6 Expansion Port change case INPUT_CHANNEL_EXPANSION_PORT:// 6 Expansion Port change
{ {
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
ParseExpansionReport(&mInputBuffer[2]); ParseExpansionReport(&mInputBuffer[2]);
bool restart = mDataStreamRunning; bool restart = mDataStreamRunning;
StopDataStream(); StopDataStream();
InitNunchuck(); InitNunchuck();
if (restart) if (restart)
{ {
retval = StartDataStream(); retval = StartDataStream();
} }
} }
break; break;
case INPUT_CHANNEL_BUTTONS_ONLY:// 2 Buttons only case INPUT_CHANNEL_BUTTONS_ONLY:// 2 Buttons only
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
break; break;
case 0x21:// 21 Read data case 0x21:// 21 Read data
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
ParseReadData(&mInputBuffer[3]); ParseReadData(&mInputBuffer[3]);
break; break;
case INPUT_CHANNEL_WRITE_CONFIRM:// 4 Write data case INPUT_CHANNEL_WRITE_CONFIRM:// 4 Write data
break; break;
case 0x31:// 5 Buttons | Motion Sensing Report case 0x31:// 5 Buttons | Motion Sensing Report
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]); ParseMotionReport(&mInputBuffer[3]);
break; break;
case 0x32:// 16 Buttons | Expansion Port | IR?? case 0x32:// 16 Buttons | Expansion Port | IR??
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
break; break;
case INPUT_CHANNEL_MOTION_IR: case INPUT_CHANNEL_MOTION_IR:
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]); ParseMotionReport(&mInputBuffer[3]);
ParseIRReport(&mInputBuffer[6]); ParseIRReport(&mInputBuffer[6]);
break; break;
case INPUT_CHANNEL_MOTION_CHUCK_IR: case INPUT_CHANNEL_MOTION_CHUCK_IR:
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]); ParseMotionReport(&mInputBuffer[3]);
ParseIRReport(&mInputBuffer[6]); ParseIRReport(&mInputBuffer[6]);
ParseChuckReport(&mInputBuffer[16]); ParseChuckReport(&mInputBuffer[16]);
break; break;
case INPUT_CHANNEL_MOTION_CHUCK: case INPUT_CHANNEL_MOTION_CHUCK:
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
ParseMotionReport(&mInputBuffer[3]); ParseMotionReport(&mInputBuffer[3]);
ParseChuckReport(&mInputBuffer[6]); ParseChuckReport(&mInputBuffer[6]);
break; break;
case 0x34:// 21 Buttons | Expansion Port | IR?? case 0x34:// 21 Buttons | Expansion Port | IR??
case 0x3d:// 21 Buttons | Expansion Port | IR?? case 0x3d:// 21 Buttons | Expansion Port | IR??
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
break; break;
case 0x3e:// 21 Buttons | Motion Sensing Report | IR?? case 0x3e:// 21 Buttons | Motion Sensing Report | IR??
case 0x3f:// 21 Buttons | Motion Sensing Report | IR?? case 0x3f:// 21 Buttons | Motion Sensing Report | IR??
ParseButtonReport(&mInputBuffer[1]); ParseButtonReport(&mInputBuffer[1]);
break; break;
default: default:
retval = false; retval = false;
//unknown report //unknown report
break; break;
} }
} }
return retval; return retval;
} }
void cWiiMote::ParseExpansionReport(const unsigned char *data) void cWiiMote::ParseExpansionReport(const unsigned char *data)
{ {
//four bytes long //four bytes long
mLastExpansionReport.mAttachmentPluggedIn = (data[0] & 0x02) != 0; mLastExpansionReport.mAttachmentPluggedIn = (data[0] & 0x02) != 0;
mLastExpansionReport.mIREnabled = (data[0] & 0x08) != 0; mLastExpansionReport.mIREnabled = (data[0] & 0x08) != 0;
mLastExpansionReport.mSpeakerEnabled = (data[0] & 0x04) != 0; mLastExpansionReport.mSpeakerEnabled = (data[0] & 0x04) != 0;
mLastExpansionReport.mLED1On = (data[0] & 0x10) != 0; mLastExpansionReport.mLED1On = (data[0] & 0x10) != 0;
mLastExpansionReport.mLED2On = (data[0] & 0x20) != 0; mLastExpansionReport.mLED2On = (data[0] & 0x20) != 0;
mLastExpansionReport.mLED3On = (data[0] & 0x40) != 0; mLastExpansionReport.mLED3On = (data[0] & 0x40) != 0;
mLastExpansionReport.mLED4On = (data[0] & 0x80) != 0; mLastExpansionReport.mLED4On = (data[0] & 0x80) != 0;
//two unknown bytes //two unknown bytes
mLastExpansionReport.mBatteryLevel = data[3]; mLastExpansionReport.mBatteryLevel = data[3];
} }
void cWiiMote::ParseButtonReport(const unsigned char * data) void cWiiMote::ParseButtonReport(const unsigned char * data)
{ {
//two bytes long //two bytes long
mLastButtonStatus.mA = (data[1] & 0x08) != 0; mLastButtonStatus.mA = (data[1] & 0x08) != 0;
mLastButtonStatus.mB = (data[1] & 0x04) != 0; mLastButtonStatus.mB = (data[1] & 0x04) != 0;
mLastButtonStatus.m1 = (data[1] & 0x02) != 0; mLastButtonStatus.m1 = (data[1] & 0x02) != 0;
mLastButtonStatus.m2 = (data[1] & 0x01) != 0; mLastButtonStatus.m2 = (data[1] & 0x01) != 0;
mLastButtonStatus.mPlus = (data[0] & 0x10) != 0; mLastButtonStatus.mPlus = (data[0] & 0x10) != 0;
mLastButtonStatus.mMinus = (data[1] & 0x10) != 0; mLastButtonStatus.mMinus = (data[1] & 0x10) != 0;
mLastButtonStatus.mHome = (data[1] & 0x80) != 0; mLastButtonStatus.mHome = (data[1] & 0x80) != 0;
mLastButtonStatus.mUp = (data[0] & 0x08) != 0; mLastButtonStatus.mUp = (data[0] & 0x08) != 0;
mLastButtonStatus.mDown = (data[0] & 0x04) != 0; mLastButtonStatus.mDown = (data[0] & 0x04) != 0;
mLastButtonStatus.mLeft = (data[0] & 0x01) != 0; mLastButtonStatus.mLeft = (data[0] & 0x01) != 0;
mLastButtonStatus.mRight = (data[0] & 0x02) != 0; mLastButtonStatus.mRight = (data[0] & 0x02) != 0;
} }
void cWiiMote::ParseMotionReport(const unsigned char * data) void cWiiMote::ParseMotionReport(const unsigned char * data)
{ {
//three bytes long //three bytes long
mLastMotionReport.mX = data[0]; mLastMotionReport.mX = data[0];
mLastMotionReport.mY = data[1]; mLastMotionReport.mY = data[1];
mLastMotionReport.mZ = data[2]; mLastMotionReport.mZ = data[2];
} }
void cWiiMote::PrintStatus() const void cWiiMote::PrintStatus() const
{ {
float wX,wY,wZ; float wX,wY,wZ;
float cX,cY,cZ; float cX,cY,cZ;
float sX,sY; float sX,sY;
float irX,irY; float irX,irY;
wX =wY=wZ=cX=cY=cZ=sX=sY=irX=irY=0.f; wX =wY=wZ=cX=cY=cZ=sX=sY=irX=irY=0.f;
GetCalibratedAcceleration(wX,wY,wZ); GetCalibratedAcceleration(wX,wY,wZ);
printf("W:[%+1.2f %+1.2f %+1.2f] ",wX,wY,wZ); printf("W:[%+1.2f %+1.2f %+1.2f] ",wX,wY,wZ);
if (mNunchuckAttached) if (mNunchuckAttached)
{ {
GetCalibratedChuckAcceleration(cX,cY,cZ); GetCalibratedChuckAcceleration(cX,cY,cZ);
printf("N:[%+1.2f %+1.2f %+1.2f] ",cX,cY,cZ); printf("N:[%+1.2f %+1.2f %+1.2f] ",cX,cY,cZ);
GetCalibratedChuckStick(sX,sY); GetCalibratedChuckStick(sX,sY);
printf("S:[%+1.2f %+1.2f] ",sX,sY); printf("S:[%+1.2f %+1.2f] ",sX,sY);
} }
if (mIRRunning) if (mIRRunning)
{ {
if (GetIRP1(irX,irY)) if (GetIRP1(irX,irY))
{ {
printf("P1:[%+1.2f %+1.2f]",irX,irY); printf("P1:[%+1.2f %+1.2f]",irX,irY);
} }
if (GetIRP2(irX,irY)) if (GetIRP2(irX,irY))
{ {
printf("P2:[%+1.2f %+1.2f]",irX,irY); printf("P2:[%+1.2f %+1.2f]",irX,irY);
} }
} }
//print the button status //print the button status
if (mLastButtonStatus.m1) if (mLastButtonStatus.m1)
printf("1"); printf("1");
if (mLastButtonStatus.m2) if (mLastButtonStatus.m2)
printf("2"); printf("2");
if (mLastButtonStatus.mA) if (mLastButtonStatus.mA)
printf("A"); printf("A");
if (mLastButtonStatus.mB) if (mLastButtonStatus.mB)
printf("B"); printf("B");
if (mLastButtonStatus.mPlus) if (mLastButtonStatus.mPlus)
printf("+"); printf("+");
if (mLastButtonStatus.mMinus) if (mLastButtonStatus.mMinus)
printf("-"); printf("-");
if (mLastButtonStatus.mUp) if (mLastButtonStatus.mUp)
printf("U"); printf("U");
if (mLastButtonStatus.mDown) if (mLastButtonStatus.mDown)
printf("D"); printf("D");
if (mLastButtonStatus.mLeft) if (mLastButtonStatus.mLeft)
printf("L"); printf("L");
if (mLastButtonStatus.mRight) if (mLastButtonStatus.mRight)
printf("R"); printf("R");
if (mLastButtonStatus.mHome) if (mLastButtonStatus.mHome)
printf("H"); printf("H");
if (mNunchuckAttached) if (mNunchuckAttached)
{ {
if (mLastChuckReport.mButtonZ) if (mLastChuckReport.mButtonZ)
printf("Z"); printf("Z");
if (mLastChuckReport.mButtonC) if (mLastChuckReport.mButtonC)
printf("C"); printf("C");
} }
printf("\n"); printf("\n");
} }
bool cWiiMote::SelectInputChannel(bool continuous, unsigned char channel) bool cWiiMote::SelectInputChannel(bool continuous, unsigned char channel)
{ {
ClearBuffer(); ClearBuffer();
mOutputBuffer[0] = OUTPUT_CHANNEL_REPORT; mOutputBuffer[0] = OUTPUT_CHANNEL_REPORT;
mOutputBuffer[1] = (continuous ? REQUEST_CONTINUOUS_REPORTS : REQUEST_SINGLE_REPORTS) | (mOutputControls.mVibration ? 0x1 : 0x0); mOutputBuffer[1] = (continuous ? REQUEST_CONTINUOUS_REPORTS : REQUEST_SINGLE_REPORTS) | (mOutputControls.mVibration ? 0x1 : 0x0);
mOutputBuffer[2] = channel; mOutputBuffer[2] = channel;
return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize); return mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
} }
//this may or may not work to read buffers greater than 16 bytes. . . . //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 cWiiMote::IssueReadRequest(unsigned int address, unsigned short size, unsigned char * buffer)
{ {
bool retval = false; bool retval = false;
if (mReadInfo.mReadStatus != tMemReadInfo::READ_PENDING) if (mReadInfo.mReadStatus != tMemReadInfo::READ_PENDING)
{ {
ClearBuffer(); ClearBuffer();
mOutputBuffer[0] = OUTPUT_READ_MEMORY; mOutputBuffer[0] = OUTPUT_READ_MEMORY;
mOutputBuffer[1] = (((address & 0xff000000) >> 24) & 0xFE) | (mOutputControls.mVibration ? 0x1 : 0x0); mOutputBuffer[1] = (((address & 0xff000000) >> 24) & 0xFE) | (mOutputControls.mVibration ? 0x1 : 0x0);
mOutputBuffer[2] = (address & 0x00ff0000) >> 16; mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
mOutputBuffer[3] = (address & 0x0000ff00) >> 8; mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
mOutputBuffer[4] = (address & 0xff); mOutputBuffer[4] = (address & 0xff);
mOutputBuffer[5] = (size & 0xff00) >> 8; mOutputBuffer[5] = (size & 0xff00) >> 8;
mOutputBuffer[6] = (size & 0xff); mOutputBuffer[6] = (size & 0xff);
if (mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize)) if (mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize))
{ {
mReadInfo.mReadStatus = tMemReadInfo::READ_PENDING; mReadInfo.mReadStatus = tMemReadInfo::READ_PENDING;
mReadInfo.mReadBuffer = buffer; mReadInfo.mReadBuffer = buffer;
mReadInfo.mTotalBytesToRead = size; mReadInfo.mTotalBytesToRead = size;
mReadInfo.mBytesRead =0; mReadInfo.mBytesRead =0;
mReadInfo.mBaseAddress = (unsigned short)(address & 0xFFFF); mReadInfo.mBaseAddress = (unsigned short)(address & 0xFFFF);
retval = true; retval = true;
} }
} }
return retval; return retval;
} }
void cWiiMote::ParseReadData(const unsigned char * data) void cWiiMote::ParseReadData(const unsigned char * data)
{ {
if(mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING) if(mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
{ {
const bool error = (data[0] & 0x0F) != 0; const bool error = (data[0] & 0x0F) != 0;
if (error) if (error)
{ {
mReadInfo.mReadStatus = tMemReadInfo::READ_ERROR; mReadInfo.mReadStatus = tMemReadInfo::READ_ERROR;
} }
else else
{ {
unsigned char bytes = (data[0] >> 4)+1; unsigned char bytes = (data[0] >> 4)+1;
unsigned short offset = ((unsigned short)data[1] << 8) + data[2]; unsigned short offset = ((unsigned short)data[1] << 8) + data[2];
unsigned int space_left_in_buffer = mReadInfo.mTotalBytesToRead - mReadInfo.mBytesRead; unsigned int space_left_in_buffer = mReadInfo.mTotalBytesToRead - mReadInfo.mBytesRead;
if (offset == mReadInfo.mBytesRead + mReadInfo.mBaseAddress && if (offset == mReadInfo.mBytesRead + mReadInfo.mBaseAddress &&
space_left_in_buffer >= bytes) space_left_in_buffer >= bytes)
{ {
memcpy(&mReadInfo.mReadBuffer[mReadInfo.mBytesRead],&data[3],bytes); memcpy(&mReadInfo.mReadBuffer[mReadInfo.mBytesRead],&data[3],bytes);
mReadInfo.mBytesRead+= bytes; mReadInfo.mBytesRead+= bytes;
if (mReadInfo.mBytesRead >= mReadInfo.mTotalBytesToRead) if (mReadInfo.mBytesRead >= mReadInfo.mTotalBytesToRead)
{ {
mReadInfo.mReadStatus = tMemReadInfo::READ_COMPLETE; mReadInfo.mReadStatus = tMemReadInfo::READ_COMPLETE;
} }
} }
} }
} }
} }
bool cWiiMote::ReadData(unsigned int address, unsigned short size, unsigned char * buffer) bool cWiiMote::ReadData(unsigned int address, unsigned short size, unsigned char * buffer)
{ {
if (IssueReadRequest(address, size,buffer)) if (IssueReadRequest(address, size,buffer))
{ {
while (mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING) while (mReadInfo.mReadStatus == tMemReadInfo::READ_PENDING)
{ {
if (!HeartBeat(1000)) if (!HeartBeat(1000))
{ {
break; break;
} }
} }
} }
return mReadInfo.mReadStatus == tMemReadInfo::READ_COMPLETE; return mReadInfo.mReadStatus == tMemReadInfo::READ_COMPLETE;
} }
bool cWiiMote::ReadCalibrationData() bool cWiiMote::ReadCalibrationData()
{ {
bool retval = false; bool retval = false;
unsigned char buffer[CALIBRATION_DATA_LENGTH]; unsigned char buffer[CALIBRATION_DATA_LENGTH];
if (ReadData(CALIBRATION_ADDRESS, CALIBRATION_DATA_LENGTH,buffer)) if (ReadData(CALIBRATION_ADDRESS, CALIBRATION_DATA_LENGTH,buffer))
{ {
mAccelCalibrationData.mXZero = buffer[0]; mAccelCalibrationData.mXZero = buffer[0];
mAccelCalibrationData.mYZero = buffer[1]; mAccelCalibrationData.mYZero = buffer[1];
mAccelCalibrationData.mZZero = buffer[2]; mAccelCalibrationData.mZZero = buffer[2];
mAccelCalibrationData.mXG = buffer[4]; mAccelCalibrationData.mXG = buffer[4];
mAccelCalibrationData.mYG = buffer[5]; mAccelCalibrationData.mYG = buffer[5];
mAccelCalibrationData.mZG = buffer[6]; mAccelCalibrationData.mZG = buffer[6];
retval = true; retval = true;
} }
return retval; return retval;
} }
void cWiiMote::GetCalibratedAcceleration(float & x, float & y, float &z) const void cWiiMote::GetCalibratedAcceleration(float & x, float & y, float &z) const
{ {
x = (mLastMotionReport.mX - mAccelCalibrationData.mXZero) / (float)(mAccelCalibrationData.mXG- mAccelCalibrationData.mXZero); x = (mLastMotionReport.mX - mAccelCalibrationData.mXZero) / (float)(mAccelCalibrationData.mXG- mAccelCalibrationData.mXZero);
y = (mLastMotionReport.mY - mAccelCalibrationData.mYZero) / (float)(mAccelCalibrationData.mYG- mAccelCalibrationData.mYZero); y = (mLastMotionReport.mY - mAccelCalibrationData.mYZero) / (float)(mAccelCalibrationData.mYG- mAccelCalibrationData.mYZero);
z = (mLastMotionReport.mZ - mAccelCalibrationData.mZZero) / (float)(mAccelCalibrationData.mZG- mAccelCalibrationData.mZZero); z = (mLastMotionReport.mZ - mAccelCalibrationData.mZZero) / (float)(mAccelCalibrationData.mZG- mAccelCalibrationData.mZZero);
} }
void cWiiMote::GetCalibratedChuckAcceleration(float & x, float & y, float &z) const void cWiiMote::GetCalibratedChuckAcceleration(float & x, float & y, float &z) const
{ {
if (!mNunchuckAttached) if (!mNunchuckAttached)
{ {
x = y = z = 0.f; x = y = z = 0.f;
return; return;
} }
x = (mLastChuckReport.mAccelX - mNunchuckAccelCalibrationData.mXZero) / (float)(mNunchuckAccelCalibrationData.mXG- mNunchuckAccelCalibrationData.mXZero); x = (mLastChuckReport.mAccelX - mNunchuckAccelCalibrationData.mXZero) / (float)(mNunchuckAccelCalibrationData.mXG- mNunchuckAccelCalibrationData.mXZero);
y = (mLastChuckReport.mAccelY - mNunchuckAccelCalibrationData.mYZero) / (float)(mNunchuckAccelCalibrationData.mYG- mNunchuckAccelCalibrationData.mYZero); y = (mLastChuckReport.mAccelY - mNunchuckAccelCalibrationData.mYZero) / (float)(mNunchuckAccelCalibrationData.mYG- mNunchuckAccelCalibrationData.mYZero);
z = (mLastChuckReport.mAccelZ - mNunchuckAccelCalibrationData.mZZero) / (float)(mNunchuckAccelCalibrationData.mZG- mNunchuckAccelCalibrationData.mZZero); z = (mLastChuckReport.mAccelZ - mNunchuckAccelCalibrationData.mZZero) / (float)(mNunchuckAccelCalibrationData.mZG- mNunchuckAccelCalibrationData.mZZero);
} }
void cWiiMote::GetCalibratedChuckStick(float & x, float & y) const void cWiiMote::GetCalibratedChuckStick(float & x, float & y) const
{ {
if (!mNunchuckAttached) if (!mNunchuckAttached)
{ {
x = y = 0.f; x = y = 0.f;
return; return;
} }
if (mLastChuckReport.mStickX < mNunchuckStickCalibrationData.mXmid) if (mLastChuckReport.mStickX < mNunchuckStickCalibrationData.mXmid)
{ {
x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmin) / (float)(mNunchuckStickCalibrationData.mXmid - mNunchuckStickCalibrationData.mXmin)) - 1.f; x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmin) / (float)(mNunchuckStickCalibrationData.mXmid - mNunchuckStickCalibrationData.mXmin)) - 1.f;
} }
else else
{ {
x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmid) / (float)(mNunchuckStickCalibrationData.mXmax - mNunchuckStickCalibrationData.mXmid)); x = ((mLastChuckReport.mStickX - mNunchuckStickCalibrationData.mXmid) / (float)(mNunchuckStickCalibrationData.mXmax - mNunchuckStickCalibrationData.mXmid));
} }
if (mLastChuckReport.mStickY < mNunchuckStickCalibrationData.mYmid) if (mLastChuckReport.mStickY < mNunchuckStickCalibrationData.mYmid)
{ {
y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmin) / (float)(mNunchuckStickCalibrationData.mYmid - mNunchuckStickCalibrationData.mYmin)) - 1.f; y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmin) / (float)(mNunchuckStickCalibrationData.mYmid - mNunchuckStickCalibrationData.mYmin)) - 1.f;
} }
else else
{ {
y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmid) / (float)(mNunchuckStickCalibrationData.mYmax - mNunchuckStickCalibrationData.mYmid)); y = ((mLastChuckReport.mStickY - mNunchuckStickCalibrationData.mYmid) / (float)(mNunchuckStickCalibrationData.mYmax - mNunchuckStickCalibrationData.mYmid));
} }
} }
bool cWiiMote::WriteMemory(unsigned int address, unsigned char size, const unsigned char * buffer) bool cWiiMote::WriteMemory(unsigned int address, unsigned char size, const unsigned char * buffer)
{ {
bool retval = false; bool retval = false;
if (size <= 16) if (size <= 16)
{ {
ClearBuffer(); ClearBuffer();
mOutputBuffer[0] = OUTPUT_WRITE_MEMORY; mOutputBuffer[0] = OUTPUT_WRITE_MEMORY;
mOutputBuffer[1] = (address & 0xff000000) >> 24 | (mOutputControls.mVibration ? 0x1 : 0x0); mOutputBuffer[1] = (address & 0xff000000) >> 24 | (mOutputControls.mVibration ? 0x1 : 0x0);
mOutputBuffer[2] = (address & 0x00ff0000) >> 16; mOutputBuffer[2] = (address & 0x00ff0000) >> 16;
mOutputBuffer[3] = (address & 0x0000ff00) >> 8; mOutputBuffer[3] = (address & 0x0000ff00) >> 8;
mOutputBuffer[4] = (address & 0xff); mOutputBuffer[4] = (address & 0xff);
mOutputBuffer[5] = size; mOutputBuffer[5] = size;
memcpy(&mOutputBuffer[6],buffer,size); memcpy(&mOutputBuffer[6],buffer,size);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize); retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
} }
return retval; return retval;
} }
bool cWiiMote::InitNunchuck() bool cWiiMote::InitNunchuck()
{ {
bool retval = false; bool retval = false;
//first init the nunchuck, if it is present //first init the nunchuck, if it is present
if (WriteMemory(NUNCHUCK_INIT_ADDRESS,1,&NUNCHUCK_INIT_VAL)) if (WriteMemory(NUNCHUCK_INIT_ADDRESS,1,&NUNCHUCK_INIT_VAL))
{ {
unsigned char buffer[16]; unsigned char buffer[16];
//now try to read the nunchuck's calibration data //now try to read the nunchuck's calibration data
if (ReadData(NUNCHUCK_CALIBRATION_ADDRESS,16,buffer)) if (ReadData(NUNCHUCK_CALIBRATION_ADDRESS,16,buffer))
{ {
//note that this hasn't worked properly for me yet (I get all 0xff). //note that this hasn't worked properly for me yet (I get all 0xff).
/*mNunchuckAccelCalibrationData.mXZero = NunChuckByte(buffer[0]); /*mNunchuckAccelCalibrationData.mXZero = NunChuckByte(buffer[0]);
mNunchuckAccelCalibrationData.mYZero = NunChuckByte(buffer[1]); mNunchuckAccelCalibrationData.mYZero = NunChuckByte(buffer[1]);
mNunchuckAccelCalibrationData.mZZero = NunChuckByte(buffer[2]); mNunchuckAccelCalibrationData.mZZero = NunChuckByte(buffer[2]);
mNunchuckAccelCalibrationData.mXG = NunChuckByte(buffer[4]); mNunchuckAccelCalibrationData.mXG = NunChuckByte(buffer[4]);
mNunchuckAccelCalibrationData.mYG = NunChuckByte(buffer[5]); mNunchuckAccelCalibrationData.mYG = NunChuckByte(buffer[5]);
mNunchuckAccelCalibrationData.mZG = NunChuckByte(buffer[6]); mNunchuckAccelCalibrationData.mZG = NunChuckByte(buffer[6]);
mNunchuckStickCalibrationData.mXmax = NunChuckByte(buffer[8]); mNunchuckStickCalibrationData.mXmax = NunChuckByte(buffer[8]);
mNunchuckStickCalibrationData.mXmin = NunChuckByte(buffer[9]); mNunchuckStickCalibrationData.mXmin = NunChuckByte(buffer[9]);
mNunchuckStickCalibrationData.mXmid = NunChuckByte(buffer[10]); mNunchuckStickCalibrationData.mXmid = NunChuckByte(buffer[10]);
mNunchuckStickCalibrationData.mYmax = NunChuckByte(buffer[11]); mNunchuckStickCalibrationData.mYmax = NunChuckByte(buffer[11]);
mNunchuckStickCalibrationData.mYmin = NunChuckByte(buffer[12]); mNunchuckStickCalibrationData.mYmin = NunChuckByte(buffer[12]);
mNunchuckStickCalibrationData.mYmid = NunChuckByte(buffer[13]);*/ mNunchuckStickCalibrationData.mYmid = NunChuckByte(buffer[13]);*/
//these are default values from the wiili wiki //these are default values from the wiili wiki
mNunchuckAccelCalibrationData.mXZero = 0x7E; mNunchuckAccelCalibrationData.mXZero = 0x7E;
mNunchuckAccelCalibrationData.mYZero = 0x7A; mNunchuckAccelCalibrationData.mYZero = 0x7A;
mNunchuckAccelCalibrationData.mZZero = 0x7D; mNunchuckAccelCalibrationData.mZZero = 0x7D;
mNunchuckAccelCalibrationData.mXG = 0xB0; mNunchuckAccelCalibrationData.mXG = 0xB0;
mNunchuckAccelCalibrationData.mYG = 0xAF; mNunchuckAccelCalibrationData.mYG = 0xAF;
mNunchuckAccelCalibrationData.mZG = 0xB1; mNunchuckAccelCalibrationData.mZG = 0xB1;
mNunchuckStickCalibrationData.mXmax = 0xe5; mNunchuckStickCalibrationData.mXmax = 0xe5;
mNunchuckStickCalibrationData.mXmin = 0x21; mNunchuckStickCalibrationData.mXmin = 0x21;
mNunchuckStickCalibrationData.mXmid = 0x7c; mNunchuckStickCalibrationData.mXmid = 0x7c;
mNunchuckStickCalibrationData.mYmax = 0xe7; mNunchuckStickCalibrationData.mYmax = 0xe7;
mNunchuckStickCalibrationData.mYmin = 0x23; mNunchuckStickCalibrationData.mYmin = 0x23;
mNunchuckStickCalibrationData.mYmid = 0x7a; mNunchuckStickCalibrationData.mYmid = 0x7a;
retval = true; retval = true;
} }
} }
mNunchuckAttached = retval; mNunchuckAttached = retval;
return retval; return retval;
} }
void cWiiMote::ParseChuckReport(const unsigned char * data) void cWiiMote::ParseChuckReport(const unsigned char * data)
{ {
mLastChuckReport.mStickX = NunChuckByte(data[0]); mLastChuckReport.mStickX = NunChuckByte(data[0]);
mLastChuckReport.mStickY = NunChuckByte(data[1]); mLastChuckReport.mStickY = NunChuckByte(data[1]);
mLastChuckReport.mAccelX = NunChuckByte(data[2]); mLastChuckReport.mAccelX = NunChuckByte(data[2]);
mLastChuckReport.mAccelY = NunChuckByte(data[3]); mLastChuckReport.mAccelY = NunChuckByte(data[3]);
mLastChuckReport.mAccelZ = NunChuckByte(data[4]); mLastChuckReport.mAccelZ = NunChuckByte(data[4]);
mLastChuckReport.mButtonC = (NunChuckByte(data[5]) & 0x2) == 0; mLastChuckReport.mButtonC = (NunChuckByte(data[5]) & 0x2) == 0;
mLastChuckReport.mButtonZ = (NunChuckByte(data[5]) & 0x1) == 0; mLastChuckReport.mButtonZ = (NunChuckByte(data[5]) & 0x1) == 0;
} }
bool cWiiMote::EnableIR() bool cWiiMote::EnableIR()
{ {
bool retval = false; bool retval = false;
DisableIR(); DisableIR();
if (!mIRRunning) if (!mIRRunning)
{ {
ClearBuffer(); ClearBuffer();
mOutputBuffer[0] = OUTPUT_ENABLE_IR; mOutputBuffer[0] = OUTPUT_ENABLE_IR;
mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0); mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize); retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
if (retval) if (retval)
{ {
mOutputBuffer[0] = OUTPUT_ENABLE_IR2; mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0); mOutputBuffer[1] = 0x4 | (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize); retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
} }
if (retval) if (retval)
{ {
unsigned char val = 0x1; unsigned char val = 0x1;
retval = WriteMemory(IR_REG_1,1,&val); retval = WriteMemory(IR_REG_1,1,&val);
} }
if (retval) if (retval)
{ {
retval = WriteMemory(IR_SENS_ADDR_1,9,IR_SENS_MIDRANGE_PART1); retval = WriteMemory(IR_SENS_ADDR_1,9,IR_SENS_MIDRANGE_PART1);
} }
if (retval) if (retval)
{ {
retval = WriteMemory(IR_SENS_ADDR_2,2,IR_SENS_MIDRANGE_PART2); retval = WriteMemory(IR_SENS_ADDR_2,2,IR_SENS_MIDRANGE_PART2);
} }
if (retval) if (retval)
{ {
retval = WriteMemory(IR_REG_2,1,&IR_MODE_EXP); retval = WriteMemory(IR_REG_2,1,&IR_MODE_EXP);
} }
if (retval) if (retval)
{ {
unsigned char val = 0x8; unsigned char val = 0x8;
retval = WriteMemory(IR_REG_1,1,&val); retval = WriteMemory(IR_REG_1,1,&val);
} }
mIRRunning = retval; mIRRunning = retval;
} }
return retval; return retval;
} }
bool cWiiMote::DisableIR() bool cWiiMote::DisableIR()
{ {
bool retval = false; bool retval = false;
if (mIRRunning) if (mIRRunning)
{ {
ClearBuffer(); ClearBuffer();
mOutputBuffer[0] = OUTPUT_ENABLE_IR; mOutputBuffer[0] = OUTPUT_ENABLE_IR;
mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0); mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize); retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
if (retval) if (retval)
{ {
mOutputBuffer[0] = OUTPUT_ENABLE_IR2; mOutputBuffer[0] = OUTPUT_ENABLE_IR2;
mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0); mOutputBuffer[1] = (mOutputControls.mVibration ? 0x1 : 0x0);
retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize); retval = mHIDDevice.WriteToDevice(mOutputBuffer,mOutputBufferSize);
} }
mIRRunning = false; mIRRunning = false;
} }
return retval; return retval;
} }
void cWiiMote::ParseIRReport(const unsigned char * data) void cWiiMote::ParseIRReport(const unsigned char * data)
{ {
mLastIRReport.mP1X = data[0] << 2 | (data[2] & 0x30) >>4; mLastIRReport.mP1X = data[0] << 2 | (data[2] & 0x30) >>4;
mLastIRReport.mP1Y = data[1] << 2 | (data[2] & 0xc0) >>6; mLastIRReport.mP1Y = data[1] << 2 | (data[2] & 0xc0) >>6;
mLastIRReport.mP1Size = data[2] & 0xf; mLastIRReport.mP1Size = data[2] & 0xf;
mLastIRReport.mP2X = data[3] << 2 | (data[5] & 0x30) >>4; mLastIRReport.mP2X = data[3] << 2 | (data[5] & 0x30) >>4;
mLastIRReport.mP2Y = data[4] << 2 | (data[5] & 0xc0) >>6; mLastIRReport.mP2Y = data[4] << 2 | (data[5] & 0xc0) >>6;
mLastIRReport.mP2Size = data[5] & 0xf; mLastIRReport.mP2Size = data[5] & 0xf;
mLastIRReport.mP1Found = !(data[0] == 0xff && data[1] == 0xff && data[2] == 0xff); mLastIRReport.mP1Found = !(data[0] == 0xff && data[1] == 0xff && data[2] == 0xff);
mLastIRReport.mP2Found = !(data[3] == 0xff && data[4] == 0xff && data[5] == 0xff); mLastIRReport.mP2Found = !(data[3] == 0xff && data[4] == 0xff && data[5] == 0xff);
} }
bool cWiiMote::GetIRP1(float &x, float &y) const bool cWiiMote::GetIRP1(float &x, float &y) const
{ {
bool retval = false; bool retval = false;
if (mIRRunning && mLastIRReport.mP1Found) if (mIRRunning && mLastIRReport.mP1Found)
{ {
x = mLastIRReport.mP1X / 1024.f; x = mLastIRReport.mP1X / 1024.f;
y = mLastIRReport.mP1Y / 1024.f; y = mLastIRReport.mP1Y / 1024.f;
retval = true; retval = true;
} }
return retval; return retval;
} }
bool cWiiMote::GetIRP2(float &x, float &y) const bool cWiiMote::GetIRP2(float &x, float &y) const
{ {
bool retval = false; bool retval = false;
if (mIRRunning && mLastIRReport.mP2Found) if (mIRRunning && mLastIRReport.mP2Found)
{ {
x = mLastIRReport.mP2X / 1024.f; x = mLastIRReport.mP2X / 1024.f;
y = mLastIRReport.mP2Y / 1024.f; y = mLastIRReport.mP2Y / 1024.f;
retval = true; retval = true;
} }
return retval; return retval;
} }
bool cWiiMote::StartDataStream() bool cWiiMote::StartDataStream()
{ {
bool retval = false; bool retval = false;
StopDataStream(); StopDataStream();
if (mNunchuckAttached) if (mNunchuckAttached)
{ {
retval =SetReportMode(REPORT_MODE_MOTION_CHUCK_IR); retval =SetReportMode(REPORT_MODE_MOTION_CHUCK_IR);
} }
else else
{ {
retval = SetReportMode(REPORT_MODE_MOTION_IR); retval = SetReportMode(REPORT_MODE_MOTION_IR);
} }
EnableIR(); EnableIR();
mDataStreamRunning = retval; mDataStreamRunning = retval;
return retval; return retval;
} }
bool cWiiMote::StopDataStream() bool cWiiMote::StopDataStream()
{ {
if (mDataStreamRunning) if (mDataStreamRunning)
{ {
mDataStreamRunning = false; mDataStreamRunning = false;
DisableIR(); DisableIR();
SetReportMode(REPORT_MODE_EVENT_BUTTONS); SetReportMode(REPORT_MODE_EVENT_BUTTONS);
} }
return true;; return true;;
} }
#endif #endif
#include "OISConfig.h" #include "OISConfig.h"
#ifdef OIS_WIN32_WIIMOTE_SUPPORT #ifdef OIS_WIN32_WIIMOTE_SUPPORT
//cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com) //cWiimote 0.2 by Kevin Forbes (http://simulatedcomicproduct.com)
//This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code. //This code is public domain, and comes with no warranty. The user takes full responsibility for anything that happens as a result from using this code.
#ifndef WIIMOTE_H #ifndef WIIMOTE_H
#define WIIMOTE_H #define WIIMOTE_H
#include "hiddevice.h" #include "hiddevice.h"
class cWiiMote class cWiiMote
{ {
public: public:
cWiiMote(); cWiiMote();
~cWiiMote(); ~cWiiMote();
//connection management //connection management
bool ConnectToDevice(int index = 0); bool ConnectToDevice(int index = 0);
bool Disconnect(); bool Disconnect();
bool IsConnected() const {return mHIDDevice.IsConnected();} bool IsConnected() const {return mHIDDevice.IsConnected();}
bool StartDataStream(); bool StartDataStream();
bool StopDataStream(); bool StopDataStream();
bool IsNunChuckAttached() { return mNunchuckAttached; } bool IsNunChuckAttached() { return mNunchuckAttached; }
//this is the wiimote message pump. It should probably be called in loop from a thread //this is the wiimote message pump. It should probably be called in loop from a thread
bool HeartBeat(int timeout = 1); bool HeartBeat(int timeout = 1);
bool SetVibration(bool vib_on); bool SetVibration(bool vib_on);
bool SetLEDs(bool led1, bool led2, bool led3, bool led4); bool SetLEDs(bool led1, bool led2, bool led3, bool led4);
//Querying functions and structures: //Querying functions and structures:
void GetCalibratedAcceleration(float & x, float & y, float &z) const; void GetCalibratedAcceleration(float & x, float & y, float &z) const;
void GetCalibratedChuckAcceleration(float & x, float & y, float &z) const; void GetCalibratedChuckAcceleration(float & x, float & y, float &z) const;
void GetCalibratedChuckStick(float & x, float & y) const; void GetCalibratedChuckStick(float & x, float & y) const;
bool GetIRP1(float &x, float &y) const; bool GetIRP1(float &x, float &y) const;
bool GetIRP2(float &x, float &y) const; bool GetIRP2(float &x, float &y) const;
struct tExpansionReport struct tExpansionReport
{ {
bool mAttachmentPluggedIn; bool mAttachmentPluggedIn;
bool mIREnabled; bool mIREnabled;
bool mSpeakerEnabled; bool mSpeakerEnabled;
bool mLED1On; bool mLED1On;
bool mLED2On; bool mLED2On;
bool mLED3On; bool mLED3On;
bool mLED4On; bool mLED4On;
unsigned char mBatteryLevel; unsigned char mBatteryLevel;
void Init() void Init()
{ {
mAttachmentPluggedIn = false; mAttachmentPluggedIn = false;
mIREnabled = false; mIREnabled = false;
mSpeakerEnabled = false; mSpeakerEnabled = false;
mLED1On = false; mLED1On = false;
mLED2On = false; mLED2On = false;
mLED3On = false; mLED3On = false;
mLED4On = false; mLED4On = false;
mBatteryLevel = 0; mBatteryLevel = 0;
} }
}; };
struct tButtonStatus struct tButtonStatus
{ {
bool mA; bool mA;
bool mB; bool mB;
bool m1; bool m1;
bool m2; bool m2;
bool mPlus; bool mPlus;
bool mMinus; bool mMinus;
bool mHome; bool mHome;
bool mUp; bool mUp;
bool mDown; bool mDown;
bool mLeft; bool mLeft;
bool mRight; bool mRight;
void Init() void Init()
{ {
mA = mB = m1 = m2 = mPlus = mMinus = mHome = mUp = mDown = mLeft = mRight = false; mA = mB = m1 = m2 = mPlus = mMinus = mHome = mUp = mDown = mLeft = mRight = false;
} }
}; };
struct tMotionReport struct tMotionReport
{ {
unsigned char mX; unsigned char mX;
unsigned char mY; unsigned char mY;
unsigned char mZ; unsigned char mZ;
void Init() void Init()
{ {
mX = mY = mZ = 0; mX = mY = mZ = 0;
} }
}; };
struct tChuckReport struct tChuckReport
{ {
unsigned char mStickX; unsigned char mStickX;
unsigned char mStickY; unsigned char mStickY;
unsigned char mAccelX; unsigned char mAccelX;
unsigned char mAccelY; unsigned char mAccelY;
unsigned char mAccelZ; unsigned char mAccelZ;
bool mButtonC; bool mButtonC;
bool mButtonZ; bool mButtonZ;
void Init() void Init()
{ {
mStickX=mStickY=mAccelX=mAccelY=mAccelZ=0; mStickX=mStickY=mAccelX=mAccelY=mAccelZ=0;
mButtonC = mButtonZ = false; mButtonC = mButtonZ = false;
}; };
}; };
struct tIRReport struct tIRReport
{ {
unsigned short mP1X; unsigned short mP1X;
unsigned short mP1Y; unsigned short mP1Y;
unsigned short mP2X; unsigned short mP2X;
unsigned short mP2Y; unsigned short mP2Y;
unsigned char mP1Size; unsigned char mP1Size;
unsigned char mP2Size; unsigned char mP2Size;
bool mP1Found; bool mP1Found;
bool mP2Found; bool mP2Found;
void Init() void Init()
{ {
mP1X = mP1Y = mP2X = mP2Y = mP1Size = mP2Size = 0; mP1X = mP1Y = mP2X = mP2Y = mP1Size = mP2Size = 0;
mP1Found = mP2Found = false; mP1Found = mP2Found = false;
} }
}; };
const tButtonStatus & GetLastButtonStatus() const {return mLastButtonStatus;} const tButtonStatus & GetLastButtonStatus() const {return mLastButtonStatus;}
const tChuckReport & GetLastChuckReport() const {return mLastChuckReport;} const tChuckReport & GetLastChuckReport() const {return mLastChuckReport;}
const tMotionReport & GetLastMotionReport() const { return mLastMotionReport;} const tMotionReport & GetLastMotionReport() const { return mLastMotionReport;}
const tExpansionReport & GetLastExpansionReport() const { return mLastExpansionReport;} const tExpansionReport & GetLastExpansionReport() const { return mLastExpansionReport;}
const tIRReport & GetLastIRReport() const { return mLastIRReport;} const tIRReport & GetLastIRReport() const { return mLastIRReport;}
//debugging functions: //debugging functions:
void PrintStatus() const; void PrintStatus() const;
private: private:
//parsing functions for input reports //parsing functions for input reports
void ParseExpansionReport(const unsigned char * data); void ParseExpansionReport(const unsigned char * data);
void ParseButtonReport(const unsigned char * data); void ParseButtonReport(const unsigned char * data);
void ParseMotionReport(const unsigned char * data); void ParseMotionReport(const unsigned char * data);
void ParseReadData(const unsigned char * data); void ParseReadData(const unsigned char * data);
void ParseChuckReport(const unsigned char * data); void ParseChuckReport(const unsigned char * data);
void ParseIRReport(const unsigned char * data); void ParseIRReport(const unsigned char * data);
//tell the wiimote how to send data //tell the wiimote how to send data
enum eReportMode enum eReportMode
{ {
REPORT_MODE_EVENT_BUTTONS, REPORT_MODE_EVENT_BUTTONS,
REPORT_MODE_MOTION, REPORT_MODE_MOTION,
REPORT_MODE_MOTION_CHUCK, REPORT_MODE_MOTION_CHUCK,
REPORT_MODE_MOTION_IR, REPORT_MODE_MOTION_IR,
REPORT_MODE_MOTION_CHUCK_IR REPORT_MODE_MOTION_CHUCK_IR
}; };
bool SetReportMode(eReportMode mode); bool SetReportMode(eReportMode mode);
//housekeeping functions //housekeeping functions
void Init(); void Init();
void ClearBuffer(); void ClearBuffer();
//low level tasks //low level tasks
bool SelectInputChannel(bool continuous, unsigned char channel); bool SelectInputChannel(bool continuous, unsigned char channel);
bool UpdateOutput(); bool UpdateOutput();
bool ReadMemory(unsigned int address, unsigned short size, unsigned char * buffer) const; 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 WriteMemory(unsigned int address, unsigned char size, const unsigned char * buffer);
bool ReadData(unsigned int address, unsigned short size, 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 IssueReadRequest(unsigned int address, unsigned short size, unsigned char * buffer);
bool ReadCalibrationData(); bool ReadCalibrationData();
bool SendReportMode(); bool SendReportMode();
bool InitNunchuck(); bool InitNunchuck();
bool EnableIR(); bool EnableIR();
bool DisableIR(); bool DisableIR();
static inline unsigned char NunChuckByte(unsigned char in) {return (in ^ 0x17)+0x17;} static inline unsigned char NunChuckByte(unsigned char in) {return (in ^ 0x17)+0x17;}
//flash reading vars //flash reading vars
struct tMemReadInfo struct tMemReadInfo
{ {
enum eReadStatus enum eReadStatus
{ {
READ_PENDING, READ_PENDING,
READ_NONE, READ_NONE,
READ_COMPLETE, READ_COMPLETE,
READ_ERROR READ_ERROR
} mReadStatus; } mReadStatus;
unsigned char * mReadBuffer; unsigned char * mReadBuffer;
unsigned short mTotalBytesToRead; unsigned short mTotalBytesToRead;
unsigned short mBytesRead; unsigned short mBytesRead;
unsigned short mBaseAddress; unsigned short mBaseAddress;
void Init() void Init()
{ {
mReadStatus = READ_NONE; mReadStatus = READ_NONE;
mReadBuffer = NULL; mReadBuffer = NULL;
mTotalBytesToRead = 0; mTotalBytesToRead = 0;
mBytesRead = 0; mBytesRead = 0;
mBaseAddress = 0; mBaseAddress = 0;
} }
} mReadInfo; } mReadInfo;
//calibration data for the wiimote //calibration data for the wiimote
struct tAccelCalibrationData struct tAccelCalibrationData
{ {
unsigned char mXZero; unsigned char mXZero;
unsigned char mYZero; unsigned char mYZero;
unsigned char mZZero; unsigned char mZZero;
unsigned char mXG; unsigned char mXG;
unsigned char mYG; unsigned char mYG;
unsigned char mZG; unsigned char mZG;
void Init() void Init()
{ {
mXZero = mYZero = mZZero = mXG = mYG = mZG= 0; mXZero = mYZero = mZZero = mXG = mYG = mZG= 0;
} }
} ; } ;
struct tStickCalibrationData struct tStickCalibrationData
{ {
unsigned char mXmin; unsigned char mXmin;
unsigned char mXmid; unsigned char mXmid;
unsigned char mXmax; unsigned char mXmax;
unsigned char mYmin; unsigned char mYmin;
unsigned char mYmid; unsigned char mYmid;
unsigned char mYmax; unsigned char mYmax;
void Init() void Init()
{ {
mXmax = mYmax = mXmin = mYmin = mXmid = mYmid =0; mXmax = mYmax = mXmin = mYmin = mXmid = mYmid =0;
} }
}; };
tAccelCalibrationData mAccelCalibrationData; tAccelCalibrationData mAccelCalibrationData;
tAccelCalibrationData mNunchuckAccelCalibrationData; tAccelCalibrationData mNunchuckAccelCalibrationData;
tStickCalibrationData mNunchuckStickCalibrationData; tStickCalibrationData mNunchuckStickCalibrationData;
//output requests //output requests
struct tOutputControls struct tOutputControls
{ {
bool mVibration; bool mVibration;
bool mLED1; bool mLED1;
bool mLED2; bool mLED2;
bool mLED3; bool mLED3;
bool mLED4; bool mLED4;
void Init() void Init()
{ {
mVibration = mLED1 = mLED2= mLED3= mLED4 = false; mVibration = mLED1 = mLED2= mLED3= mLED4 = false;
} }
}; };
//input states //input states
tExpansionReport mLastExpansionReport; tExpansionReport mLastExpansionReport;
tButtonStatus mLastButtonStatus; tButtonStatus mLastButtonStatus;
tMotionReport mLastMotionReport; tMotionReport mLastMotionReport;
tChuckReport mLastChuckReport; tChuckReport mLastChuckReport;
tIRReport mLastIRReport; tIRReport mLastIRReport;
//output states //output states
tOutputControls mOutputControls; tOutputControls mOutputControls;
eReportMode mReportMode; eReportMode mReportMode;
//our communications device //our communications device
cHIDDevice mHIDDevice; cHIDDevice mHIDDevice;
bool mNunchuckAttached; bool mNunchuckAttached;
bool mIRRunning; bool mIRRunning;
bool mDataStreamRunning; bool mDataStreamRunning;
//buffers for input/output //buffers for input/output
static const int mOutputBufferSize = 22; static const int mOutputBufferSize = 22;
unsigned char mOutputBuffer[mOutputBufferSize]; unsigned char mOutputBuffer[mOutputBufferSize];
static const int mInputBufferSize = 22; static const int mInputBufferSize = 22;
unsigned char mInputBuffer[mInputBufferSize]; unsigned char mInputBuffer[mInputBufferSize];
}; };
#endif #endif
#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