Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1344 was 1219, checked in by rgrieder, 17 years ago

merged input branch back to trunk. Not yet tested on tardis

File size: 12.7 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 the high bit in so that an axis value of zero does not mean a null userdata
152        diptr.uData             = 0x80000000 | _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        _this->_AxisNumber += 1;
169
170        //Set range
171        DIPROPRANGE diprg;
172        diprg.diph.dwSize       = sizeof(DIPROPRANGE);
173        diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
174        diprg.diph.dwHow        = DIPH_BYID;
175        diprg.diph.dwObj        = lpddoi->dwType;
176        diprg.lMin              = MIN_AXIS;
177        diprg.lMax              = MAX_AXIS;
178
179        if (FAILED(_this->mJoyStick->SetProperty(DIPROP_RANGE, &diprg.diph)))
180                OIS_EXCEPT( E_General, "Win32JoyStick::_DIEnumDeviceObjectsCallback >> Failed to set min/max range property" );
181
182        //Check if FF Axes
183        if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 )
184        {
185                if( _this->ff_device )
186                {
187                        //todo - increment force feedback axis count
188                }
189        }
190
191        return DIENUM_CONTINUE;
192}
193
194//--------------------------------------------------------------------------------------------------//
195BOOL CALLBACK Win32JoyStick::DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef)
196{
197        Win32JoyStick* _this = (Win32JoyStick*)pvRef;
198
199        //Create the FF class after we know there is at least one effect type
200        if( _this->ff_device == 0 )
201                _this->ff_device = new Win32ForceFeedback(_this->mJoyStick);
202
203        _this->ff_device->_addEffectSupport( pdei );
204
205        return DIENUM_CONTINUE;
206}
207
208//--------------------------------------------------------------------------------------------------//
209void Win32JoyStick::capture()
210{
211        DIDEVICEOBJECTDATA diBuff[JOYSTICK_DX_BUFFERSIZE];
212        DWORD entries = JOYSTICK_DX_BUFFERSIZE;
213
214        // Poll the device to read the current state
215        HRESULT hr = mJoyStick->Poll();
216        if( hr == DI_OK )
217                hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
218
219        if( hr != DI_OK )
220        {
221                hr = mJoyStick->Acquire();
222                while( hr == DIERR_INPUTLOST )
223                        hr = mJoyStick->Acquire();
224
225                // Poll the device to read the current state
226            mJoyStick->Poll();
227                hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
228                //Perhaps the user just tabbed away
229                if( FAILED(hr) )
230                        return;
231        }
232
233        bool axisMoved[24] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,
234                                                  false,false,false,false,false,false,false,false};
235        bool sliderMoved[4] = {false,false,false,false};
236
237        //Loop through all the events
238        for(unsigned int i = 0; i < entries; ++i)
239        {
240                //First check to see if event entry is a Axis we enumerated earlier
241                if( diBuff[i].uAppData != 0xFFFFFFFF && diBuff[i].uAppData > 0 )
242                {
243                        int axis = (int)(0x7FFFFFFF & diBuff[i].uAppData); //Mask out the high bit
244                        assert( axis >= 0 && axis < (int)mState.mAxes.size() && "Axis out of range!");
245                        mState.mAxes[axis].abs = diBuff[i].dwData;
246                        axisMoved[axis] = true;
247                }
248                else
249                {
250                        //This may seem outof order, but is in order of the way these variables
251                        //are declared in the JoyStick State 2 structure.
252                        switch(diBuff[i].dwOfs)
253                        {
254                        //------ slider -//
255                        case DIJOFS_SLIDER0(0):
256                                sliderMoved[0] = true;
257                                mState.mSliders[0].abX = diBuff[i].dwData;
258                                break;
259                        case DIJOFS_SLIDER0(1):
260                                sliderMoved[0] = true;
261                                mState.mSliders[0].abY = diBuff[i].dwData;
262                                break;
263                        //----- Max 4 POVs Next ---------------//
264                        case DIJOFS_POV(0):
265                                if(!_changePOV(0,diBuff[i]))
266                                        return;
267                                break;
268                        case DIJOFS_POV(1):
269                                if(!_changePOV(1,diBuff[i]))
270                                        return;
271                                break;
272                        case DIJOFS_POV(2):
273                                if(!_changePOV(2,diBuff[i]))
274                                        return;
275                                break;
276                        case DIJOFS_POV(3):
277                                if(!_changePOV(3,diBuff[i]))
278                                        return;
279                                break;
280                        case DIJOFS_SLIDER1(0):
281                                sliderMoved[1] = true;
282                                mState.mSliders[1].abX = diBuff[i].dwData;
283                                break;
284                        case DIJOFS_SLIDER1(1):
285                                sliderMoved[1] = true;
286                                mState.mSliders[1].abY = diBuff[i].dwData;
287                                break;
288                        case DIJOFS_SLIDER2(0):
289                                sliderMoved[2] = true;
290                                mState.mSliders[2].abX = diBuff[i].dwData;
291                                break;
292                        case DIJOFS_SLIDER2(1):
293                                sliderMoved[2] = true;
294                                mState.mSliders[2].abY = diBuff[i].dwData;
295                                break;
296                        case DIJOFS_SLIDER3(0):
297                                sliderMoved[3] = true;
298                                mState.mSliders[3].abX = diBuff[i].dwData;
299                                break;
300                        case DIJOFS_SLIDER3(1):
301                                sliderMoved[3] = true;
302                                mState.mSliders[3].abY = diBuff[i].dwData;
303                                break;
304                        //-----------------------------------------//
305                        default:
306                                //Handle Button Events Easily using the DX Offset Macros
307                                if( diBuff[i].dwOfs >= DIJOFS_BUTTON(0) && diBuff[i].dwOfs < DIJOFS_BUTTON(128) )
308                                {
309                                        if(!_doButtonClick((diBuff[i].dwOfs - DIJOFS_BUTTON(0)), diBuff[i]))
310                                                return;
311                                }
312                                break;
313                        } //end case
314                } //End else
315        } //end for
316
317        //Check to see if any of the axes values have changed.. if so send events
318        if( mBuffered && mListener && entries > 0 )
319        {
320                JoyStickEvent temp(this, mState);
321
322                //Update axes
323                for( int i = 0; i < 24; ++i )
324                        if( axisMoved[i] )
325                                if( mListener->axisMoved( temp, i ) == false )
326                                        return;
327
328                //Now update sliders
329                for( int i = 0; i < 4; ++i )
330                        if( sliderMoved[i] )
331                                if( mListener->sliderMoved( temp, i ) == false )
332                                        return;
333        }
334}
335
336//--------------------------------------------------------------------------------------------------//
337bool Win32JoyStick::_doButtonClick( int button, DIDEVICEOBJECTDATA& di )
338{
339        if( di.dwData & 0x80 )
340        {
341                mState.mButtons[button] = true;
342                if( mBuffered && mListener )
343                        return mListener->buttonPressed( JoyStickEvent( this, mState ), button );
344        }
345        else
346        {
347                mState.mButtons[button] = false;
348                if( mBuffered && mListener )
349                        return mListener->buttonReleased( JoyStickEvent( this, mState ), button );
350        }
351
352        return true;
353}
354
355//--------------------------------------------------------------------------------------------------//
356bool Win32JoyStick::_changePOV( int pov, DIDEVICEOBJECTDATA& di )
357{
358        //Some drivers report a value of 65,535, instead of —1,
359        //for the center position
360        if(LOWORD(di.dwData) == 0xFFFF)
361        {
362                mState.mPOV[pov].direction = Pov::Centered;
363        }
364        else
365        {
366                switch(di.dwData)
367                {
368                        case 0: mState.mPOV[pov].direction = Pov::North; break;
369                        case 4500: mState.mPOV[pov].direction = Pov::NorthEast; break;
370                        case 9000: mState.mPOV[pov].direction = Pov::East; break;
371                        case 13500: mState.mPOV[pov].direction = Pov::SouthEast; break;
372                        case 18000: mState.mPOV[pov].direction = Pov::South; break;
373                        case 22500: mState.mPOV[pov].direction = Pov::SouthWest; break;
374                        case 27000: mState.mPOV[pov].direction = Pov::West; break;
375                        case 31500: mState.mPOV[pov].direction = Pov::NorthWest; break;
376                }
377        }
378
379        if( mBuffered && mListener )
380                return mListener->povMoved( JoyStickEvent( this, mState ), pov );
381
382        return true;
383}
384
385//--------------------------------------------------------------------------------------------------//
386void Win32JoyStick::setBuffered(bool buffered)
387{
388        mBuffered = buffered;
389}
390
391//--------------------------------------------------------------------------------------------------//
392Interface* Win32JoyStick::queryInterface(Interface::IType type)
393{
394        //Thought about using covariant return type here.. however,
395        //some devices may allow LED light changing, or other interface stuff
396
397        if( ff_device && type == Interface::ForceFeedback )
398                return ff_device;
399        else
400                return 0;
401}
Note: See TracBrowser for help on using the repository browser.