Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/ois/win32/Win32JoyStick.cpp @ 1762

Last change on this file since 1762 was 1505, checked in by rgrieder, 16 years ago

f* svn: It doesn't even inform you if you attempt to set a non existing property. It is svn:eol-style and not eol-style when using the command by the way…

  • Property svn:eol-style set to native
File size: 12.3 KB
Line 
1/*
2The zlib/libpng License
3
4Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
5
6This software is provided 'as-is', without any express or implied warranty. In no event will
7the authors be held liable for any damages arising from the use of this software.
8
9Permission is granted to anyone to use this software for any purpose, including commercial
10applications, and to alter it and redistribute it freely, subject to the following
11restrictions:
12
13    1. The origin of this software must not be misrepresented; you must not claim that
14                you wrote the original software. If you use this software in a product,
15                an acknowledgment in the product documentation would be appreciated but is
16                not required.
17
18    2. Altered source versions must be plainly marked as such, and must not be
19                misrepresented as being the original software.
20
21    3. This notice may not be removed or altered from any source distribution.
22*/
23#include "Win32/Win32JoyStick.h"
24#include "Win32/Win32InputManager.h"
25#include "Win32/Win32ForceFeedback.h"
26#include "OISEvents.h"
27#include "OISException.h"
28
29#include <cassert>
30
31//DX Only defines macros for the JOYSTICK not JOYSTICK2, so fix it
32#undef DIJOFS_BUTTON
33#undef DIJOFS_POV
34
35#define DIJOFS_BUTTON(n)  (FIELD_OFFSET(DIJOYSTATE2, rgbButtons) + (n))
36#define DIJOFS_POV(n)     (FIELD_OFFSET(DIJOYSTATE2, rgdwPOV)+(n)*sizeof(DWORD))
37#define DIJOFS_SLIDER0(n) (FIELD_OFFSET(DIJOYSTATE2, rglSlider)+(n) * sizeof(LONG))
38#define DIJOFS_SLIDER1(n) (FIELD_OFFSET(DIJOYSTATE2, rglVSlider)+(n) * sizeof(LONG))
39#define DIJOFS_SLIDER2(n) (FIELD_OFFSET(DIJOYSTATE2, rglASlider)+(n) * sizeof(LONG))
40#define DIJOFS_SLIDER3(n) (FIELD_OFFSET(DIJOYSTATE2, rglFSlider)+(n) * sizeof(LONG))
41
42using namespace OIS;
43
44//--------------------------------------------------------------------------------------------------//
45Win32JoyStick::Win32JoyStick( InputManager* creator, IDirectInput8* pDI,
46        bool buffered, DWORD coopSettings, const JoyStickInfo &info )
47        : JoyStick(info.vendor, buffered, info.devId, creator)
48{
49        mDirectInput = pDI;
50        coopSetting = coopSettings;
51        mJoyStick = 0;
52
53        deviceGuid = info.deviceID;
54
55        ff_device = 0;
56}
57
58//--------------------------------------------------------------------------------------------------//
59Win32JoyStick::~Win32JoyStick()
60{
61        delete ff_device;
62
63        if(mJoyStick)
64        {
65                mJoyStick->Unacquire();
66                mJoyStick->Release();
67                mJoyStick = 0;
68        }
69
70        //Return joystick to pool
71        JoyStickInfo js;
72        js.deviceID = deviceGuid;
73        js.devId = mDevID;
74        js.vendor = mVendor;
75        static_cast<Win32InputManager*>(mCreator)->_returnJoyStick(js);
76}
77
78//--------------------------------------------------------------------------------------------------//
79void Win32JoyStick::_initialize()
80{
81        //Clear old state
82        mState.mAxes.clear();
83
84        delete ff_device;
85        ff_device = 0;
86
87        DIPROPDWORD dipdw;
88
89        dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
90        dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
91        dipdw.diph.dwObj        = 0;
92        dipdw.diph.dwHow        = DIPH_DEVICE;
93        dipdw.dwData            = JOYSTICK_DX_BUFFERSIZE;
94
95        if(FAILED(mDirectInput->CreateDevice(deviceGuid, &mJoyStick, NULL)))
96                OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> Could not initialize joy device!");
97
98        if(FAILED(mJoyStick->SetDataFormat(&c_dfDIJoystick2)))
99                OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> data format error!");
100
101        HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
102
103        if(FAILED(mJoyStick->SetCooperativeLevel( hwin, coopSetting)))
104                OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> failed to set cooperation level!");
105
106        if( FAILED(mJoyStick->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)) )
107                OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set buffer size property" );
108
109        //Enumerate all axes/buttons/sliders/etc before aquiring
110        _enumerate();
111
112        mState.clear();
113
114        capture();
115}
116
117//--------------------------------------------------------------------------------------------------//
118void Win32JoyStick::_enumerate()
119{
120        //We can check force feedback here too
121        DIDEVCAPS  DIJoyCaps;
122        DIJoyCaps.dwSize = sizeof(DIDEVCAPS);
123        mJoyStick->GetCapabilities(&DIJoyCaps);
124
125        mPOVs = (short)DIJoyCaps.dwPOVs;
126
127        mState.mButtons.resize(DIJoyCaps.dwButtons);
128        mState.mAxes.resize(DIJoyCaps.dwAxes);
129
130        //Reset the axis mapping enumeration value
131        _AxisNumber = 0;
132
133        //Enumerate Force Feedback (if any)
134        mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL);
135
136        //Enumerate and set axis constraints (and check FF Axes)
137        mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS);
138}
139
140//--------------------------------------------------------------------------------------------------//
141BOOL CALLBACK Win32JoyStick::DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
142{
143        Win32JoyStick* _this = (Win32JoyStick*)pvRef;
144
145        //Setup mappings
146        DIPROPPOINTER diptr;
147        diptr.diph.dwSize       = sizeof(DIPROPPOINTER);
148        diptr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
149        diptr.diph.dwHow        = DIPH_BYID;
150        diptr.diph.dwObj        = lpddoi->dwType;
151        //Add a magic number to recognise we set seomthing
152        diptr.uData             = 0x13130000 | _this->_AxisNumber;
153
154        //Check if axis is slider, if so, do not treat as regular axis
155        if(GUID_Slider == lpddoi->guidType)
156        {
157                ++_this->mSliders;
158
159                //Decrease Axes, since this slider shows up in a different place
160                _this->mState.mAxes.pop_back();
161        }
162        else if (FAILED(_this->mJoyStick->SetProperty(DIPROP_APPDATA, &diptr.diph)))
163        {       //If for some reason we could not set needed user data, just ignore this axis
164                return DIENUM_CONTINUE;
165        }
166
167        //Increase for next time through
168        if(GUID_Slider != lpddoi->guidType)
169                _this->_AxisNumber += 1;
170
171        //Set range
172        DIPROPRANGE diprg;
173        diprg.diph.dwSize       = sizeof(DIPROPRANGE);
174        diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
175        diprg.diph.dwHow        = DIPH_BYID;
176        diprg.diph.dwObj        = lpddoi->dwType;
177        diprg.lMin              = MIN_AXIS;
178        diprg.lMax              = MAX_AXIS;
179
180        if (FAILED(_this->mJoyStick->SetProperty(DIPROP_RANGE, &diprg.diph)))
181                OIS_EXCEPT( E_General, "Win32JoyStick::_DIEnumDeviceObjectsCallback >> Failed to set min/max range property" );
182
183        //Check if FF Axes
184        if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 )
185        {
186                if( _this->ff_device )
187                {
188                        //todo - increment force feedback axis count
189                }
190        }
191
192        return DIENUM_CONTINUE;
193}
194
195//--------------------------------------------------------------------------------------------------//
196BOOL CALLBACK Win32JoyStick::DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef)
197{
198        Win32JoyStick* _this = (Win32JoyStick*)pvRef;
199
200        //Create the FF class after we know there is at least one effect type
201        if( _this->ff_device == 0 )
202                _this->ff_device = new Win32ForceFeedback(_this->mJoyStick);
203
204        _this->ff_device->_addEffectSupport( pdei );
205
206        return DIENUM_CONTINUE;
207}
208
209//--------------------------------------------------------------------------------------------------//
210void Win32JoyStick::capture()
211{
212        DIDEVICEOBJECTDATA diBuff[JOYSTICK_DX_BUFFERSIZE];
213        DWORD entries = JOYSTICK_DX_BUFFERSIZE;
214
215        // Poll the device to read the current state
216        HRESULT hr = mJoyStick->Poll();
217        if( hr == DI_OK )
218                hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
219
220        if( hr != DI_OK )
221        {
222                hr = mJoyStick->Acquire();
223                while( hr == DIERR_INPUTLOST )
224                        hr = mJoyStick->Acquire();
225
226                // Poll the device to read the current state
227            mJoyStick->Poll();
228                hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
229                //Perhaps the user just tabbed away
230                if( FAILED(hr) )
231                        return;
232        }
233
234        bool axisMoved[24] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,
235                                                  false,false,false,false,false,false,false,false};
236        bool sliderMoved[4] = {false,false,false,false};
237
238        //Loop through all the events
239        for(unsigned int i = 0; i < entries; ++i)
240        {
241                //This may seem outof order, but is in order of the way these variables
242                //are declared in the JoyStick State 2 structure.
243                switch(diBuff[i].dwOfs)
244                {
245                //------ slider -//
246                case DIJOFS_SLIDER0(0):
247                        sliderMoved[0] = true;
248                        mState.mSliders[0].abX = diBuff[i].dwData;
249                        break;
250                case DIJOFS_SLIDER0(1):
251                        sliderMoved[0] = true;
252                        mState.mSliders[0].abY = diBuff[i].dwData;
253                        break;
254                //----- Max 4 POVs Next ---------------//
255                case DIJOFS_POV(0):
256                        if(!_changePOV(0,diBuff[i]))
257                                return;
258                        break;
259                case DIJOFS_POV(1):
260                        if(!_changePOV(1,diBuff[i]))
261                                return;
262                        break;
263                case DIJOFS_POV(2):
264                        if(!_changePOV(2,diBuff[i]))
265                                return;
266                        break;
267                case DIJOFS_POV(3):
268                        if(!_changePOV(3,diBuff[i]))
269                                return;
270                        break;
271                case DIJOFS_SLIDER1(0):
272                        sliderMoved[1] = true;
273                        mState.mSliders[1].abX = diBuff[i].dwData;
274                        break;
275                case DIJOFS_SLIDER1(1):
276                        sliderMoved[1] = true;
277                        mState.mSliders[1].abY = diBuff[i].dwData;
278                        break;
279                case DIJOFS_SLIDER2(0):
280                        sliderMoved[2] = true;
281                        mState.mSliders[2].abX = diBuff[i].dwData;
282                        break;
283                case DIJOFS_SLIDER2(1):
284                        sliderMoved[2] = true;
285                        mState.mSliders[2].abY = diBuff[i].dwData;
286                        break;
287                case DIJOFS_SLIDER3(0):
288                        sliderMoved[3] = true;
289                        mState.mSliders[3].abX = diBuff[i].dwData;
290                        break;
291                case DIJOFS_SLIDER3(1):
292                        sliderMoved[3] = true;
293                        mState.mSliders[3].abY = diBuff[i].dwData;
294                        break;
295                //-----------------------------------------//
296                default:
297                        //Handle Button Events Easily using the DX Offset Macros
298                        if( diBuff[i].dwOfs >= DIJOFS_BUTTON(0) && diBuff[i].dwOfs < DIJOFS_BUTTON(128) )
299                        {
300                                if(!_doButtonClick((diBuff[i].dwOfs - DIJOFS_BUTTON(0)), diBuff[i]))
301                                        return;
302                        }
303                        else if((short)(diBuff[i].uAppData >> 16) == 0x1313)
304                        {       //If it was nothing else, might be axis enumerated earlier (determined by magic number)
305                                int axis = (int)(0x0000FFFF & diBuff[i].uAppData); //Mask out the high bit
306                                assert( axis >= 0 && axis < (int)mState.mAxes.size() && "Axis out of range!");
307
308                                if(axis >= 0 && axis < (int)mState.mAxes.size())
309                                {
310                                        mState.mAxes[axis].abs = diBuff[i].dwData;
311                                        axisMoved[axis] = true;
312                                }
313                        }
314
315                        break;
316                } //end case
317        } //end for
318
319        //Check to see if any of the axes values have changed.. if so send events
320        if( mBuffered && mListener && entries > 0 )
321        {
322                JoyStickEvent temp(this, mState);
323
324                //Update axes
325                for( int i = 0; i < 24; ++i )
326                        if( axisMoved[i] )
327                                if( mListener->axisMoved( temp, i ) == false )
328                                        return;
329
330                //Now update sliders
331                for( int i = 0; i < 4; ++i )
332                        if( sliderMoved[i] )
333                                if( mListener->sliderMoved( temp, i ) == false )
334                                        return;
335        }
336}
337
338//--------------------------------------------------------------------------------------------------//
339bool Win32JoyStick::_doButtonClick( int button, DIDEVICEOBJECTDATA& di )
340{
341        if( di.dwData & 0x80 )
342        {
343                mState.mButtons[button] = true;
344                if( mBuffered && mListener )
345                        return mListener->buttonPressed( JoyStickEvent( this, mState ), button );
346        }
347        else
348        {
349                mState.mButtons[button] = false;
350                if( mBuffered && mListener )
351                        return mListener->buttonReleased( JoyStickEvent( this, mState ), button );
352        }
353
354        return true;
355}
356
357//--------------------------------------------------------------------------------------------------//
358bool Win32JoyStick::_changePOV( int pov, DIDEVICEOBJECTDATA& di )
359{
360        //Some drivers report a value of 65,535, instead of —1,
361        //for the center position
362        if(LOWORD(di.dwData) == 0xFFFF)
363        {
364                mState.mPOV[pov].direction = Pov::Centered;
365        }
366        else
367        {
368                switch(di.dwData)
369                {
370                        case 0: mState.mPOV[pov].direction = Pov::North; break;
371                        case 4500: mState.mPOV[pov].direction = Pov::NorthEast; break;
372                        case 9000: mState.mPOV[pov].direction = Pov::East; break;
373                        case 13500: mState.mPOV[pov].direction = Pov::SouthEast; break;
374                        case 18000: mState.mPOV[pov].direction = Pov::South; break;
375                        case 22500: mState.mPOV[pov].direction = Pov::SouthWest; break;
376                        case 27000: mState.mPOV[pov].direction = Pov::West; break;
377                        case 31500: mState.mPOV[pov].direction = Pov::NorthWest; break;
378                }
379        }
380
381        if( mBuffered && mListener )
382                return mListener->povMoved( JoyStickEvent( this, mState ), pov );
383
384        return true;
385}
386
387//--------------------------------------------------------------------------------------------------//
388void Win32JoyStick::setBuffered(bool buffered)
389{
390        mBuffered = buffered;
391}
392
393//--------------------------------------------------------------------------------------------------//
394Interface* Win32JoyStick::queryInterface(Interface::IType type)
395{
396        //Thought about using covariant return type here.. however,
397        //some devices may allow LED light changing, or other interface stuff
398
399        if( ff_device && type == Interface::ForceFeedback )
400                return ff_device;
401        else
402                return 0;
403}
Note: See TracBrowser for help on using the repository browser.